diff --git a/backend/go.mod b/backend/go.mod index 2b68f9f..ed5f3d7 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -20,6 +20,7 @@ require ( github.com/muesli/termenv v0.16.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/robert-nix/ansihtml v1.0.1 // indirect github.com/stretchr/testify v1.10.0 // indirect github.com/wneessen/go-mail v0.6.2 // indirect golang.org/x/crypto v0.33.0 // indirect diff --git a/backend/go.sum b/backend/go.sum index 4e3e5c4..e5991fa 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -6,6 +6,7 @@ github.com/charmbracelet/log v0.4.1 h1:6AYnoHKADkghm/vt4neaNEXkxcXLSV2g1rdyFDOpT github.com/charmbracelet/log v0.4.1/go.mod h1:pXgyTsqsVu4N9hGdHmQ0xEA4RsXof402LX9ZgiITn2I= github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk= github.com/charmbracelet/x/ansi v0.4.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= @@ -33,6 +34,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robert-nix/ansihtml v1.0.1 h1:VTiyQ6/+AxSJoSSLsMecnkh8i0ZqOEdiRl/odOc64fc= +github.com/robert-nix/ansihtml v1.0.1/go.mod h1:CJwclxYaTPc2RfcxtanEACsYuTksh4yDXcNeHHKZINE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -109,5 +114,6 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/logs.go b/backend/logs.go index 9cc82d1..c0023fd 100644 --- a/backend/logs.go +++ b/backend/logs.go @@ -1,13 +1,21 @@ 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" @@ -36,6 +44,83 @@ func (w *DatabaseWriter) Write(p []byte) (n int, err error) { } } +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 := "" + + for _, log := range logs { + html += fmt.Sprintf("
%s
", string(ansihtml.ConvertToHTML([]byte(log)))+"\n") + } + + css := ` + + ` + + fullHtml := fmt.Sprintf("Logs%s%s", css, 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, diff --git a/backend/main.go b/backend/main.go index ae050be..9759017 100644 --- a/backend/main.go +++ b/backend/main.go @@ -393,6 +393,12 @@ func main() { fmt.Fprint(w, string(json)) }) + logWriter := DatabaseWriter{ + dbPool: db, + } + + r.Route("/logs", createLogHandler(&logWriter)) + log.Println("Listening and serving on port 3040.") if err := http.ListenAndServe(":3040", r); err != nil { log.Println(err)