From 5d62e56d601ebf66a81a702f68aa1f58072106b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Thu, 7 Nov 2024 16:47:31 +0100 Subject: [PATCH 1/4] fixes issue where url was updated after broadcast was started, #429. --- server/internal/capture/broadcast.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/internal/capture/broadcast.go b/server/internal/capture/broadcast.go index fc6727e1..16cb353f 100644 --- a/server/internal/capture/broadcast.go +++ b/server/internal/capture/broadcast.go @@ -46,12 +46,13 @@ func (manager *BroacastManagerCtx) Start(url string) error { manager.mu.Lock() defer manager.mu.Unlock() + manager.url = url + err := manager.createPipeline() if err != nil { return err } - manager.url = url manager.started = true return nil } From e3b6e006481433b437634265f137f08efa8b4f1f Mon Sep 17 00:00:00 2001 From: Mmx <36563672+Mmx233@users.noreply.github.com> Date: Mon, 30 Dec 2024 20:44:05 +0800 Subject: [PATCH 2/4] feat(general): add heartbeat to websocket control (#460) * chore: ignore .idea * feat: add heartbeat event to websocket * feat: add HeartbeatInterval to websocket config * feat: send HeartbeatInterval in SYSTEM_INIT message * feat: add heartbeat logic * fix: client events is not in WebSocketEvents type --- .gitignore | 3 +++ client/src/neko/base.ts | 6 ++++++ client/src/neko/events.ts | 5 +++++ client/src/neko/index.ts | 7 ++++++- client/src/neko/messages.ts | 1 + server/internal/config/websocket.go | 9 +++++++++ server/internal/types/event/events.go | 4 ++++ server/internal/types/message/messages.go | 9 +++++---- server/internal/websocket/handler/handler.go | 5 +++++ server/internal/websocket/handler/session.go | 11 ++++++----- server/internal/websocket/websocket.go | 2 +- 11 files changed, 51 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 44d65cd8..8940655f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ bin # Environment files *.env + +# Code Editors +.idea \ No newline at end of file diff --git a/client/src/neko/base.ts b/client/src/neko/base.ts index 43267b1d..3df2b94c 100644 --- a/client/src/neko/base.ts +++ b/client/src/neko/base.ts @@ -20,6 +20,7 @@ export interface BaseEvents { export abstract class BaseClient extends EventEmitter { protected _ws?: WebSocket + protected _ws_heartbeat?: number protected _peer?: RTCPeerConnection protected _channel?: RTCDataChannel protected _timeout?: number @@ -80,6 +81,11 @@ export abstract class BaseClient extends EventEmitter { this._timeout = undefined } + if (this._ws_heartbeat) { + clearInterval(this._ws_heartbeat) + this._ws_heartbeat = undefined + } + if (this._ws) { // reset all events this._ws.onmessage = () => {} diff --git a/client/src/neko/events.ts b/client/src/neko/events.ts index 5deb010a..45c264db 100644 --- a/client/src/neko/events.ts +++ b/client/src/neko/events.ts @@ -14,6 +14,9 @@ export const EVENT = { DISCONNECT: 'system/disconnect', ERROR: 'system/error', }, + CLIENT: { + HEARTBEAT: 'client/heartbeat' + }, SIGNAL: { OFFER: 'signal/offer', ANSWER: 'signal/answer', @@ -69,6 +72,7 @@ export type Events = typeof EVENT export type WebSocketEvents = | SystemEvents + | ClientEvents | ControlEvents | MemberEvents | SignalEvents @@ -87,6 +91,7 @@ export type ControlEvents = | typeof EVENT.CONTROL.KEYBOARD export type SystemEvents = typeof EVENT.SYSTEM.DISCONNECT +export type ClientEvents = typeof EVENT.CLIENT.HEARTBEAT export type MemberEvents = typeof EVENT.MEMBER.LIST | typeof EVENT.MEMBER.CONNECTED | typeof EVENT.MEMBER.DISCONNECTED export type SignalEvents = diff --git a/client/src/neko/index.ts b/client/src/neko/index.ts index 16ca0b6f..d40fa568 100644 --- a/client/src/neko/index.ts +++ b/client/src/neko/index.ts @@ -134,7 +134,7 @@ export class NekoClient extends BaseClient implements EventEmitter { ///////////////////////////// // System Events ///////////////////////////// - protected [EVENT.SYSTEM.INIT]({ implicit_hosting, locks, file_transfer }: SystemInitPayload) { + protected [EVENT.SYSTEM.INIT]({ implicit_hosting, locks, file_transfer, heartbeat_interval }: SystemInitPayload) { this.$accessor.remote.setImplicitHosting(implicit_hosting) this.$accessor.remote.setFileTransfer(file_transfer) @@ -145,6 +145,11 @@ export class NekoClient extends BaseClient implements EventEmitter { id: locks[resource], }) } + + if (heartbeat_interval > 0) { + if (this._ws_heartbeat) clearInterval(this._ws_heartbeat) + this._ws_heartbeat = window.setInterval(() => this.sendMessage(EVENT.CLIENT.HEARTBEAT), heartbeat_interval * 1000) + } } protected [EVENT.SYSTEM.DISCONNECT]({ message }: SystemMessagePayload) { diff --git a/client/src/neko/messages.ts b/client/src/neko/messages.ts index 54d1cb11..ac12ef23 100644 --- a/client/src/neko/messages.ts +++ b/client/src/neko/messages.ts @@ -61,6 +61,7 @@ export interface SystemInitPayload { implicit_hosting: boolean locks: Record file_transfer: boolean + heartbeat_interval: number } // system/disconnect diff --git a/server/internal/config/websocket.go b/server/internal/config/websocket.go index 9bf97381..589b5b07 100644 --- a/server/internal/config/websocket.go +++ b/server/internal/config/websocket.go @@ -14,6 +14,8 @@ type WebSocket struct { ControlProtection bool + HeartbeatInterval int + FileTransferEnabled bool FileTransferPath string } @@ -39,6 +41,11 @@ func (WebSocket) Init(cmd *cobra.Command) error { return err } + cmd.PersistentFlags().Int("heartbeat_interval", 120, "heartbeat interval in seconds") + if err := viper.BindPFlag("heartbeat_interval", cmd.PersistentFlags().Lookup("heartbeat_interval")); err != nil { + return err + } + // File transfer cmd.PersistentFlags().Bool("file_transfer_enabled", false, "enable file transfer feature") @@ -61,6 +68,8 @@ func (s *WebSocket) Set() { s.ControlProtection = viper.GetBool("control_protection") + s.HeartbeatInterval = viper.GetInt("heartbeat_interval") + s.FileTransferEnabled = viper.GetBool("file_transfer_enabled") s.FileTransferPath = viper.GetString("file_transfer_path") s.FileTransferPath = filepath.Clean(s.FileTransferPath) diff --git a/server/internal/types/event/events.go b/server/internal/types/event/events.go index 8032ba90..3cc0b3ae 100644 --- a/server/internal/types/event/events.go +++ b/server/internal/types/event/events.go @@ -6,6 +6,10 @@ const ( SYSTEM_ERROR = "system/error" ) +const ( + CLIENT_HEARTBEAT = "client/heartbeat" +) + const ( SIGNAL_OFFER = "signal/offer" SIGNAL_ANSWER = "signal/answer" diff --git a/server/internal/types/message/messages.go b/server/internal/types/message/messages.go index 89552b71..5dc79764 100644 --- a/server/internal/types/message/messages.go +++ b/server/internal/types/message/messages.go @@ -11,10 +11,11 @@ type Message struct { } type SystemInit struct { - Event string `json:"event"` - ImplicitHosting bool `json:"implicit_hosting"` - Locks map[string]string `json:"locks"` - FileTransfer bool `json:"file_transfer"` + Event string `json:"event"` + ImplicitHosting bool `json:"implicit_hosting"` + Locks map[string]string `json:"locks"` + FileTransfer bool `json:"file_transfer"` + HeartbeatInterval int `json:"heartbeat_interval"` } type SystemMessage struct { diff --git a/server/internal/websocket/handler/handler.go b/server/internal/websocket/handler/handler.go index 628771ca..7da03867 100644 --- a/server/internal/websocket/handler/handler.go +++ b/server/internal/websocket/handler/handler.go @@ -74,6 +74,11 @@ func (h *MessageHandler) Message(id string, raw []byte) error { } switch header.Event { + // Client Events + case event.CLIENT_HEARTBEAT: + // do nothing + return nil + // Signal Events case event.SIGNAL_OFFER: payload := &message.SignalOffer{} diff --git a/server/internal/websocket/handler/session.go b/server/internal/websocket/handler/session.go index af53d252..60d4e00f 100644 --- a/server/internal/websocket/handler/session.go +++ b/server/internal/websocket/handler/session.go @@ -6,7 +6,7 @@ import ( "m1k1o/neko/internal/types/message" ) -func (h *MessageHandler) SessionCreated(id string, session types.Session) error { +func (h *MessageHandler) SessionCreated(id string, heartbeatInterval int, session types.Session) error { // send sdp and id over to client if err := h.signalProvide(id, session); err != nil { return err @@ -14,10 +14,11 @@ func (h *MessageHandler) SessionCreated(id string, session types.Session) error // send initialization information if err := session.Send(message.SystemInit{ - Event: event.SYSTEM_INIT, - ImplicitHosting: h.webrtc.ImplicitControl(), - Locks: h.state.AllLocked(), - FileTransfer: h.state.FileTransferEnabled(), + Event: event.SYSTEM_INIT, + ImplicitHosting: h.webrtc.ImplicitControl(), + Locks: h.state.AllLocked(), + FileTransfer: h.state.FileTransferEnabled(), + HeartbeatInterval: heartbeatInterval, }); err != nil { h.logger.Warn().Str("id", id).Err(err).Msgf("sending event %s has failed", event.SYSTEM_INIT) return err diff --git a/server/internal/websocket/websocket.go b/server/internal/websocket/websocket.go index e22ab0de..573c2e98 100644 --- a/server/internal/websocket/websocket.go +++ b/server/internal/websocket/websocket.go @@ -111,7 +111,7 @@ func (ws *WebSocketHandler) Start() { switch e.Type { case types.SESSION_CREATED: - if err := ws.handler.SessionCreated(e.Id, e.Session); err != nil { + if err := ws.handler.SessionCreated(e.Id, ws.conf.HeartbeatInterval, e.Session); err != nil { ws.logger.Warn().Str("id", e.Id).Err(err).Msg("session created with and error") } else { ws.logger.Debug().Str("id", e.Id).Msg("session created") From e26e595af0c66c8394b5d3c98fa0f723c5759636 Mon Sep 17 00:00:00 2001 From: SomnusVeritas <133667014+SomnusVeritas@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:22:28 +0100 Subject: [PATCH 3/4] Update examples.md (#464) --- docs/getting-started/examples.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/getting-started/examples.md b/docs/getting-started/examples.md index f15ee60c..6f1d6305 100644 --- a/docs/getting-started/examples.md +++ b/docs/getting-started/examples.md @@ -12,6 +12,8 @@ services: ports: - "8080:8080" - "52000-52100:52000-52100/udp" + volumes: + - :/home/neko/.mozilla/firefox # persist firexfox settings environment: NEKO_SCREEN: '1920x1080@30' NEKO_PASSWORD: neko From 7e8aecd3683ae006b90a52ecd403d6e9fa2acfb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Mon, 10 Feb 2025 16:12:36 +0100 Subject: [PATCH 4/4] firefox switches to .tar.xz https://blog.nightly.mozilla.org/2024/11/28/announcing-faster-lighter-firefox-downloads-for-linux-with-tar-xz-packaging/ --- .docker/firefox/Dockerfile | 10 +++++----- .docker/firefox/Dockerfile.nvidia | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.docker/firefox/Dockerfile b/.docker/firefox/Dockerfile index 7ddc798c..87332bf7 100644 --- a/.docker/firefox/Dockerfile +++ b/.docker/firefox/Dockerfile @@ -7,13 +7,13 @@ ARG SRC_URL="https://download.mozilla.org/?product=firefox-latest&os=linux64&lan # install firefox RUN set -eux; apt-get update; \ apt-get install -y --no-install-recommends openbox \ - xz-utils bzip2 libgtk-3-0 libdbus-glib-1-2; \ + xz-utils libgtk-3-0 libdbus-glib-1-2; \ # # fetch latest release - wget -O /tmp/firefox-setup.tar.bz2 "${SRC_URL}"; \ + wget -O /tmp/firefox-setup.tar.xz "${SRC_URL}"; \ mkdir /usr/lib/firefox; \ - tar -xjf /tmp/firefox-setup.tar.bz2 -C /usr/lib; \ - rm -f /tmp/firefox-setup.tar.bz2; \ + tar -xvf /tmp/firefox-setup.tar.xz -C /usr/lib; \ + rm -f /tmp/firefox-setup.tar.xz; \ ln -s /usr/lib/firefox/firefox /usr/bin/firefox; \ # # create a profile directory @@ -21,7 +21,7 @@ RUN set -eux; apt-get update; \ chown -R neko:neko /home/neko/.mozilla/firefox/profile.default; \ # # clean up - apt-get --purge autoremove -y xz-utils bzip2; \ + apt-get --purge autoremove -y xz-utils; \ apt-get clean -y; \ rm -rf /var/lib/apt/lists/* /var/cache/apt/* diff --git a/.docker/firefox/Dockerfile.nvidia b/.docker/firefox/Dockerfile.nvidia index 0bdc70b7..a43c5279 100644 --- a/.docker/firefox/Dockerfile.nvidia +++ b/.docker/firefox/Dockerfile.nvidia @@ -7,13 +7,13 @@ ARG SRC_URL="https://download.mozilla.org/?product=firefox-latest&os=linux64&lan # install firefox RUN set -eux; apt-get update; \ apt-get install -y --no-install-recommends openbox \ - xz-utils bzip2 libgtk-3-0 libdbus-glib-1-2; \ + xz-utils libgtk-3-0 libdbus-glib-1-2; \ # # fetch latest release - wget -O /tmp/firefox-setup.tar.bz2 "${SRC_URL}"; \ + wget -O /tmp/firefox-setup.tar.xz "${SRC_URL}"; \ mkdir /usr/lib/firefox; \ - tar -xjf /tmp/firefox-setup.tar.bz2 -C /usr/lib; \ - rm -f /tmp/firefox-setup.tar.bz2; \ + tar -xvf /tmp/firefox-setup.tar.xz -C /usr/lib; \ + rm -f /tmp/firefox-setup.tar.xz; \ ln -s /usr/lib/firefox/firefox /usr/bin/firefox; \ # # create a profile directory @@ -21,7 +21,7 @@ RUN set -eux; apt-get update; \ chown -R neko:neko /home/neko/.mozilla/firefox/profile.default; \ # # clean up - apt-get --purge autoremove -y xz-utils bzip2; \ + apt-get --purge autoremove -y xz-utils; \ apt-get clean -y; \ rm -rf /var/lib/apt/lists/* /var/cache/apt/*