From cfb26a0b47e91a1ed19a81ea97459801d6e75b50 Mon Sep 17 00:00:00 2001 From: 2mal3 <56305732+2mal3@users.noreply.github.com> Date: Wed, 3 Dec 2025 17:29:45 +0100 Subject: [PATCH] fix(display): custom program file handling --- display/pkg/file_handler.go | 63 ++++++++++++++++++++++++++++++++++++ display/pkg/file_handlers.go | 44 ------------------------- display/web/main.go | 8 ++--- shared/main.go | 2 +- 4 files changed, 67 insertions(+), 50 deletions(-) create mode 100644 display/pkg/file_handler.go delete mode 100644 display/pkg/file_handlers.go diff --git a/display/pkg/file_handler.go b/display/pkg/file_handler.go new file mode 100644 index 0000000..3c37a39 --- /dev/null +++ b/display/pkg/file_handler.go @@ -0,0 +1,63 @@ +package pkg + +import ( + "fmt" + "os" + "os/exec" + "plg-mudics/shared" + "syscall" + + "github.com/gabriel-vasile/mimetype" +) + +var FileHandler fileHandler = fileHandler{} + +type fileHandler struct { + runningProgram *exec.Cmd +} + +func (fh *fileHandler) OpenFile(path string) error { + var err error + + mType, err := mimetype.DetectFile(path) + if err != nil { + return fmt.Errorf("failed to detect mime type: %w", err) + } + + tempDirPath, err := os.MkdirTemp("", "plg-mudics-program-profile-") + if err != nil { + return fmt.Errorf("failed to create temporary profile directory: %w", err) + } + + err = fh.CloseRunningProgram() + if err != nil { + return err + } + + switch mType.String() { + case "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.oasis.opendocument.presentation": + fh.runningProgram = exec.Command("soffice", "--show", path, "--nologo", "--view", "--norestore", fmt.Sprintf("-env:UserInstallation=file://%s", tempDirPath)) + case "application/pdf": + fh.runningProgram = exec.Command("xreader", path, "--presentation") + default: + return fmt.Errorf("unsupported file type: %s", mType.String()) + } + + fh.runningProgram.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + + result := shared.RunShellCommandNonBlocking(fh.runningProgram) + if result.ExitCode != 0 { + return fmt.Errorf("could not open pdf: %s (%d)", result.Stderr, result.ExitCode) + } + + return nil +} + +func (fh *fileHandler) CloseRunningProgram() error { + if fh.runningProgram == nil { + return nil + } + err := syscall.Kill(-fh.runningProgram.Process.Pid, syscall.SIGTERM) + fh.runningProgram = nil + return err +} diff --git a/display/pkg/file_handlers.go b/display/pkg/file_handlers.go deleted file mode 100644 index d0183d7..0000000 --- a/display/pkg/file_handlers.go +++ /dev/null @@ -1,44 +0,0 @@ -package pkg - -import ( - "errors" - "fmt" - "os" - "os/exec" - "plg-mudics/shared" -) - -var runningHelpProgram *exec.Cmd = nil - -func OpenPresentation(path string) error { - tempDirPath, err := os.MkdirTemp("", "plg-mudics-libreoffice-profile-") - if err != nil { - return fmt.Errorf("failed to create temporary profile directory: %w", err) - } - - result := shared.RunShellCommand(runningHelpProgram) - runningHelpProgram = exec.Command("soffice", "--show", path, "--nologo", "--view", "--norestore", fmt.Sprintf("-env:UserInstallation=file:///%s", tempDirPath)) - killedByParent := -1 - if result.ExitCode != 0 && result.ExitCode != killedByParent { - return errors.New(result.Stderr) - } - return nil -} - -func OpenPDF(path string) error { - runningHelpProgram = exec.Command("xreader", path, "--presentation") - result := shared.RunShellCommandNonBlocking(runningHelpProgram) - killedByParent := -1 - if result.ExitCode != 0 && result.ExitCode != killedByParent { - return fmt.Errorf("could not open pdf: %s (%d)", result.Stderr, result.ExitCode) - } - return nil -} - -func CloseRunningProgram() error { - if runningHelpProgram == nil { - return nil - } - err := runningHelpProgram.Process.Kill() - return err -} diff --git a/display/web/main.go b/display/web/main.go index 809bb66..24b9345 100644 --- a/display/web/main.go +++ b/display/web/main.go @@ -322,10 +322,8 @@ func openFileRoute(ctx echo.Context) error { var templateBuffer bytes.Buffer imageTemplate(pathParam).Render(context.Background(), &templateBuffer) sseConnection <- templateBuffer.String() - case "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.oasis.opendocument.presentation": - err = pkg.OpenPresentation(fullPath) - case "application/pdf": - err = pkg.OpenPDF(fullPath) + case "application/pdf", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.oasis.opendocument.presentation": + err = pkg.FileHandler.OpenFile(fullPath) default: slog.Info("Unsupported file type", "type", mType) return ctx.JSON(http.StatusUnsupportedMediaType, shared.ErrorResponse{Description: "Unsupported file type: " + mType.String()}) @@ -409,7 +407,7 @@ func previewRoute(ctx echo.Context) error { // Reset previous file views so they dont collide with the new one func resetView() error { - err := pkg.CloseRunningProgram() + err := pkg.FileHandler.CloseRunningProgram() if err != nil { return fmt.Errorf("failed to close running program: %w", err) } diff --git a/shared/main.go b/shared/main.go index a596961..a50761b 100644 --- a/shared/main.go +++ b/shared/main.go @@ -36,7 +36,7 @@ func RunShellCommandNonBlocking(cmd *exec.Cmd) CommandResponse { cmd.Stderr = &stderr cmd.Start() - ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() done := make(chan error, 1)