150 lines
3.1 KiB
Go
150 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
|
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
. "github.com/go-jet/jet/v2/postgres"
|
|
"github.com/robert-nix/ansihtml"
|
|
|
|
"github.com/charmbracelet/log"
|
|
"github.com/google/uuid"
|
|
"github.com/muesli/termenv"
|
|
)
|
|
|
|
type DatabaseWriter struct {
|
|
dbPool *sql.DB
|
|
imageId uuid.UUID
|
|
}
|
|
|
|
func (w *DatabaseWriter) Write(p []byte) (n int, err error) {
|
|
if len(p) == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
insertLogStmt := Logs.
|
|
INSERT(Logs.Log, Logs.ImageID).
|
|
VALUES(string(p), w.imageId)
|
|
|
|
_, err = insertLogStmt.Exec(w.dbPool)
|
|
|
|
if err != nil {
|
|
return 0, err
|
|
} else {
|
|
return len(p), nil
|
|
}
|
|
}
|
|
|
|
func (w *DatabaseWriter) GetImageLogs(ctx context.Context, imageId uuid.UUID) ([]string, error) {
|
|
getImageLogsStmt := Logs.
|
|
SELECT(Logs.Log).
|
|
WHERE(Logs.ImageID.EQ(UUID(imageId)))
|
|
|
|
logs := []model.Logs{}
|
|
err := getImageLogsStmt.QueryContext(ctx, w.dbPool, &logs)
|
|
|
|
if err != nil {
|
|
return []string{}, err
|
|
}
|
|
|
|
stringLogs := make([]string, len(logs))
|
|
for i, log := range logs {
|
|
stringLogs[i] = log.Log
|
|
}
|
|
|
|
return stringLogs, nil
|
|
}
|
|
|
|
func createLogHandler(logWriter *DatabaseWriter) func(r chi.Router) {
|
|
return func(r chi.Router) {
|
|
r.Get("/{imageId}", func(w http.ResponseWriter, r *http.Request) {
|
|
stringImageId := r.PathValue("imageId")
|
|
imageId, err := uuid.Parse(stringImageId)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadGateway)
|
|
return
|
|
}
|
|
|
|
logs, err := logWriter.GetImageLogs(r.Context(), imageId)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
html := ""
|
|
|
|
imageTag := fmt.Sprintf(`<image src="http://localhost:3040/image/%s">`, stringImageId)
|
|
|
|
for _, log := range logs {
|
|
html += fmt.Sprintf("<div>%s</div>", string(ansihtml.ConvertToHTML([]byte(log)))+"\n")
|
|
}
|
|
|
|
css := `
|
|
<style>
|
|
body {
|
|
background-color: #1e1e1e;
|
|
color: #f0f0f0;
|
|
font-family: sans-serif;
|
|
line-height: 1.6;
|
|
margin: 0;
|
|
padding: 20px;
|
|
}
|
|
|
|
/* Basic styling for code blocks often used for logs */
|
|
pre {
|
|
background-color: #2a2a2a;
|
|
padding: 1em;
|
|
border-radius: 4px;
|
|
overflow-x: auto;
|
|
border: 1px solid #444;
|
|
}
|
|
|
|
code {
|
|
font-family: monospace;
|
|
}
|
|
</style>
|
|
`
|
|
|
|
fullHtml := fmt.Sprintf("<html><head><title>Logs</title>%s</head><body>%s%s</body></html>", css, imageTag, html)
|
|
|
|
w.Header().Add("Content-Type", "text/html")
|
|
w.Write([]byte(fullHtml))
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
}
|
|
}
|
|
|
|
func newDatabaseWriter(dbPool *sql.DB, imageId uuid.UUID) *DatabaseWriter {
|
|
return &DatabaseWriter{
|
|
dbPool: dbPool,
|
|
imageId: imageId,
|
|
}
|
|
}
|
|
|
|
func createDbStdoutWriter(dbPool *sql.DB, imageId uuid.UUID) io.Writer {
|
|
return io.MultiWriter(os.Stdout, newDatabaseWriter(dbPool, imageId))
|
|
}
|
|
|
|
func createLogger(prefix string, writer io.Writer) *log.Logger {
|
|
logger := log.NewWithOptions(writer, log.Options{
|
|
ReportTimestamp: true,
|
|
TimeFormat: time.Kitchen,
|
|
Prefix: prefix,
|
|
Formatter: log.TextFormatter,
|
|
})
|
|
|
|
logger.SetColorProfile(termenv.TrueColor)
|
|
logger.SetLevel(log.DebugLevel)
|
|
|
|
return logger
|
|
}
|