Commit Graph
105 Commits
Author SHA1 Message Date
Paul WellsandClaude Opus 5 36966911ed agent endpoints: serve webtransport from the node's server set
StartWebTransport built the node's only HTTP/3 listener from inside AgentService:
it minted the TLS config, bound the UDP socket, assembled an h3 mux and returned
a stop closure LivekitServer held in agentWTStop. Every other listener is
constructed in NewLivekitServer and delegates to a service, and agents are the
first consumer of HTTP/3 rather than the last.

webtransport.go now carries the transport with no agent references:
WebTransportTLS, NewWebTransportServer, NewWebTransportHandler,
ListenWebTransport, and WithWebTransportServer/GetWebTransportServer, which put
the serving server in the request context so a route that upgrades is a
conventional http.Handler instead of a closure over the server. The listener is
built in NewLivekitServer beside the prometheus and debug servers, bound in Start
with the other listeners, and stopped once doneChan unblocks, so no stop closure
is held on LivekitServer. /agent is a route on its mux, as it is on the API mux.

UpgradeWebTransport unwraps the ResponseWriter before upgrading. webtransport-go
type-asserts it to http3.Settingser and http3.HTTPStreamer without checking and
negroni wraps the writer on every chain, so the h3 listener could not carry a
middleware chain at all. It now runs the same recovery, api-key auth and path
normalization as the TCP chain.

AgentService splits into AgentWSService and AgentWTService over the shared
AgentHandler, and the endpoint front becomes AgentEndpointService. wire builds
all four and threads one endpoint.Registry into the handler and the front.
NewAgentHandler takes the config and builds its own ServerInfo, so endpointsConfig
and singleAPIKey are set at construction and the psrpc server is registered
against a fully formed handler; it previously bound one whose embedded
*AgentHandler was still nil.

The listener's port and certificate move to a top-level webtransport config
block. The listener no longer reads agents.endpoints.disabled, which continues to
refuse endpoint registrations. ListenWebTransport binds one socket per bind
address, where the h3 listener ignored bind_addresses that every TCP listener
honoured.

NewWorkerRegisterer takes a variadic WorkerRegisterHandler, each handler reading
the request and filling its part of the response and the registration, replacing
the single EndpointSettingsFunc threaded through HandleRegister.
EndpointRegisterHandler is the endpoint declaration's turn, and
endpoint.NegotiateSettings holds the protocol negotiation the OSS and cloud
handshakes each carried a copy of.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 23:31:24 -07:00
Paul WellsandClaude Opus 5 d9a643243a agent endpoints: build the front and registration from params
Front is an http.Handler, so fallback, identity and singleKeyFallback were read
on every request with no synchronization while WithFallback, WithIdentity and
WithSingleKeyFallback wrote them on the live object. Each returned the same
pointer, so the chain read as though it built a value. Every call site happens
to run before the handler is mounted, so nothing races today, but nothing in
the type prevents it, and WithSingleKeyFallback took no argument and could only
be turned on. NewFront now takes FrontParams and configuration is fixed at
construction.

NewWorkerRegisterer takes its EndpointSettingsFunc directly, and
HandshakeAgentWorker takes one in place of a variadic of raw closures that
existed only to reach the setter it replaced.

Registration gains NewRegistration and RegistrationParams, moving the Draining
callback off an exported mutable field and folding SetSession into
construction. IsDraining absorbs the nil check at both call sites.

Access carried a three-state ladder as two bools, with "granted implies
credentialed" documented but unenforced. It is now an ordered AccessLevel, so
callers compare a rank rather than combining flags and the invariant holds by
construction.

Registry.Register returned an error that was always nil, with a dead branch at
each call site. Both registry maps and the per-registration session are
read-heavy, so they take RWMutex.

CopyBody returned two errors to separate a source failure from a destination
one. It returns one, wrapping a source failure in *SourceError, which is what
the caller discriminates on.

NewWebTransportServer took a callback to break the handler/server init cycle;
the caller assigns wt.H3.Handler after construction instead. StartWebTransport
reads Development off the service rather than taking a bool, and returns a nil
stop function where it starts no listener.

Smaller: slices.Sort for sort.Strings, for range for an unused counter, a nil
slice for regs[:0:0], p2c generic over its slice so the call site passes a
method expression rather than allocating a closure per request, and streamCode
deduplicated into wire.StreamCode so both peers map reset codes in one place.

Comments on the touched declarations drop remote behavior, migration narration
and contrastive framing, keeping the constraints and invariants.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 17:56:52 -07:00
Paul Wells 9ac10fba0e agent endpoints: serve the front on its own middleware chain
The front was mounted on the API mux and served through the API middleware
chain, which is shaped for handlers that buffer a request and write one
response. Four consequences.

negroni.NewRecovery() recovers every panic with no http.ErrAbortHandler
exemption, and NewRecovery sets PrintStack. On an abort it wrote "PANIC: ..."
and a goroutine stack into the already-committed body, then returned normally,
so net/http terminated the chunked stream cleanly. A truncated response
reached the client as complete, with a stack trace appended. Detection was
already correct; delivery was not, and the x-lk- trailers that would otherwise
signal it are stripped before the response leaves. A Content-Length response
still failed safe, since net/http enforces the declared length itself, so the
gap was the chunked and trailer paths.

Endpoints.Disabled documents that it turns the front off, but only
registrations were refused; the mount was unconditional.

The CORS method list omits PUT, which a manifest may declare.

The API body limiter capped request bodies at MaxAPIRequestBodySize, though
the front streams a body through a pooled buffer and never holds one.

NewHTTPHandler now routes the prefix to a chain carrying AgentRecovery, a CORS
list matching the methods a manifest may declare, and the api-key auth
middleware the front resolves a caller's access from. The mount is built only
when endpoints are enabled, so the prefix otherwise falls through and 404s.
RemoveDoubleSlashes moves above the split, so routing and both chains see one
path form.

Taking the front off the mux also stops ServeMux rewriting the paths it is
handed: "//x", "/../" and interior "//" were answered with a redirect rather
than proxied, which a byte-transparent exchange cannot do.

The endpoint stack tests now build the production handler, so they run on the
chain the node serves on.
2026-09-14 13:11:10 -07:00
Théo Monnom 751d85c9bf agent endpoints: WebTransport data plane
Replace the capsule mux / credit / attach-pool machinery with one WebTransport
(QUIC) session per worker: a control stream carries registration and status,
and each HTTP exchange rides its own QUIC stream (native mux, per-stream flow
control, half-close, and reset). Encode the HTTP method into the cross-node
route filter so candidate selection is method-aware. Keep the legacy WebSocket
control transport for backward compatibility.
2026-08-30 18:59:30 -07:00
Théo Monnom 8c7011cb7a agent: HTTP endpoints data plane
Serve worker-declared FastAPI routes at /agents/{deployment}/{path} without
any worker-side listener: workers dial a fixed pool of wires speaking
AgentHttp.Frame, the server opens multiplexed streams carrying one opaque
HTTP/1.1 exchange each (two-level credit flow control, prioritized write
scheduler, attach epoch fencing). The front does starlette-exact manifest
matching with per-endpoint public access, typed 401/404/405, a retry table,
and SSE/WebSocket passthrough; a pluggable fallback hook lets multi-node
deployments resolve misses elsewhere. Includes a conformance client, a
manual sidecar, and the acceptance suite.

The auth middleware now reads access_token from the query string only:
FormValue consumed the bodies of proxied url-encoded POSTs.
2026-08-19 18:25:35 -07:00
Raja SubramanianandClaude Opus 4.8 f72254ba6b Limit API request body size (#4757)
Bound the size of HTTP request bodies on the main API listener so large
messages cannot exhaust memory. Configurable via limit.max_api_request_body_size
(defaults to 10 MiB, 0 disables).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-14 10:36:40 +05:30
Raja Subramanian 2561589868 Fail server start up on partial prom config. (#4749)
* Fail server start up on partial prom config.

* tweaking error message a bit
2026-08-13 13:49:17 +05:30
Trey Hakanson 233a226438 Add ability to run pprof on dedicated HTTP server (#4584)
This allows exposing the pprof/debug endpoints in a production
environment more easily, where it shouldn't be exposed publicly.
2026-06-10 21:23:39 -07:00
cnderrauber 89faaeba82 Apply ttl check only when authenticate allocation creating (#4526)
* Apply ttl check only when authenticate allocation creating

TTL check could reject allocation/persmission refresh in
security enhancement #4505, cause long-live session disconnect
when turn credential is expired.
Only check ttl on allocation creating to prevent abusing leaked
credential but keep long-live session work.
2026-05-15 14:55:05 +08:00
David Zhao 4b3856125c chore: pin GH commits and switch to golangci-lint (#4444)
* chore: pin GH commits

* switch to golangci-lint-action

* fix lint issues
2026-04-11 13:04:22 -07:00
cnderrauber 8ae564065e generate & log egressID for start egress request (#4303)
* generate & log egressID for start egress request

* seprate method

* use ctx value instead of metadata

* comment
2026-02-10 09:34:56 +08:00
Raja Subramanian b8ddd0f98c Taking interface{} -> any modernize bits (#4204) 2025-12-28 05:22:12 +05:30
Raja Subramanian 34a491309f Delete v2 signalling (#3835)
* Delete v2 signalling

* deps

* mage generate

* deelte unused file
2025-08-06 09:08:09 +05:30
Raja Subramanian 5751692a2f deps (#3829) 2025-08-03 04:00:38 +05:30
Raja Subramanian b9a44c3fbf Signalling V2 protocol implementation start (#3794)
* WIP

* name

* refactor validate

* WIP

* WIP

* signal cache initial impl

* HandleConnect in room manager

* generate subscriber offer

* handle ConnectRequest as stand alone

* segmentation, reassembly

* clean up

* rearrange

* lock scope

* support metadata in connect request

* prom

* add SifTrailer to ConnectResponse

* prom for get offer error counter

* RtcInit counter

* Jie feedback

* signal client

* consolidate v1 and v2 into SignalClient

* clean up

* comment

* deps

* mage generate

* fix tests

* pass around roomName and participantIdentity

* mage generate
2025-07-18 00:01:21 +05:30
Raja Subramanian 1b760393bc WHIP support. (#3692)
* WHIP support.

WHIP like signalling with added support for data channels.

* clean up

* Paul feedback

* deps
2025-06-03 08:23:37 -07:00
Denys Smirnov ccbc988824 Pass error details and timeouts. (#3402) 2025-02-06 13:53:44 +02:00
Raja Subramanian bb0ee1139c Drive-by misc changes. (#3399)
While working on a different service, noticed delegation of setting up
routes to the service itself. So, making that change and making some
methods internal only as there is no need to export them outside the
service.
2025-02-04 12:32:05 +05:30
Alan Willard 5b61bbc446 remove code that deletes state from the store for rooms older than 24 hours (#3320) 2025-01-10 10:09:55 +05:30
cnderrauber 54f9f7de51 upgrade to pion/webrtc v4 (#3213) 2024-11-28 16:05:38 +08:00
Raja Subramanian 49b75e94a6 Consolidate operations on LocalNode. (#3140) 2024-10-25 18:57:23 +05:30
David Zhao 50576b503e Handle trailing slashes in URL (#2988)
When a user includes a trailing slash in LIVEKIT_URL, it would produce
double slashes in the path, i.e. `https://myhost.livekit.cloud//twirp/RoomService.ListRooms`

Currently the server will send a 302 MOVED response, causing Twirp requests to fail.

We now remove the double slash in front within the middleware.
2024-09-07 11:30:24 -07:00
David Zhao 91cb4369ef Standardize twirp hooks during server init (#2959) 2024-08-26 00:53:13 -07:00
Benjamin Pracht 64057c3e4d Implement AgentDispatch service (#2919)
This allows listing, adding and deleting agent dispatches on an existing room. Requests go to a new AgentDispatchService, which sends them over RPC to the rtc.Room via the RoomManager. The rtc.Room then does agent job management using RPCs to the agent service.
2024-08-08 22:31:23 +02:00
holzgeist 6523c9c099 Feat add prometheus auth (#2252)
* feat: add support for basic auth on prometheus

* fix: properly name middleware generator

* refactor: move all prometheus configs into common object

* chore: add suggestions from review

add back old config switch and print warning if it is used

* fix: undo accidental change

* fix: rebase/merge issue
2024-06-27 02:13:51 -07:00
dc67f505a5 agent service: new protocol & namespaces (#2545)
* initial worker impl

* fix test

* fix build

* TestAgentNamespaces

* log err

* nit cmt

* TestAgentMultiNode

* Update pkg/agent/worker.go

Co-authored-by: David Zhao <dz@livekit.io>

* retry on worker selection & fix review comments

* Update roommanager.go

* license

* use testutils.WIthTimeout

* abstract namespace/enabled logic into agent.Client, incrementally dispatch

* typos and dates

* lock

* timeout is now optional

* pass in topics instead of fixed

* handler handles connections

* onIdle, numConnections

* fix WithGrants

* update protocol

* check agent client

* broadcast after unlock

* fix data race

* remove ReadChan, fix dispatcher

---------

Co-authored-by: David Zhao <dz@livekit.io>
Co-authored-by: David Colburn <xero73@gmail.com>
2024-04-03 15:25:42 -07:00
David Zhao 3fe124c87f Log cleanup pass (#2285)
* Log cleanup pass

Demoted a bunch of logs to DEBUG, consolidated logs.

* use context logger and fix context var usage

* moved common error types, fixed tests
2023-12-02 15:07:31 -08:00
Sean DuBois 702e562f9f Add SIP Support (#2240) 2023-11-14 14:24:54 -05:00
David Colburn 60374c6402 Agents (#2203)
* agents

* add test

* undo name changes

* remove debug logs

* fixes

* fix data race in test
2023-11-03 11:43:35 -07:00
cnderrauber 9b9298b927 Add batch i/o to improve throughput (#2033)
* Add batch i/o to improve throughput

* remove empty line

* Solve comments

* Change rtcconfig.UDPPort to PortRange

* Fix test
2023-09-06 10:18:20 +08:00
David Zhao debd75fa15 Integrate logger components (#1933)
* Integrate logger components

Dividing into the following components
* pub - publisher
* pub.sfu
* sub - subscriber
* transport
* transport.pion
* transport.cc
* api
* webhook

* update go modules
2023-08-03 13:31:17 -07:00
David Zhao 981fb7cac7 Adding license notices (#1913)
* Adding license notices

* remove from config
2023-07-27 16:43:19 -07:00
Paul Wells 6ad1e1598d move signal server start to server start (#1894)
* move signal server start to server start

* fix test
2023-07-20 19:13:27 -07:00
Juan Navarro 2668073c29 Honor bind address passed as --bind also for RTC ports (#1815)
* Use net.JoinHostPort to build "host:port" strings for `net.Listen`

net.JoinHostPort provides a unified way of building strings of the form
"Host:Port", abstracting the particular syntax requirements of some
methods in the `net` package (namely, that IPv4 addresses can be given
as-is to `net.Listen`, but IPv6 addresses must be given enclosed in
square brackets).

This change makes sense because an address such as `[::1]` is *not* a
valid IPv6 address; the square brackets are just a detail particular to
the Go `net` library. As such, this syntax shouldn't be exposed to the
user, and configuration should just accept valid IPv6 addresses and
convert them as needed for usage within the code.

* Use '--bind' CLI flag to also filter RTC bind address

The local address passed to a command such as

    livekit-server --dev --bind 127.0.0.1

was being used as binding address for the TCP WebSocket port, but was
being ignored for RTC connections.

With `--dev`, the conf.RTC.UDPPort config is set to 7882, which enables
"UDP muxing" mechanism. Without interface or address filtering, Pion
would try to bind to port 7882 on *all* interfaces.

This was failing on a system with IPv6 enabled, when trying to bind to
an IPv6 address of the `docker0` interface. It seems to make sense that
the user-passed bind addresses are also honored for the RTC port
bindings.
2023-06-28 16:52:43 -07:00
David Zhao 956735ae05 Fix node stats updates on Windows (#1748)
Because we aren't able to get CPU count/load info on Windows, they are
stubbed out to return placeholders. This restores compatibility to run
on Windows.
2023-05-29 10:53:08 -07:00
Paul Wells e22de045ba add signal psrpc service (#1485)
* add signal psrpc service

* update protocol dep

* refactor for cloud

* update psrpc

* pr feedback
2023-03-03 15:49:46 -08:00
Benjamin Pracht 17ae1506f5 Chain twirpLogger and twirpRequestStatusHook properly for the Egress server (#1470) 2023-02-25 15:15:50 -07:00
Benjamin Pracht edc39da0b1 Add TwirpRequestStatusReporter twirp server hook to count requests (#1309) 2023-01-18 11:53:20 -08:00
David Colburn a87107a0f3 IOInfo service (#1305)
* IOInfo service

* only start if not nil

* use ctx in updateEgressInfo

* updates

* fix merge
2023-01-16 16:26:03 -08:00
David Zhao 988858a98a Update dependencies to generic versions (#1259) 2022-12-26 22:29:13 -08:00
David Zhao 7a1273151f Update to new logging library, using sampling participant logger (#1219) 2022-12-09 00:09:03 -08:00
David Zhao e5d21cb1d9 CreateRoom API to actually create the room on an RTC node (#1155)
Previously, CreateRoom only created the room in storage, but did not
hydrate it on an RTC node. This has caused strange behaviors such as
emptyTimeout not working correctly (#1109).

Also reduced room reap worker to consistently reap rooms. Fixes #241
2022-11-09 23:35:35 -08:00
David Zhao 4161768530 Log Service API requests (#1091) 2022-10-17 00:16:54 -07:00
Samuel Humeau 00ec859dd1 Add default handler to 404 (#1088) 2022-10-16 10:30:34 -07:00
David Zhao feb47812e7 Allow CORS responses to be cached to allow faster initial connection (#1027) 2022-09-20 23:56:24 -07:00
cnderrauber 0b42a8f2c6 loop variable captured (#945) 2022-08-23 14:27:21 +08:00
Benjamin Pracht c333b7a026 Add support for Ingress service (#868)
Also check for Join permission on ingress API calls
2022-08-04 09:48:53 -07:00
David Colburn 7aa5888338 Keep egress info for 24h (#856)
* Keep egress info for 24h

* updates

* better version comparison

* fix test

* duplicated if
2022-07-28 20:27:59 -05:00
David Zhao a2bf32797b Allow binding HTTP server to specific address (#831)
Improves security when running with placeholder keys. Only allowing
access from loopback by default.
2022-07-13 23:58:33 -07:00
David Colburn fbbcbe77df Remove recording (#811)
* remove recorder service

* update protocol
2022-07-05 18:39:32 -07:00