Skip to content

Server

moqt.Server manages server-side operations for the MoQ protocol. It listens for incoming QUIC connections, dispatches them based on ALPN negotiation, and manages their lifecycle.

The server uses ALPN (Application-Layer Protocol Negotiation) to determine the transport:

  • moq-lite-04 (moqt.NextProtoMOQ) — Native QUIC, dispatched to Server.Handler
  • h3 (moqt.NextProtoH3) — WebTransport via HTTP/3, dispatched to Server.WebTransportServer
Overview
func main() {
    mux := moqt.NewTrackMux(0)

    server := moqt.Server{
        Addr: ":9000",
        TLSConfig: &tls.Config{
            NextProtos:   []string{moqt.NextProtoH3, moqt.NextProtoMOQ},
            Certificates: []tls.Certificate{loadCert()},
        },
        QUICConfig: &quic.Config{
            Allow0RTT:       true,
            EnableDatagrams: true,
        },
        TrackMux: mux,
        Handler: moqt.HandleFunc(func(sess *moqt.Session) {
            slog.Info("Native QUIC session established")
            <-sess.Context().Done()
        }),
        WebTransportServer: &webtransportgo.Server{},
        Logger: slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
            Level: slog.LevelInfo,
        })),
    }

    err := server.ListenAndServe()
    if err != nil {
        slog.Error("Failed to start server", "error", err)
    }
}

Initialize a Server

There is no dedicated function (such as a constructor) for initializing a server. Users define the struct directly and assign values to its fields as needed.

    server := moqt.Server{
        // Set server options here
    }

Configuration

The following table describes the public fields of the Server struct:

FieldTypeDescription
AddrstringServer address and port
TLSConfig*tls.ConfigTLS configuration for secure connections
QUICConfig*quic.ConfigQUIC protocol configuration
Config*moqt.ConfigMOQ protocol configuration
TrackMux*moqt.TrackMuxMultiplexer for routing announcements and track subscriptions. If nil, a global default mux is used.
Handlermoqt.HandlerHandler for accepted native QUIC sessions. If nil, native QUIC connections are not handled.
FetchHandlermoqt.FetchHandlerHandles incoming FETCH requests on native QUIC sessions. If nil, FETCH requests are rejected.
WebTransportServermoqt.WebTransportServerWebTransport server for handling WebTransport sessions. If nil, a default implementation is used.
ListenFuncfunc(addr, tlsConfig, quicConfig) (QUICListener, error)Custom QUIC listener function. If nil, the default implementation is used.
ConnContextfunc(ctx context.Context, conn StreamConn) context.ContextModifies the context used for a new connection. Optional.
NextSessionURIstringThe URI sent to clients during Shutdown, allowing them to reconnect to a different server. If empty, no redirect URI is provided.
Logger*slog.LoggerLogger for server events and errors. If nil, logging is disabled.

quic-go/quic-go is used internally as the default QUIC implementation when relevant fields which is set for customization are not set or nil.

quic-go/quic-go
Loading...
- -

quic-go/webtransport-go is used internally as the default WebTransport implementation when WebTransportServer is nil.

quic-go/webtransport-go
Loading...
- -

Handle Sessions

ALPN-Based Dispatch

ServeQUICConn detects the negotiated ALPN protocol and dispatches the connection accordingly:

    // Native QUIC (moq-lite-04) → Server.Handler.ServeMOQ(sess)
    // HTTP/3 (h3)               → Server.WebTransportServer.ServeQUICConn(conn)

Native QUIC Handler

For native QUIC connections (ALPN moq-lite-04), the Handler field receives a *moqt.Session directly:

type Handler interface {
    ServeMOQ(sess *Session)
}
    server := moqt.Server{
        Handler: moqt.HandleFunc(func(sess *moqt.Session) {
            slog.Info("Session established",
                "remote", sess.RemoteAddr(),
                "version", sess.ConnectionState().Version,
            )
            <-sess.Context().Done()
        }),
        // ...
    }

WebTransport Handler

For WebTransport connections, use moqt.WebTransportHandler to handle HTTP upgrade and session setup:

    wtHandler := &moqt.WebTransportHandler{
        TrackMux: mux,
        Handler: moqt.HandleFunc(func(sess *moqt.Session) {
            slog.Info("WebTransport session established")
            <-sess.Context().Done()
        }),
        CheckOrigin: func(r *http.Request) bool {
            return r.Header.Get("Origin") == "https://trusted.example.com"
        },
        FetchHandler: moqt.FetchHandlerFunc(func(w *moqt.GroupWriter, r *moqt.FetchRequest) {
            // Handle fetch requests
        }),
        Logger: logger,
    }

    http.Handle("/moq", wtHandler)

WebTransportHandler implements http.Handler and can be used with any HTTP server. It upgrades the HTTP/3 connection to WebTransport, creates a session, and invokes the configured Handler.

Run the Server

Server.ListenAndServe starts the server listening for incoming connections.

    server.ListenAndServe()

For more advanced use cases:

  • ListenAndServeTLS(certFile, keyFile string): Starts the server with TLS certificates loaded from files.
  • ServeQUICListener(ln QUICListener): Serves on an existing QUIC listener.
  • ServeQUICConn(conn StreamConn): Handles a single QUIC connection directly.

Shutting Down a Server

Servers also support immediate and graceful shutdowns.

Immediate Shutdown

Server.Close method terminates all sessions and closes listeners forcefully.

    server.Close() // Immediate shutdown

Graceful Shutdown

Server.Shutdown method notifies all active sessions with NextSessionURI as the redirect and waits for them to close gracefully before forcing termination.

    server := moqt.Server{
        NextSessionURI: "https://backup.example.com/moq",
        // ...
    }

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    err := server.Shutdown(ctx)
    if err != nil {
        // Handle forced termination
    }

If the context expires before all sessions close, remaining connections are closed with a GoAwayTimeoutErrorCode.