diff --git a/server/main.go b/server/main.go index 499a550..1c2f911 100644 --- a/server/main.go +++ b/server/main.go @@ -3,9 +3,11 @@ package main import ( "errors" "fmt" + "io" "net/http" "os" "path" + "strconv" "syscall" "time" @@ -30,10 +32,6 @@ var dataDir = "." var token = "" var upgrader = websocket.Upgrader{} -type ReqData struct { - ID uuid.UUID `json:"id"` -} - type IDParam struct { ID string `param:"id"` } @@ -48,6 +46,23 @@ func authed(next echo.HandlerFunc) echo.HandlerFunc { } } +func idparam(next func(echo.Context, uuid.UUID) error) echo.HandlerFunc { + return func(c echo.Context) error { + var data IDParam + err := c.Bind(&data) + if err != nil || data.ID == "" { + return c.JSON(http.StatusBadRequest, echo.Map{"message": "missing field 'id'"}) + } + id, err := uuid.Parse(data.ID) + if err != nil { + return c.JSON(http.StatusBadRequest, echo.Map{"message": "field 'id' is not a uuid"}) + } + + return next(c, id) + } + +} + func main() { _ = godotenv.Load() dataDir = os.Getenv("DATA_DIR") @@ -132,28 +147,80 @@ func main() { return c.JSON(http.StatusOK, clients) }) - app.GET("/admin/:id/logs", authed(func(c echo.Context) error { - // TODO: finish - return nil - })) - app.POST("/admin/:id/name", authed(func(c echo.Context) error { - return nil - })) - app.POST("/admin/exit", authed(func(c echo.Context) error { - var data ReqData - err := c.Bind(&data) - if err != nil { - return c.JSON(http.StatusBadRequest, echo.Map{"message": "missing field 'id'"}) + app.GET("/admin/:id", authed(idparam(func(c echo.Context, id uuid.UUID) error { + for _, client := range clients { + if client.Obj.ID == id { + return c.JSON(http.StatusOK, client) + } } + return c.NoContent(http.StatusNotFound) + }))) + app.GET("/admin/:id/logs", authed(idparam(func(c echo.Context, id uuid.UUID) error { + date := c.Param("date") + if date == "" { + date = time.Now().Format("2006-01-02") + } + skipRaw := c.Param("skip") + skip := 0 + if skipRaw != "" { + skip, err = strconv.Atoi(skipRaw) + if err != nil { + return c.JSON(http.StatusBadRequest, echo.Map{"message": "skip is not a number"}) + } + } + takeRaw := c.Param("take") + take := 1024 + if takeRaw != "" { + take, err = strconv.Atoi(takeRaw) + if err != nil { + return c.JSON(http.StatusBadRequest, echo.Map{"message": "take is not a number"}) + } + } + + f, err := os.OpenFile(fmt.Sprintf("%s/%s_%d.txt", dataDir, time.Now().Format("2006-01-02"), id), syscall.O_CREAT|syscall.O_APPEND|syscall.O_WRONLY, 0644) + if err != nil { + return c.JSON(http.StatusNotFound, echo.Map{"message": "file not found"}) + } + + _, err = f.Seek(int64(skip), io.SeekStart) + if err != nil { + return c.NoContent(http.StatusInternalServerError) + } + + bytes := make([]byte, take) + _, err = f.Read(bytes) + if err != nil { + return c.NoContent(http.StatusInternalServerError) + } + + return c.JSON(http.StatusOK, bytes) + }))) + app.POST("/admin/:id/name", authed(idparam(func(c echo.Context, id uuid.UUID) error { for _, client := range clients { - if client.Obj.ID == data.ID { + if client.Obj.ID == id { + client.Obj.Name = c.Param("name") + client.Obj.UpdatedAt = time.Now() + tx := db.Save(client.Obj) + if tx.Error != nil { + return c.NoContent(http.StatusInternalServerError) + } + return c.JSON(http.StatusOK, echo.Map{"message": "ok"}) + } + } + + return c.JSON(http.StatusNotFound, echo.Map{"message": "not found"}) + }))) + app.POST("/admin/:id/exit", authed(idparam(func(c echo.Context, id uuid.UUID) error { + for _, client := range clients { + if client.Obj.ID == id { client.ExitWanted = true return c.JSON(http.StatusOK, echo.Map{"message": "ok"}) } } + return c.JSON(http.StatusNotFound, echo.Map{"message": "not found"}) - })) + }))) log.Fatal(app.Start(":8080")) } @@ -197,7 +264,7 @@ func keys(c echo.Context) error { log.Error(err) } - f, err := os.OpenFile(fmt.Sprintf("%s/%s_%d.txt", dataDir, time.Now().Format("2006-01-02_15-04"), client.Obj.ID.String()), syscall.O_CREAT|syscall.O_APPEND|syscall.O_WRONLY, 0644) + f, err := os.OpenFile(fmt.Sprintf("%s/%s_%d.txt", dataDir, time.Now().Format("2006-01-02"), client.Obj.ID.String()), syscall.O_CREAT|syscall.O_APPEND|syscall.O_WRONLY, 0644) if err != nil { log.Error(err) fmt.Printf("%s client %s crashed (couldn't open file)\n", time.Now().Format(TimeFormat), client.Obj.ID)