Owner sign-off: replace root LICENSE with Apache License 2.0, add a root
NOTICE file, and swap the GPL-2.0 boilerplate header in every first-party
core/ and obs-adapter/ source file for a short Apache-2.0 notice.
This resolves review finding C2 (GPLv2 top-level LICENSE vs. the vendored
Apache-2.0 LiveKit SDK is a license-compatibility violation): the whole
repo is now Apache-2.0, matching LiveKit, so there's no GPL/Apache clash
left. Updated the README Status gate and the CI workflow comment to reflect
that C2 is resolved, while leaving the C1 WebRTC/OpenH264 patent/royalty
gate untouched -- that question is still open and still blocks release.
third_party/ stays under its own upstream licenses; only this project's own
code changed hands. All 6 CTest suites still pass after the header swap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
Implements the two read-key-scoped calls in
apps/server/src/obs/plugin.routes.ts: GET /api/obs/:slug/slots and
POST /api/obs/:slug/token.
Three pieces, all in core/ with no OBS dependency:
- stplugin::json -- a small, strict JSON reader. Hand-rolled rather than
vendoring nlohmann because the only JSON this plugin ever sees is two
fixed-shape responses from its own server, and the parser has to build on
three platforms with no package-manager step in CI. It never throws,
bounds its recursion (kMaxDepth=32) so a hostile response cannot overflow
the stack inside OBS, rejects trailing garbage, and returns the caller's
fallback for wrong-typed access instead of aborting.
- stplugin::HttpClient -- a two-method injectable interface, with libcurl
behind it on Linux/macOS and WinHTTP on Windows. WinHTTP rather than curl
on Windows because it ships with the OS and does TLS through SChannel: the
self-hosted winvm-builder runner has no package manager, and per the
scaffold README does not even have cmake preinstalled. Both backends cap
the response body at 4 MiB, keep TLS verification on (the read key is a
credential), and honour a whole-request timeout.
- stplugin::ApiClient -- maps the responses onto an ApiStatus enum that
distinguishes NotFound (404), Unavailable (503), NetworkError,
MalformedResponse and InvalidConfig. It deliberately does not claim to
know whether a 404 was a wrong key or an unknown slug, because the server
deliberately does not say. Server URLs are normalised the way an operator
actually pastes them, defaulting to https so the read key is never sent in
the clear by accident, and redactedUrl() exists so a URL can be logged
without the key.
Tests (279 checks across two new suites) run at two levels: a fake
HttpClient covering every response and error branch, and a real loopback
HTTP server on 127.0.0.1 driving the actual platform backend -- so libcurl
on Linux/macOS and WinHTTP on Windows are each exercised in CI rather than
assumed. The loopback cases deliberately include the ones that must not hang
OBS: a truncated JSON body, a connection accepted and closed without a
reply, non-HTTP garbage, a dead port, and a stalled server that has to be
cut off by the client's own timeout.
Verified locally on Ubuntu 24.04:
ctest --test-dir build --output-on-failure -> 4/4 passed
test_json: 158 checks passed
test_api_client: 121 checks passed
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE