mirror of
https://github.com/m1k1o/neko.git
synced 2026-11-03 00:11:48 -06:00
refactor: standardize constant names and improve goroutine handling across multiple files.
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user