Skip to content

fix(core): Comprehensive fixes and performance optimizations#254

Draft
ehfd wants to merge 3 commits into
mainfrom
comprehensive-fixes
Draft

fix(core): Comprehensive fixes and performance optimizations#254
ehfd wants to merge 3 commits into
mainfrom
comprehensive-fixes

Conversation

@ehfd

@ehfd ehfd commented Jun 13, 2026

Copy link
Copy Markdown
Member

Must be tested in tandem to linuxserver/pixelflux#18 and
linuxserver/pcmflux#5. Interface and API/ABI are backward-incompatible.

Fixes #273
Fixes #271
Fixes #270
Fixes #269
Fixes #268
Fixes #267
Fixes #266
Fixes #265
Fixes #264
Fixes #261
Fixes #259
Fixes #258
Fixes #257
Fixes #245
Fixes #241
Fixes #234
Fixes #222
Fixes #220
Fixes #214
Fixes #200
Fixes #169
Fixes #157
Fixes #153
Fixes #145
Fixes #85

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces various stability, performance, and security improvements across the Selkies codebase. Key changes include offloading blocking PulseAudio and GPU monitoring calls to executors, implementing robust bounds and validation on client-supplied parameters (such as display dimensions and scroll magnitudes) to prevent resource exhaustion, and introducing Base64 encoding for file paths to safely handle special characters. Additionally, it resolves potential memory leaks by clearing timers on reconnect, handles out-of-order JPEG stripe decodes, and ensures player slot uniqueness. The review feedback highlights several opportunities to further improve robustness, such as using a FIFO queue to prevent race conditions in asynchronous frame ID tagging, adding defensive length checks on message tokens to avoid IndexError crashes, and wrapping integer conversions in try-except blocks to handle malformed client inputs gracefully.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread addons/selkies-web-core/selkies-ws-core.js Outdated
Comment thread addons/selkies-web-core/selkies-ws-core.js Outdated
Comment thread src/selkies/input_handler.py
Comment thread src/selkies/input_handler.py
Comment thread src/selkies/webrtc_mode.py Outdated
@ehfd ehfd changed the title fix(core): Performance optimizations fix(core): Comprehensive fixes and performance optimizations Jun 13, 2026
@ehfd ehfd force-pushed the comprehensive-fixes branch 2 times, most recently from 6d9238d to c3f3a8f Compare June 14, 2026 15:09
@ehfd

ehfd commented Jun 14, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several performance optimizations, security enhancements, and robustness fixes across the C interposer, Python backend, and frontend. Key updates include zero-copy video rendering using track generators, stuck-key recovery via client heartbeats, and safer parsing of SDP/RTP packets. Review feedback points out a critical issue in joystick_interposer.c where copying the interposer struct to a local stack variable causes state modifications in ioctl handlers to be lost. Additionally, a potential race condition in selkies.py was identified where self.pcmflux_capture_loop could be cleared mid-execution, which can be resolved by snapshotting the loop reference.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread addons/js-interposer/joystick_interposer.c Outdated
Comment thread src/selkies/selkies.py Outdated
@ehfd ehfd force-pushed the comprehensive-fixes branch from c3f3a8f to fcd4473 Compare June 15, 2026 03:57
@Pola-fanous19

Copy link
Copy Markdown

While monitoring Sentry on the stable build, I caught two unhandled exceptions that might be worth porting into this rewrite:

AttributeError: 'NoneType' object has no attribute 'type' in the GStreamer bus callback when message is None during stream resets.
InvalidStateError: invalid state in signalling_web.py's stop(), when self.stop_server.set_result(True) is called on an already-resolved/cancelled future during shutdown.

I looked through the diff for #254 and didn't see an equivalent guard in the new files (e.g. a not self.stop_server.done() check before set_result) — apologies if I missed it since it's a large rewrite, but flagging in case it's still relevant.

@ehfd ehfd force-pushed the comprehensive-fixes branch from fcd4473 to dde1530 Compare June 20, 2026 08:58
Comment thread addons/selkies-web-core/selkies-core.js Fixed
@ehfd ehfd force-pushed the comprehensive-fixes branch 8 times, most recently from 903fa0a to 058b61f Compare June 22, 2026 15:39
@ehfd ehfd force-pushed the comprehensive-fixes branch from 058b61f to cd81c52 Compare July 2, 2026 12:27
Copilot AI review requested due to automatic review settings July 2, 2026 12:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR is a broad hardening/performance pass across Selkies’ WebRTC stack (SDP/RTP/DTLS/SCTP), signaling lifecycle, input/clipboard paths, and the web client/dashboard, with additional security tightening (notably command_enabled defaulting to False and stricter control-plane auth routing).

Changes:

  • Harden SDP/signaling/RTP parsing and connection lifecycle handling to tolerate malformed inputs without taking down shared connections.
  • Add Opus RED (RFC 2198) support plus codec negotiation/filtering updates.
  • Improve operational behavior: bounded stats CSV growth + deterministic draining, more resilient clipboard/keyboard handling, and multiple client UX/perf fixes.

Reviewed changes

Copilot reviewed 31 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/selkies/webrtc/sdp.py Makes SDP parsing more defensive (ValueError/guards) and more tolerant of malformed attributes.
src/selkies/webrtc/rtp.py Adds length checks in RTP header extension parsing and validates REMB buffer length.
src/selkies/webrtc/rtcsctptransport.py Increases SCTP max message size capability to support larger DataChannel payloads.
src/selkies/webrtc/rtcpeerconnection.py Updates codec filtering logic to account for Opus RED wrapping semantics.
src/selkies/webrtc/rtcdtlstransport.py Treats struct.error from packet parsing as non-fatal (drop + debug log).
src/selkies/webrtc/codecs/red.py Introduces an Opus RED encoder implementation (RFC 2198 framing).
src/selkies/webrtc/codecs/init.py Registers RED codec, adds encoder wiring, and helper predicates for RED detection.
src/selkies/webrtc_utils.py Reworks WebRTC stats CSV writing (bounded growth, stable headers, dedicated executor + deterministic drain).
src/selkies/webrtc_signaling.py Prevents malformed/unrecognized signaling messages from tearing down shared connections.
src/selkies/webrtc_mode.py Adjusts component initialization, cursor resend behavior, settings sanitization/clamping, and async metrics CSV init/teardown.
src/selkies/stream_server.py Tightens auth middleware routing (exact path match, master token gating) and guards cleanup on extraction failure.
src/selkies/signaling_server.py Makes peer registration/eviction more resilient and reduces lock-holding across slow socket I/O.
src/selkies/settings.py Tightens defaults/bounds (min/max), adds audio redundancy settings, and makes command_enabled opt-in by default.
src/selkies/rtc.py Adds SDP bandwidth munging improvements, zero-copy packet wrapping, and serializes DataChannel message dispatch for ordering.
src/selkies/media_pipeline.py Makes pixelflux/pcmflux imports optional, improves startup/cleanup behavior, and adds pipeline-start callback hooks.
src/selkies/input_handler.py Improves input robustness (stuck-key recovery, key repeat, clipboard transfer IDs/kinds, queue bounding, base64 path handling).
src/selkies/display_utils.py Validates resolution input before cvt/gtf invocation for clearer failures.
src/README.md Updates architecture description to match pixelflux/pcmflux-based media capture/encoding.
README.md Adds a brief client capability highlight summary.
pyproject.toml Updates package metadata (Python version floor and classifiers) and description.
docs/usage.md Documents clipboard behavior and browser support expectations.
docs/faq.md Updates clipboard guidance to reflect new fallback behavior (removes older Firefox workaround requirement).
addons/selkies-web-core/selkies-wr-core.js Improves clipboard parity, logging caps, file upload path encoding, timer cleanup, and settings persistence fixes.
addons/selkies-web-core/selkies-core.js Adds a one-time localStorage key migration for the corrected prefix sanitizer.
addons/selkies-web-core/README.md Documents new rendering paths, clipboard behavior, and related client/server features.
addons/selkies-web-core/lib/webrtc.js Renames client class and hardens message handling + adds stats fields and better error reporting.
addons/selkies-web-core/lib/signaling.js Renames signaling class and updates documentation pointers.
addons/selkies-web-core/lib/input.js Adds held-key heartbeat, improves modifier healing, and refines wheel/scroll behavior to better distinguish wheels vs trackpads.
addons/selkies-dashboard/src/components/Sidebar.jsx Fixes audio bitrate type coercion and adds master-token prompting for /switch when needed.
addons/js-interposer/joystick_interposer.c Reduces lock contention, improves short-read handling, expands libc interposition coverage, and fixes ioctl/property behaviors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/selkies/signaling_server.py
Comment thread src/selkies/media_pipeline.py Outdated
Comment thread src/selkies/media_pipeline.py Outdated
@ehfd ehfd force-pushed the comprehensive-fixes branch from cd81c52 to d090807 Compare July 2, 2026 14:26
@ehfd

ehfd commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several improvements across the platform, including support for older glibc runtimes in the joystick interposer, a one-time localStorage migration, Safari/Firefox clipboard parity, and offscreen worker video rendering. It also vendors the python-xlib library. The code review identified several critical issues: a potential buffer overflow in the joystick interposer when the requested read size is smaller than the stashed length, audio corruption in shared mode due to incorrect header assumptions in extractPrimaryOpusBuffer, a potential TypeError in the sidebar's audio bitrate handling, and a crash in unix_connect.py when parsing IPv6 peer addresses.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread addons/js-interposer/joystick_interposer.c
Comment thread addons/selkies-web-core/selkies-ws-core.js Outdated
Comment thread addons/selkies-web-core/selkies-ws-core.js Outdated
Comment thread addons/selkies-web-core/selkies-ws-core.js Outdated
Comment thread addons/selkies-dashboard/src/components/Sidebar.jsx Outdated
Comment thread src/selkies/Xlib/support/unix_connect.py Outdated
@ehfd ehfd force-pushed the comprehensive-fixes branch from d090807 to 490f088 Compare July 2, 2026 15:55
@ehfd

ehfd commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant enhancements across the Selkies streaming platform, including C-level interposer improvements for old glibc compatibility, partial-event stashing to prevent stream desynchronization, and faithful Xbox 360 controller emulation. On the web client side, it adds a worker-based video rendering pipeline for Safari and Firefox, stuck-key prevention via heartbeats, improved trackpad/mouse wheel detection, and robust multi-part clipboard synchronization for non-Chromium browsers. It also vendors python-xlib and updates the Python requirement to >=3.9. Feedback on these changes highlights two important issues: a potential buffer overflow vulnerability in the C interposer's read path if the destination buffer is smaller than the event size, and a potential unhandled TypeError in the WebRTC client's metrics loop if it fires after disconnection.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread addons/js-interposer/joystick_interposer.c
Comment thread addons/selkies-web-core/selkies-wr-core.js
@ehfd ehfd force-pushed the comprehensive-fixes branch from 490f088 to 8c0e0ff Compare July 4, 2026 13:34
@rmounce

rmounce commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Updated 2026-07-08: pixelflux no longer needs source-built ffmpeg/x264/libjpeg-turbo/wayland (system ffmpeg 6.0–8.1 is accepted, libjpeg-turbo is vendored statically, wayland is dlopen'd) — the builder stage is now just distro dev packages + rustup. The control plane moved under /api (the nginx rule below routes it), and the SHAs are bumped to the current branch tips, now exercised on Intel/VA-API and NVIDIA/NVENC hardware with Firefox + Chrome clients.

For anyone else wanting to second-eye test this stack on the linuxserver.io images: below is the Dockerfile we've been using, sanitised to build directly on ghcr.io/linuxserver/baseimage-selkies:ubuntunoble. It builds the pixelflux/pcmflux wheels from the PR branches (linuxserver/pixelflux#18, linuxserver/pcmflux#5), the web frontend and the selkies package from this branch, and patches them into the stock image in place, working around the noble-specific gaps we reported earlier (the six runtime dep, the LSIO-required nginx/ fancyindex files, the /api proxy location, and websocket basic auth vs browser clients).

All three branches advance by amend + force-push, so bump the pins together.

Dockerfile
# Example: build and test the comprehensive-fixes stack on top of the
# linuxserver.io Selkies base image, patching the stock image in place:
#
#   - selkies-project/selkies#254   (comprehensive-fixes: selkies python + frontend)
#   - linuxserver/pixelflux#18      (comprehensive-fixes: pure-Rust rewrite)
#   - linuxserver/pcmflux#5         (comprehensive-fixes: pure-Rust, AudioPlayback)
#
# This is a sanitised copy of the recipe we use for second-eye testing #254 —
# our real builds start from a downstream image based on
# baseimage-selkies:ubuntunoble, which is what this stack has actually been
# exercised on (Intel/VA-API and NVIDIA/NVENC, Firefox + Chrome clients).
#
# Since the first version of this example, pixelflux stopped pinning ffmpeg
# (any system 6.0-8.1 works, only avcodec/avfilter needed), statically
# vendors libjpeg-turbo, links noble's libx264-dev, and dlopens wayland — so
# the x264/libjpeg-turbo/ffmpeg/wayland source builds are all gone in favour
# of noble's distro packages, and the builder stage is just deps + rustup.
#
# All three source branches are moving targets that advance by amend +
# force-push; the SHAs below pin what we tested. Bump them together — the
# selkies python side needs the matching native-module features
# (deferred_free / OwnedFrame / request_idr_frame / AudioPlayback).
ARG SELKIES_REPO=https://github.com/selkies-project/selkies
ARG SELKIES_HASH=da1b55e7148a074816286eb6d54ee1e500fcfb53
ARG PIXELFLUX_HASH=ab248a32d63bec09786ce5f7406fc4182875485a
ARG PCMFLUX_HASH=0cbadcb334dbc190ba4525da091401276671beeb
ARG BASE_IMAGE=ghcr.io/linuxserver/baseimage-selkies:ubuntunoble

########################################################################
# Frontend: mirrors the base image's own packaging flow.
########################################################################
FROM node:20-alpine AS frontend
RUN apk add --no-cache git
ARG SELKIES_REPO
ARG SELKIES_HASH
RUN mkdir /src && cd /src && \
        git init && git remote add origin "${SELKIES_REPO}.git" && \
        git fetch --depth 1 origin "${SELKIES_HASH}" && git checkout FETCH_HEAD

# The postbuild step (gendb.js) fetches the SDL game-controller DB from
# raw.githubusercontent.com and swallows fetch failures (logs + exit 0),
# silently skipping dist/jsdb — which the dashboard stage's cp then trips
# over. Retry it once and fail loudly here instead.
RUN cd /src/addons/selkies-web-core && \
        npm install && npm run build && \
        { [ -d dist/jsdb ] || node gendb.js; } && \
        { [ -d dist/jsdb ] || { echo 'ERROR: dist/jsdb missing - gendb.js could not fetch SDL_GameControllerDB (transient network?). Re-run the build.'; exit 1; }; }
# The final stage keeps the base image's nginx/ fancyindex header/footer
# copies (required by the LSIO runtime: init-nginx seds footer.html and
# default.conf references both), so they are not packaged from source here.
RUN cd /src/addons/selkies-dashboard && \
        cp ../selkies-web-core/dist/selkies-core.js src/ && \
        npm install && npm run build && \
        mkdir -p dist/src && \
        cp ../selkies-web-core/dist/selkies-core.js dist/src/ && \
        cp ../universal-touch-gamepad/universalTouchGamepad.js dist/src/ && \
        cp -r ../selkies-web-core/dist/jsdb dist/

########################################################################
# Native modules: build pixelflux/pcmflux wheels from the PR branches.
#
# Both are pure-Rust PyO3 extensions (no prebuilt wheels for these
# branches). Building FROM the same base image guarantees the wheels match
# /lsiopy's python and the base glibc.
#
# The dep list mirrors pixelflux's [tool.cibuildwheel] before-all:
# ffmpeg-sys-next accepts system ffmpeg 6.0-8.1 (noble: 6.1) with only
# avcodec/avfilter needed; x264-sys links noble's libx264-dev; turbojpeg-sys
# statically builds its vendored libjpeg-turbo (hence cmake + nasm); wayland
# is dlopen'd at runtime, so headers suffice.
########################################################################
FROM ${BASE_IMAGE} AS native-builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential clang libclang-dev curl git nasm cmake pkg-config \
        libpixman-1-dev libx11-dev libxext-dev libxfixes-dev \
        libva-dev libdrm-dev libinput-dev libxkbcommon-dev libgbm-dev \
        libwayland-dev libudev-dev \
        libavcodec-dev libavfilter-dev libx264-dev \
        libpulse-dev libopus-dev

# noble's rustc is too old for the PyO3 0.27 crate graph. The LSIO base image
# sets HOME=/config, so don't let rustup pick $HOME/.cargo — pin both trees
# somewhere fixed and PATH that instead.
ENV RUSTUP_HOME=/opt/rustup \
    CARGO_HOME=/opt/cargo \
    PATH=/opt/cargo/bin:$PATH
# Download-then-run, NOT `curl | sh`: a failed download would feed sh an empty
# script, which exits 0 and silently installs nothing.
RUN curl --proto '=https' --tlsv1.2 -sSf -o /tmp/rustup-init.sh https://sh.rustup.rs && \
        sh /tmp/rustup-init.sh -y --profile minimal --no-modify-path && \
        rm /tmp/rustup-init.sh
RUN cargo --version && rustc --version

# The PR heads live on ehfd's forks (linuxserver/pixelflux#18,
# linuxserver/pcmflux#5); init+fetch pins an arbitrary SHA on any git.
ARG PIXELFLUX_HASH
ARG PCMFLUX_HASH
RUN mkdir /tmp/pixelflux && cd /tmp/pixelflux && \
        git init && git remote add origin https://github.com/ehfd/pixelflux.git && \
        git fetch --depth 1 origin "${PIXELFLUX_HASH}" && git checkout FETCH_HEAD && \
        pip wheel --no-deps -w /wheels .
RUN mkdir /tmp/pcmflux && cd /tmp/pcmflux && \
        git init && git remote add origin https://github.com/ehfd/pcmflux.git && \
        git fetch --depth 1 origin "${PCMFLUX_HASH}" && git checkout FETCH_HEAD && \
        pip wheel --no-deps -w /wheels .

# The joystick interposer and fake-udev shim were both reworked on
# comprehensive-fixes; the base image's copies predate that, so rebuild them
# from the same selkies checkout the python side comes from.
ARG SELKIES_REPO
ARG SELKIES_HASH
RUN mkdir /tmp/selkies && cd /tmp/selkies && \
        git init && git remote add origin "${SELKIES_REPO}.git" && \
        git fetch --depth 1 origin "${SELKIES_HASH}" && git checkout FETCH_HEAD && \
        cd addons/js-interposer && \
        gcc -shared -fPIC -o selkies_joystick_interposer.so joystick_interposer.c -ldl -pthread && \
        cd ../fake-udev && \
        make

########################################################################
# Final: patch the base image in place.
########################################################################
FROM ${BASE_IMAGE}
ARG SELKIES_REPO
ARG SELKIES_HASH
ENV DEBIAN_FRONTEND=noninteractive

# Runtime halves of the distro libs the wheels link against (noble ffmpeg 6.1
# sonames + x264; libjpeg-turbo is statically vendored inside the pixelflux
# wheel). NVIDIA driver libs (libcuda, libnvidia-encode) come from the
# container runtime as usual — the Rust NVENC bindings dlopen them.
RUN apt-get update && apt-get install -y --no-install-recommends \
        libavcodec60 libavfilter9 libx264-164 libopus0 && \
    rm -rf /var/lib/apt/lists/*

COPY --from=native-builder /wheels /tmp/wheels
RUN pip install --no-deps --force-reinstall /tmp/wheels/*.whl && rm -rf /tmp/wheels

# selkies python package. 'six' is a new runtime dep on comprehensive-fixes
# (its vendored python-Xlib needs it), so install it explicitly. (pynput /
# GPUtil / pasimple / python-xlib were dropped upstream; the stale copies in
# the image are harmless.)
RUN pip install --no-deps --force-reinstall \
        "${SELKIES_REPO}/archive/${SELKIES_HASH}.zip" && \
        pip install six && \
        rm -rf /tmp/* ~/.cache

# Replace the whole dashboard build (content-hashed assets must stay
# consistent), but keep the base image's nginx/ fancyindex header/footer,
# which the LSIO runtime requires (init-nginx seds footer.html; default.conf
# references both).
RUN cp -a /usr/share/selkies/selkies-dashboard/nginx /tmp/nginx-keep && \
        rm -rf /usr/share/selkies/selkies-dashboard
COPY --from=frontend /src/addons/selkies-dashboard/dist/ \
        /usr/share/selkies/selkies-dashboard/
RUN mkdir -p /usr/share/selkies/selkies-dashboard/nginx && \
        cp -a /tmp/nginx-keep/. /usr/share/selkies/selkies-dashboard/nginx/ && \
        rm -rf /tmp/nginx-keep

# The LSIO nginx only proxies SUBFOLDERwebsocket* to the backend; the
# comprehensive-fixes control plane now lives under SUBFOLDERapi/ (status,
# health, tokens, switch — one rule routes them all, present and future).
# The SUBFOLDER and CWS placeholders are substituted by the image's init
# scripts at container start.
#
# NOTE: anything in the image that talks to the old control endpoints must
# follow this move too — e.g. a token-provisioning helper POSTing to
# /tokens must now POST to {prefix}/api/tokens on the websocket port, and
# until that first successful POST the server's config gate rejects all
# websocket connections.
RUN sed -i "s|location SUBFOLDERwebsocket {|\
location SUBFOLDERapi {\n\
    proxy_pass              http://127.0.0.1:CWS;\n\
    proxy_set_header        Host \$host;\n\
    proxy_set_header        X-Real-IP \$remote_addr;\n\
    proxy_set_header        X-Forwarded-For \$proxy_add_x_forwarded_for;\n\
    proxy_set_header        X-Forwarded-Proto \$scheme;\n\
  }\n\n\
  location SUBFOLDERwebsocket {|g" \
        /defaults/default.conf

# Interposer + fake-udev rebuilt against the comprehensive-fixes protocol.
COPY --from=native-builder /tmp/selkies/addons/js-interposer/selkies_joystick_interposer.so \
        /usr/lib/selkies_joystick_interposer.so
COPY --from=native-builder /tmp/selkies/addons/fake-udev/libudev.so.1.0.0-fake \
        /opt/lib/libudev.so.1.0.0-fake

# comprehensive-fixes' unified server fronts the websocket with basic auth by
# default (ubuntu/mypasswd unless SELKIES_BASIC_AUTH_* is set). Browsers
# cannot attach an Authorization header to a WebSocket upgrade; the server
# now skips basic auth on websocket paths once a master token is provisioned,
# but a deployment without token provisioning still locks browser clients
# out unless this is disabled. (The LSIO images never set the enable env, and
# nginx-level auth via CUSTOM_USER/PASSWORD is available instead.)
ENV SELKIES_ENABLE_BASIC_AUTH=false

🤖 Generated with Claude Code

@rmounce

rmounce commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Two more findings from testing on the lsio-based image, both about failure opacity rather than the happy path:

1. WebSocket upgrades rejected by basic auth are silent on both ends. In _auth_middleware, a request with no Authorization header gets a 401 with no server-side log (unlike the disallowed-Origin and invalid-credentials branches, which both log warnings). For a WebSocket upgrade this is doubly invisible: browsers can't attach an Authorization header to a WS handshake, and the page only sees a generic connection failure (Firefox reports NS_ERROR_WEBSOCKET_CONNECTION_REFUSED; the status code isn't exposed to JS). Since enable_basic_auth defaults to true (ubuntu/mypasswd), a deployment that doesn't explicitly set SELKIES_ENABLE_BASIC_AUTH=false has a data websocket no browser can reach, and neither side logs why — this cost us a debugging session. Suggestions: log rejected WS upgrades at warning level like the Origin check does, and consider whether the Basic gate should apply to websocket paths at all when token auth is in play (the token is already validated in data_ws_handler).

2. When pixelflux fails to import, capture start dies with an unrelated-looking TypeError instead of the clean degrade. The import fallback sets ScreenCapture = CaptureSettings = None and logs a good warning at startup — but in _start_capture_for_display_impl, _get_capture_settings() (which instantiates CaptureSettings()) runs before the X11_CAPTURE_AVAILABLE guard, so "take control" crashes with 'NoneType' object is not callable, long after the informative startup warning has scrolled away. Hoisting the X11_CAPTURE_AVAILABLE check to the top of _start_capture_for_display_impl would surface the real cause at the point of failure. (This is how we experienced the libwayland issue reported on linuxserver/pixelflux#18 — the crash gave no hint the import had failed.)

🤖 Generated with Claude Code

@ehfd ehfd force-pushed the comprehensive-fixes branch 2 times, most recently from 155eb0b to de77558 Compare July 7, 2026 10:25
@ehfd

ehfd commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Fixes incorporated across all three PRs.

Current commits:

Selkies: 4de4c8a57fe21b187b3f0a383dc71abf5f4da4f8

pixelflux: a08bf5c8c660a8f2d43be750a1d09077d4a0ac51

pcmflux: 3dadfdfa62e5137d4f5ced2f31c95fa52078f1a0

I am building a temporary image (https://gitlab.nrp-nautilus.io/ehf/selkies-lsio/-/blob/main/Dockerfile) which is available on gitlab-registry.nrp-nautilus.io/ehf/selkies-lsio:latest.

Run google-chrome or firefox from the terminal.

@ehfd ehfd force-pushed the comprehensive-fixes branch from de77558 to 3823c8b Compare July 7, 2026 11:12
Co-authored-by: Ryan Mounce <ryan@mounce.com.au>
@ehfd ehfd force-pushed the comprehensive-fixes branch from 3823c8b to 2ee26a6 Compare July 7, 2026 14:41
@ehfd ehfd force-pushed the comprehensive-fixes branch 2 times, most recently from 9fcf897 to 14802af Compare July 7, 2026 16:34
@ehfd ehfd force-pushed the comprehensive-fixes branch 4 times, most recently from 32a3087 to 6f4e5c7 Compare July 8, 2026 09:13
@ehfd ehfd force-pushed the comprehensive-fixes branch 9 times, most recently from 89a8252 to 3bab531 Compare July 9, 2026 04:15
Co-authored-by: vishalkadam47 <vishalkadam472@gmail.com>
@ehfd ehfd force-pushed the comprehensive-fixes branch from 3bab531 to 4de4c8a Compare July 9, 2026 07:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

5 participants