From 546cd608c3ddc7c3d79318a19d8c0aebef9ba5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Fri, 29 Jan 2021 20:05:13 +0100 Subject: [PATCH] join plain text and rich text to one struct. --- internal/api/room/clipboard.go | 39 +++++--------------- internal/api/room/handler.go | 18 ++++++---- internal/desktop/clipboard.go | 47 +++++++++++++++---------- internal/types/desktop.go | 11 +++--- internal/websocket/handler/clipboard.go | 5 ++- internal/websocket/manager.go | 5 +-- 6 files changed, 63 insertions(+), 62 deletions(-) diff --git a/internal/api/room/clipboard.go b/internal/api/room/clipboard.go index c610ef36..88514484 100644 --- a/internal/api/room/clipboard.go +++ b/internal/api/room/clipboard.go @@ -6,6 +6,7 @@ import ( "net/http" "demodesk/neko/internal/utils" + "demodesk/neko/internal/types" ) type ClipboardPayload struct { @@ -23,52 +24,30 @@ func (h *RoomHandler) clipboardGetTargets(w http.ResponseWriter, r *http.Request utils.HttpSuccess(w, targets) } -func (h *RoomHandler) clipboardGetPlainText(w http.ResponseWriter, r *http.Request) { - text, err := h.desktop.ClipboardGetPlainText() +func (h *RoomHandler) clipboardGetText(w http.ResponseWriter, r *http.Request) { + data, err := h.desktop.ClipboardGetText() if err != nil { utils.HttpInternalServerError(w, err) return } utils.HttpSuccess(w, ClipboardPayload{ - Text: text, + Text: data.Text, + HTML: data.HTML, }) } -func (h *RoomHandler) clipboardSetPlainText(w http.ResponseWriter, r *http.Request) { +func (h *RoomHandler) clipboardSetText(w http.ResponseWriter, r *http.Request) { data := &ClipboardPayload{} if !utils.HttpJsonRequest(w, r, data) { return } - err := h.desktop.ClipboardSetPlainText(data.Text) - if err != nil { - utils.HttpInternalServerError(w, err) - return - } - - utils.HttpSuccess(w) -} - -func (h *RoomHandler) clipboardGetRichText(w http.ResponseWriter, r *http.Request) { - html, err := h.desktop.ClipboardGetRichText() - if err != nil { - utils.HttpInternalServerError(w, err) - return - } - - utils.HttpSuccess(w, ClipboardPayload{ - HTML: html, + err := h.desktop.ClipboardSetText(types.ClipboardText{ + Text: data.Text, + HTML: data.HTML, }) -} -func (h *RoomHandler) clipboardSetRichText(w http.ResponseWriter, r *http.Request) { - data := &ClipboardPayload{} - if !utils.HttpJsonRequest(w, r, data) { - return - } - - err := h.desktop.ClipboardSetRichText(data.HTML) if err != nil { utils.HttpInternalServerError(w, err) return diff --git a/internal/api/room/handler.go b/internal/api/room/handler.go index 74a44625..1045cd96 100644 --- a/internal/api/room/handler.go +++ b/internal/api/room/handler.go @@ -38,14 +38,18 @@ func (h *RoomHandler) Route(r chi.Router) { }) r.With(auth.HostsOnly).Route("/clipboard", func(r chi.Router) { - r.Get("/", h.clipboardGetPlainText) - r.Post("/", h.clipboardSetPlainText) - r.Get("/targets", h.clipboardGetTargets) - r.Get("/html", h.clipboardGetRichText) - r.Post("/html", h.clipboardSetRichText) - r.Get("/image", h.clipboardGetImage) - // TODO: Refactor. + r.Get("/", h.clipboardGetText) + r.Post("/", h.clipboardSetText) + r.Get("/image.png", h.clipboardGetImage) + + // TODO: Refactor. xclip is failing to set propper target type + // and this content is sent back to client as text in another + // clipboard update. Therefore endpoint is not usable! //r.Post("/image", h.clipboardSetImage) + + // TODO: Refactor. If there would be implemented custom target + // retrieval, this endpoint would be useful. + //r.Get("/targets", h.clipboardGetTargets) }) r.Route("/keyboard", func(r chi.Router) { diff --git a/internal/desktop/clipboard.go b/internal/desktop/clipboard.go index 2036ee5d..f6d94fb5 100644 --- a/internal/desktop/clipboard.go +++ b/internal/desktop/clipboard.go @@ -5,8 +5,37 @@ import ( "bytes" "os/exec" "strings" + + "demodesk/neko/internal/types" ) +func (manager *DesktopManagerCtx) ClipboardGetText() (*types.ClipboardText, error) { + text, err := manager.ClipboardGetBinary("STRING") + if err != nil { + return nil, err + } + + // Rich text must not always be available, can fail silently. + html, _ := manager.ClipboardGetBinary("text/html") + + return &types.ClipboardText{ + Text: string(text), + HTML: string(html), + }, nil +} + +func (manager *DesktopManagerCtx) ClipboardSetText(data types.ClipboardText) error { + // TODO: Refactor. + // Current implementation is unable to set multiple targets. HTML + // is set, if available. Otherwise plain text. + + if data.HTML != "" { + return manager.ClipboardSetBinary("text/html", []byte(data.HTML)) + } + + return manager.ClipboardSetBinary("STRING", []byte(data.Text)) +} + func (manager *DesktopManagerCtx) ClipboardGetBinary(mime string) ([]byte, error) { cmd := exec.Command("xclip", "-selection", "clipboard", "-out", "-target", mime) @@ -77,21 +106,3 @@ func (manager *DesktopManagerCtx) ClipboardGetTargets() ([]string, error) { return response, nil } - -func (manager *DesktopManagerCtx) ClipboardGetPlainText() (string, error) { - bytes, err := manager.ClipboardGetBinary("STRING") - return string(bytes), err -} - -func (manager *DesktopManagerCtx) ClipboardSetPlainText(data string) error { - return manager.ClipboardSetBinary("STRING", []byte(data)) -} - -func (manager *DesktopManagerCtx) ClipboardGetRichText() (string, error) { - bytes, err := manager.ClipboardGetBinary("text/html") - return string(bytes), err -} - -func (manager *DesktopManagerCtx) ClipboardSetRichText(data string) error { - return manager.ClipboardSetBinary("text/html", []byte(data)) -} diff --git a/internal/types/desktop.go b/internal/types/desktop.go index 61db56f5..1501fc40 100644 --- a/internal/types/desktop.go +++ b/internal/types/desktop.go @@ -35,6 +35,11 @@ type KeyboardMap struct { Variant string } +type ClipboardText struct { + Text string + HTML string +} + type DesktopManager interface { Start() Shutdown() error @@ -67,13 +72,11 @@ type DesktopManager interface { OnEventError(listener func(error_code uint8, message string, request_code uint8, minor_code uint8)) // clipboard + ClipboardGetText() (*ClipboardText, error) + ClipboardSetText(data ClipboardText) error ClipboardGetBinary(mime string) ([]byte, error) ClipboardSetBinary(mime string, data []byte) error ClipboardGetTargets() ([]string, error) - ClipboardGetPlainText() (string, error) - ClipboardSetPlainText(data string) error - ClipboardGetRichText() (string, error) - ClipboardSetRichText(data string) error // drop DropFiles(x int, y int, files []string) bool diff --git a/internal/websocket/handler/clipboard.go b/internal/websocket/handler/clipboard.go index 69e21dcf..50ae6cfa 100644 --- a/internal/websocket/handler/clipboard.go +++ b/internal/websocket/handler/clipboard.go @@ -16,5 +16,8 @@ func (h *MessageHandlerCtx) clipboardSet(session types.Session, payload *message return nil } - return h.desktop.ClipboardSetPlainText(payload.Text) + return h.desktop.ClipboardSetText(types.ClipboardText{ + Text: payload.Text, + // TODO: Send HTML? + }) } diff --git a/internal/websocket/manager.go b/internal/websocket/manager.go index eb35a0a0..9b218ab3 100644 --- a/internal/websocket/manager.go +++ b/internal/websocket/manager.go @@ -117,14 +117,15 @@ func (ws *WebSocketManagerCtx) Start() { return } - text, err := ws.desktop.ClipboardGetPlainText() + data, err := ws.desktop.ClipboardGetText() if err != nil { ws.logger.Warn().Err(err).Msg("could not get clipboard content") } if err := session.Send(message.ClipboardData{ Event: event.CLIPBOARD_UPDATED, - Text: text, + Text: data.Text, + // TODO: Send HTML? }); err != nil { ws.logger.Warn().Err(err).Msg("could not sync clipboard") }