From a4f1cfbe0d50f98f9b55ebc629bc4ae02eaf05d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Wed, 8 Apr 2026 15:16:47 +0200 Subject: [PATCH] refactor: standardize constant names and improve goroutine handling across multiple files. --- server/internal/api/room/clipboard.go | 2 +- server/internal/api/room/upload.go | 6 ++-- server/internal/capture/screencast.go | 15 +++------- server/internal/capture/streamsink.go | 7 ++--- server/internal/config/capture_pipeline.go | 7 +++-- server/internal/desktop/clipboard.go | 22 +++++++-------- server/internal/desktop/drop.go | 17 +++++++---- server/internal/desktop/filechooserdialog.go | 19 ++++++++----- server/internal/desktop/manager.go | 20 +++++++------ .../internal/plugins/filetransfer/manager.go | 4 +-- server/internal/session/session.go | 4 +-- server/internal/webrtc/metrics.go | 10 ++++--- server/internal/webrtc/peer.go | 12 +++----- server/internal/websocket/manager.go | 28 ++++++++----------- 14 files changed, 85 insertions(+), 88 deletions(-) diff --git a/server/internal/api/room/clipboard.go b/server/internal/api/room/clipboard.go index 234c4ac6..a422cb13 100644 --- a/server/internal/api/room/clipboard.go +++ b/server/internal/api/room/clipboard.go @@ -61,7 +61,7 @@ func (h *RoomHandler) clipboardGetImage(w http.ResponseWriter, r *http.Request) /* TODO: Unused now. func (h *RoomHandler) clipboardSetImage(w http.ResponseWriter, r *http.Request) error { - err := r.ParseMultipartForm(MAX_UPLOAD_SIZE) + err := r.ParseMultipartForm(multipartFormMaxMemory) if err != nil { return utils.HttpBadRequest("failed to parse multipart form").WithInternalErr(err) } diff --git a/server/internal/api/room/upload.go b/server/internal/api/room/upload.go index 3ff04616..8da7b601 100644 --- a/server/internal/api/room/upload.go +++ b/server/internal/api/room/upload.go @@ -13,14 +13,14 @@ import ( // TODO: Extract file uploading to custom utility. // maximum upload size of 32 MB -const maxUploadSize = 32 << 20 +const multipartFormMaxMemory = 32 << 20 func (h *RoomHandler) uploadDrop(w http.ResponseWriter, r *http.Request) error { if !h.desktop.IsUploadDropEnabled() { return utils.HttpBadRequest("upload drop is disabled") } - err := r.ParseMultipartForm(maxUploadSize) + err := r.ParseMultipartForm(multipartFormMaxMemory) if err != nil { return utils.HttpBadRequest("failed to parse multipart form").WithInternalErr(err) } @@ -95,7 +95,7 @@ func (h *RoomHandler) uploadDialogPost(w http.ResponseWriter, r *http.Request) e return utils.HttpBadRequest("file chooser dialog is disabled") } - err := r.ParseMultipartForm(maxUploadSize) + err := r.ParseMultipartForm(multipartFormMaxMemory) if err != nil { return utils.HttpBadRequest("failed to parse multipart form").WithInternalErr(err) } diff --git a/server/internal/capture/screencast.go b/server/internal/capture/screencast.go index efd54bfd..3850c64d 100644 --- a/server/internal/capture/screencast.go +++ b/server/internal/capture/screencast.go @@ -87,11 +87,7 @@ func screencastNew(enabled bool, pipelineStr string) *ScreencastManagerCtx { }), } - manager.wg.Add(1) - - go func() { - defer manager.wg.Done() - + manager.wg.Go(func() { ticker := time.NewTicker(screencastTimeout) defer ticker.Stop() @@ -105,7 +101,7 @@ func screencastNew(enabled bool, pipelineStr string) *ScreencastManagerCtx { } } } - }() + }) return manager } @@ -212,12 +208,9 @@ func (manager *ScreencastManagerCtx) createPipeline() error { return errors.New("timeouted while waiting for first image") } - manager.wg.Add(1) pipeline := manager.pipeline - - go func() { + manager.wg.Go(func() { manager.logger.Debug().Msg("started receiving images") - defer manager.wg.Done() for { image, ok := <-pipeline.Sample() @@ -228,7 +221,7 @@ func (manager *ScreencastManagerCtx) createPipeline() error { manager.setImage(image) } - }() + }) return nil } diff --git a/server/internal/capture/streamsink.go b/server/internal/capture/streamsink.go index 0d0905d5..903f49e5 100644 --- a/server/internal/capture/streamsink.go +++ b/server/internal/capture/streamsink.go @@ -325,12 +325,9 @@ func (manager *StreamSinkManagerCtx) CreatePipeline() error { manager.pipeline.AttachAppsink("appsink") manager.pipeline.Play() - manager.wg.Add(1) pipeline := manager.pipeline - - go func() { + manager.wg.Go(func() { manager.logger.Debug().Msg("started emitting samples") - defer manager.wg.Done() for { sample, ok := <-pipeline.Sample() @@ -341,7 +338,7 @@ func (manager *StreamSinkManagerCtx) CreatePipeline() error { manager.onSample(sample) } - }() + }) manager.pipelinesCounter.Inc() manager.pipelinesActive.Set(1) diff --git a/server/internal/config/capture_pipeline.go b/server/internal/config/capture_pipeline.go index 07cece22..f7e0c476 100644 --- a/server/internal/config/capture_pipeline.go +++ b/server/internal/config/capture_pipeline.go @@ -150,19 +150,20 @@ func NewVideoPipeline(rtpCodec codec.RTPCodec, display string, pipelineSrc strin vbvbuf = bitrate } - if hwenc == HwEncVAAPI { + switch hwenc { + case HwEncVAAPI: if err := gst.CheckPlugins([]string{"vaapi"}); err != nil { return "", err } pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! vaapih264enc rate-control=vbr bitrate=%d keyframe-period=180 quality-level=7 ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate) - } else if hwenc == HwEncNVENC { + case HwEncNVENC: if err := gst.CheckPlugins([]string{"nvcodec"}); err != nil { return "", err } pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! nvh264enc name=encoder preset=2 gop-size=25 spatial-aq=true temporal-aq=true bitrate=%d vbv-buffer-size=%d rc-mode=6 ! h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,profile=constrained-baseline"+pipelineStr, display, fps, bitrate, vbvbuf) - } else { + default: // https://gstreamer.freedesktop.org/documentation/openh264/openh264enc.html?gi-language=c#openh264enc // gstreamer1.0-plugins-bad // openh264enc multi-thread=4 complexity=high bitrate=3072000 max-bitrate=4096000 diff --git a/server/internal/desktop/clipboard.go b/server/internal/desktop/clipboard.go index fff20d8b..1386185e 100644 --- a/server/internal/desktop/clipboard.go +++ b/server/internal/desktop/clipboard.go @@ -11,18 +11,21 @@ import ( ) const ( - ClipboardTextPlainTarget = "UTF8_STRING" - ClipboardTextHtmlTarget = "text/html" + // MIME type for plain text in clipboard + clipboardTextPlainTarget = "UTF8_STRING" + + // MIME type for HTML in clipboard + clipboardTextHtmlTarget = "text/html" ) func (manager *DesktopManagerCtx) ClipboardGetText() (*types.ClipboardText, error) { - text, err := manager.ClipboardGetBinary(ClipboardTextPlainTarget) + text, err := manager.ClipboardGetBinary(clipboardTextPlainTarget) if err != nil { return nil, err } // Rich text must not always be available, can fail silently. - html, _ := manager.ClipboardGetBinary(ClipboardTextHtmlTarget) + html, _ := manager.ClipboardGetBinary(clipboardTextHtmlTarget) return &types.ClipboardText{ Text: string(text), @@ -36,10 +39,10 @@ func (manager *DesktopManagerCtx) ClipboardSetText(data types.ClipboardText) err // is set, if available. Otherwise plain text. if data.HTML != "" { - return manager.ClipboardSetBinary(ClipboardTextHtmlTarget, []byte(data.HTML)) + return manager.ClipboardSetBinary(clipboardTextHtmlTarget, []byte(data.HTML)) } - return manager.ClipboardSetBinary(ClipboardTextPlainTarget, []byte(data.Text)) + return manager.ClipboardSetBinary(clipboardTextPlainTarget, []byte(data.Text)) } func (manager *DesktopManagerCtx) ClipboardGetBinary(mime string) ([]byte, error) { @@ -114,17 +117,14 @@ func (manager *DesktopManagerCtx) ClipboardSetBinary(mime string, data []byte) e case <-wait: } - manager.wg.Add(1) - go func() { - defer manager.wg.Done() - + manager.wg.Go(func() { if err := cmd.Wait(); err != nil { msg := strings.TrimSpace(stderr.String()) manager.logger.Err(err).Msgf("clipboard command finished with error: %s", msg) } else { manager.logger.Debug().Msg("clipboard command finished successfully") } - }() + }) return nil } diff --git a/server/internal/desktop/drop.go b/server/internal/desktop/drop.go index ed102f98..bda3bcec 100644 --- a/server/internal/desktop/drop.go +++ b/server/internal/desktop/drop.go @@ -6,11 +6,16 @@ import ( "github.com/m1k1o/neko/server/pkg/drop" ) -// repeat move event multiple times -const dropMoveRepeat = 4 +const ( + // repeat move event multiple times + dropMoveRepeat = 4 -// wait after each repeated move event -const dropMoveDelay = 100 * time.Millisecond + // wait after each repeated move event + dropMoveDelay = 100 * time.Millisecond + + // wait for drop to finish before giving up + dropFinishTimeout = 1 * time.Second +) func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool { mu.Lock() @@ -32,7 +37,7 @@ func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool { }) drop.Emmiter.Once("begin", func(payload ...any) { - for i := 0; i < dropMoveRepeat; i++ { + for range dropMoveRepeat { manager.Move(x, y) time.Sleep(dropMoveDelay) } @@ -57,7 +62,7 @@ func (manager *DesktopManagerCtx) DropFiles(x int, y int, files []string) bool { select { case succeeded := <-finished: return succeeded - case <-time.After(1 * time.Second): + case <-time.After(dropFinishTimeout): drop.CloseWindow() return false } diff --git a/server/internal/desktop/filechooserdialog.go b/server/internal/desktop/filechooserdialog.go index 14c70217..9b7cbb3b 100644 --- a/server/internal/desktop/filechooserdialog.go +++ b/server/internal/desktop/filechooserdialog.go @@ -7,14 +7,19 @@ import ( "github.com/m1k1o/neko/server/pkg/xorg" ) -// name of the window that is being controlled -const fileChooserDialogName = "Open File" +const ( + // name of the window that is being controlled + fileChooserDialogName = "Open File" -// short sleep value between fake user interactions -const fileChooserDialogShortSleep = "0.2" + // short sleep value between fake user interactions + fileChooserDialogShortSleep = "0.2" -// long sleep value between fake user interactions -const fileChooserDialogLongSleep = "0.4" + // long sleep value between fake user interactions + fileChooserDialogLongSleep = "0.4" + + // number of attempts to close the dialog + fileChooserDialogCloseAttempts = 5 +) func (manager *DesktopManagerCtx) HandleFileChooserDialog(uri string) error { mu.Lock() @@ -57,7 +62,7 @@ func (manager *DesktopManagerCtx) HandleFileChooserDialog(uri string) error { } func (manager *DesktopManagerCtx) CloseFileChooserDialog() { - for i := 0; i < 5; i++ { + for range fileChooserDialogCloseAttempts { mu.Lock() manager.logger.Debug().Msg("attempting to close file chooser dialog") diff --git a/server/internal/desktop/manager.go b/server/internal/desktop/manager.go index aca5fe1a..00d0bef7 100644 --- a/server/internal/desktop/manager.go +++ b/server/internal/desktop/manager.go @@ -17,6 +17,14 @@ import ( "github.com/m1k1o/neko/server/pkg/xorg" ) +const ( + // debounce frequency for key events + debounceFrequency = 1 * time.Second + + // debounce duration for key events + debounceDuration = 10 * time.Second +) + var mu = sync.Mutex{} type DesktopManagerCtx struct { @@ -100,16 +108,10 @@ func (manager *DesktopManagerCtx) Start() { Msg("X event error occured") }) - manager.wg.Add(1) - - go func() { - defer manager.wg.Done() - - ticker := time.NewTicker(1 * time.Second) + manager.wg.Go(func() { + ticker := time.NewTicker(debounceFrequency) defer ticker.Stop() - const debounceDuration = 10 * time.Second - for { select { case <-manager.shutdown: @@ -119,7 +121,7 @@ func (manager *DesktopManagerCtx) Start() { manager.input.Debounce(debounceDuration) } } - }() + }) } func (manager *DesktopManagerCtx) OnBeforeScreenSizeChange(listener func()) { diff --git a/server/internal/plugins/filetransfer/manager.go b/server/internal/plugins/filetransfer/manager.go index 2c7d38fc..e805b35a 100644 --- a/server/internal/plugins/filetransfer/manager.go +++ b/server/internal/plugins/filetransfer/manager.go @@ -20,7 +20,7 @@ import ( "github.com/rs/zerolog/log" ) -const MULTIPART_FORM_MAX_MEMORY = 32 << 20 +const multipartFormMaxMemory = 32 << 20 func NewManager( sessions types.SessionManager, @@ -285,7 +285,7 @@ func (m *Manager) uploadFileHandler(w http.ResponseWriter, r *http.Request) erro return utils.HttpForbidden("file transfer is disabled") } - err = r.ParseMultipartForm(MULTIPART_FORM_MAX_MEMORY) + err = r.ParseMultipartForm(multipartFormMaxMemory) if err != nil || r.MultipartForm == nil { return utils.HttpBadRequest(). WithInternalErr(err). diff --git a/server/internal/session/session.go b/server/internal/session/session.go index 95a5ad65..e96a3e74 100644 --- a/server/internal/session/session.go +++ b/server/internal/session/session.go @@ -12,7 +12,7 @@ import ( // client is expected to reconnect within 5 second // if some unexpected websocket disconnect happens -const WS_DELAYED_DURATION = 5 * time.Second +const wsDelayedDuration = 5 * time.Second type SessionCtx struct { id string @@ -165,7 +165,7 @@ func (session *SessionCtx) DisconnectWebSocketPeer(websocketPeer types.WebSocket var wsDelayedTimer *time.Timer if delayed { - wsDelayedTimer = time.AfterFunc(WS_DELAYED_DURATION, func() { + wsDelayedTimer = time.AfterFunc(wsDelayedDuration, func() { session.DisconnectWebSocketPeer(websocketPeer, false) }) } diff --git a/server/internal/webrtc/metrics.go b/server/internal/webrtc/metrics.go index 8badadaa..521c7195 100644 --- a/server/internal/webrtc/metrics.go +++ b/server/internal/webrtc/metrics.go @@ -284,9 +284,10 @@ func (met *metrics) NewICECandidate(candidate webrtc.ICECandidateStats) { } met.iceCandidates[candidate.ID] = struct{}{} - if candidate.Protocol == "udp" { + switch candidate.Protocol { + case "udp": met.iceCandidatesUdpCount.Add(1) - } else if candidate.Protocol == "tcp" { + case "tcp": met.iceCandidatesTcpCount.Add(1) } } @@ -294,9 +295,10 @@ func (met *metrics) NewICECandidate(candidate webrtc.ICECandidateStats) { func (met *metrics) SetICECandidatesUsed(candidates []webrtc.ICECandidateStats) { udp, tcp := 0, 0 for _, candidate := range candidates { - if candidate.Protocol == "udp" { + switch candidate.Protocol { + case "udp": udp++ - } else if candidate.Protocol == "tcp" { + case "tcp": tcp++ } } diff --git a/server/internal/webrtc/peer.go b/server/internal/webrtc/peer.go index 3310b624..745c9682 100644 --- a/server/internal/webrtc/peer.go +++ b/server/internal/webrtc/peer.go @@ -401,10 +401,8 @@ func (peer *WebRTCPeerCtx) SetVideo(r types.PeerVideoRequest) error { // send video signal if modified if modified { - go func() { - // in goroutine because of mutex and we don't want to block - peer.session.Send(event.SIGNAL_VIDEO, peer.Video()) - }() + // in goroutine because of mutex and we don't want to block + go peer.session.Send(event.SIGNAL_VIDEO, peer.Video()) } return nil @@ -455,10 +453,8 @@ func (peer *WebRTCPeerCtx) SetAudio(r types.PeerAudioRequest) error { // send video signal if modified if modified { - go func() { - // in goroutine because of mutex and we don't want to block - peer.session.Send(event.SIGNAL_AUDIO, peer.Audio()) - }() + // in goroutine because of mutex and we don't want to block + go peer.session.Send(event.SIGNAL_AUDIO, peer.Audio()) } return nil diff --git a/server/internal/websocket/manager.go b/server/internal/websocket/manager.go index 9fc21f60..9fd67fab 100644 --- a/server/internal/websocket/manager.go +++ b/server/internal/websocket/manager.go @@ -18,14 +18,16 @@ import ( "github.com/m1k1o/neko/server/pkg/utils" ) -// send pings to peer with this period - must be less than pongWait -const pingPeriod = 10 * time.Second +const ( + // send pings to peer with this period - must be less than pongWait + pingPeriod = 10 * time.Second -// period for sending inactive cursor messages -const inactiveCursorsPeriod = 750 * time.Millisecond + // period for sending inactive cursor messages + inactiveCursorsPeriod = 750 * time.Millisecond -// maximum payload length for logging -const maxPayloadLogLength = 10_000 + // maximum payload length for logging + maxPayloadLogLength = 10_000 +) // events that are not logged in debug mode var nologEvents = []string{ @@ -309,10 +311,7 @@ func (manager *WebSocketManagerCtx) handle(connection *websocket.Conn, peer type ticker := time.NewTicker(pingPeriod) defer ticker.Stop() - manager.wg.Add(1) - go func() { - defer manager.wg.Done() - + manager.wg.Go(func() { for { _, raw, err := connection.ReadMessage() if err != nil { @@ -322,7 +321,7 @@ func (manager *WebSocketManagerCtx) handle(connection *websocket.Conn, peer type bytes <- raw } - }() + }) for { select { @@ -381,10 +380,7 @@ func (manager *WebSocketManagerCtx) startInactiveCursors() { manager.logger.Info().Msg("starting inactive cursors handler") manager.shutdownInactiveCursors = make(chan struct{}) - manager.wg.Add(1) - go func() { - defer manager.wg.Done() - + manager.wg.Go(func() { ticker := time.NewTicker(inactiveCursorsPeriod) defer ticker.Stop() @@ -424,7 +420,7 @@ func (manager *WebSocketManagerCtx) startInactiveCursors() { manager.sessions.InactiveCursorsBroadcast(event.SESSION_CURSORS, sessionCursors) } } - }() + }) } func (manager *WebSocketManagerCtx) stopInactiveCursors() {