diff --git a/control/storage.go b/control/storage.go index 3fc1da3..d1ea708 100644 --- a/control/storage.go +++ b/control/storage.go @@ -16,13 +16,13 @@ func getStorageRoute(ctx echo.Context) error { data, err := os.ReadFile(storageFile) if err != nil { slog.Error("Could not read storage file", "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Could not read storage file"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Could not read storage file"}) } var content interface{} if err := json.Unmarshal(data, &content); err != nil { slog.Error("Could not parse storage file", "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Could not parse storage file"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Could not parse storage file"}) } return ctx.JSON(http.StatusOK, content) @@ -31,15 +31,15 @@ func getStorageRoute(ctx echo.Context) error { func setStorageRoute(ctx echo.Context) error { var payload interface{} if err := ctx.Bind(&payload); err != nil { - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "Invalid JSON payload"}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: "Invalid JSON payload"}) } data, err := json.MarshalIndent(payload, "", " ") if err != nil { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to marshal storage file"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to marshal storage file"}) } if err := os.WriteFile(storageFile, data, 0644); err != nil { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to write storage file"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to write storage file"}) } return ctx.JSON(http.StatusOK, map[string]interface{}{}) diff --git a/display/web/main.go b/display/web/main.go index 335d17d..fd232ec 100644 --- a/display/web/main.go +++ b/display/web/main.go @@ -32,6 +32,7 @@ var supportedExtensions = map[string]bool{ ".pptx": true, ".odp": true, } +var badRequestDescription string = "Request uses invalid JSON syntax or does not follow request schema." func StartWebServer(v string, port string) { version = v @@ -132,7 +133,7 @@ func extractFilePathMiddleware(next echo.HandlerFunc) echo.HandlerFunc { fullPath, exists, err := pkg.ResolveStorageFilePath(pathParam) if err != nil { slog.Warn("Failed to validate file path", "path", pathParam, "error", err) - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "Invalid file path"}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: "Invalid file path"}) } ctx.Set("fullPath", fullPath) ctx.Set("fileExists", exists) @@ -146,14 +147,14 @@ func shellCommandRoute(ctx echo.Context) error { } if err := ctx.Bind(&commandInput); err != nil { slog.Error("Failed to parse shell command", "error", err) - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "Invalid JSON request"}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: badRequestDescription}) } cmd := exec.Command("bash", "-c", commandInput.Command) storagePath, err := pkg.GetStoragePath() if err != nil { slog.Error("Failed to get storage path", "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Internal server error"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to get storage path"}) } cmd.Dir = storagePath @@ -172,23 +173,23 @@ func keyboardInputRoute(ctx echo.Context) error { } if err := ctx.Bind(&request); err != nil { slog.Error("Failed to parse keyboard input", "error", err) - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "Invalid JSON request"}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: badRequestDescription}) } code, ok := pkg.KeyboardEvents[request.Key] if !ok { slog.Error("Unsupported key", "key", request.Key) - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: fmt.Sprintf("Unsupported key: %s", request.Key)}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: fmt.Sprintf("Unsupported key: %s", request.Key)}) } err := pkg.KeyboardInput(code) if err != nil { slog.Error("Failed to send keyboard input", "key", request.Key, "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to send keyboard input"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to send keyboard input"}) } slog.Info("Keyboard input sent", "key", request.Key) - return ctx.JSON(http.StatusCreated, struct{ Message string }{Message: "Success"}) + return ctx.JSON(http.StatusOK, struct{}{}) } func uploadFileRoute(ctx echo.Context) error { @@ -196,42 +197,37 @@ func uploadFileRoute(ctx echo.Context) error { // Ensure parent directories exist if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to prepare storage directory"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to prepare storage directory"}) } if ctx.Get("fileExists").(bool) { - return ctx.JSON(http.StatusConflict, shared.ErrorResponse{Error: "File already exists"}) - } - - ext := strings.ToLower(filepath.Ext(fullPath)) - if !supportedExtensions[ext] { - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: fmt.Sprintf("Unsupported file extension: %s", ext)}) + return ctx.JSON(http.StatusConflict, shared.ErrorResponse{Description: "File already exists"}) } data, err := io.ReadAll(ctx.Request().Body) if err != nil { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to read file body"}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: badRequestDescription}) } if err := os.WriteFile(fullPath, data, os.ModePerm); err != nil { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to save file"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to save file"}) } slog.Info("File uploaded successfully", "path", fullPath) - return ctx.JSON(http.StatusCreated, struct{ Message string }{Message: "File uploaded successfully"}) + return ctx.JSON(http.StatusOK, struct{}{}) } func downloadFileRoute(ctx echo.Context) error { fullPath := ctx.Get("fullPath").(string) if !ctx.Get("fileExists").(bool) { - return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Error: "File not found"}) + return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Description: "File not found"}) } err := ctx.File(fullPath) if err != nil { slog.Error("Failed to serve file", "file", fullPath, "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Internal server error"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to serve file"}) } slog.Info("File downloaded successfully", "path", fullPath) @@ -243,17 +239,17 @@ func openFileRoute(ctx echo.Context) error { fullPath := ctx.Get("fullPath").(string) if !ctx.Get("fileExists").(bool) { - return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Error: "File not found"}) + return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Description: "File not found"}) } if sseConnection == nil { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Cant connect to display browser client"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Cant connect to display browser client"}) } err := resetView() if err != nil { slog.Error("Failed to reset view", "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to reset view"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to reset view"}) } ext := strings.ToLower(filepath.Ext(fullPath)) @@ -271,14 +267,14 @@ func openFileRoute(ctx echo.Context) error { err := pkg.OpenPresentation(fullPath) if err != nil { slog.Error("Failed to open presentation", "file", pathParam, "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to open presentation"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to open presentation"}) } default: - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "Unsupported file type"}) + return ctx.JSON(http.StatusUnsupportedMediaType, shared.ErrorResponse{Description: "Unsupported file type"}) } slog.Info("Successfully run file", "file", pathParam) - return ctx.JSON(http.StatusCreated, struct{ Message string }{Message: "Success"}) + return ctx.JSON(http.StatusOK, struct{}{}) } func showHTMLRoute(ctx echo.Context) error { @@ -287,19 +283,19 @@ func showHTMLRoute(ctx echo.Context) error { } if err := ctx.Bind(&request); err != nil { slog.Error("Failed to parse request", "error", err) - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "Invalid JSON request"}) + return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: badRequestDescription}) } err := resetView() if err != nil { slog.Error("Failed to reset view", "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to reset view"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to reset view"}) } sseConnection <- request.HTML slog.Info("HTML content sent to client") - return ctx.JSON(http.StatusCreated, struct{ Message string }{Message: "Success"}) + return ctx.JSON(http.StatusOK, struct{}{}) } func pingRoute(ctx echo.Context) error { @@ -314,13 +310,13 @@ func takeScreenshotRoute(ctx echo.Context) error { screenshotPath, err := pkg.TakeScreenshot() if err != nil { slog.Error("Failed to take screenshot", "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Internal server error"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to take screenshot"}) } err = ctx.File(screenshotPath) if err != nil { slog.Error("Failed to serve file", "file", screenshotPath, "error", err) - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Internal server error"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to serve file"}) } return nil @@ -330,19 +326,19 @@ func previewRoute(ctx echo.Context) error { fullPath := ctx.Get("fullPath").(string) exists := ctx.Get("fileExists").(bool) if !exists { - return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Error: "File not found"}) + return ctx.JSON(http.StatusNotFound, shared.ErrorResponse{Description: "File not found"}) } outputFilePath, err := pkg.GenerateFilePreview(fullPath) if err != nil { slog.Error("Failed to generate preview", "file", fullPath, "error", err) if errors.Is(err, pkg.ErrFileTypePreviewNotSupported) { - return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Error: "File type not supported for preview"}) + return ctx.JSON(http.StatusUnsupportedMediaType, shared.ErrorResponse{Description: "File type not supported for preview"}) } if errors.Is(err, pkg.ErrFilePreviewToolsMissing) { - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Required tools for file preview are missing"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Required tools for file preview are missing"}) } - return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Error: "Failed to generate preview"}) + return ctx.JSON(http.StatusInternalServerError, shared.ErrorResponse{Description: "Failed to generate preview"}) } return ctx.File(outputFilePath) diff --git a/shared/main.go b/shared/main.go index d9ad7a2..d380c6a 100644 --- a/shared/main.go +++ b/shared/main.go @@ -13,7 +13,7 @@ type CommandResponse struct { } type ErrorResponse struct { - Error string `json:"error"` + Description string `json:"description"` } func RunShellCommand(cmd *exec.Cmd) CommandResponse {