CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
CI / Admin panel (push) Canceled after 0s
CI / Web client (push) Canceled after 0s
Every call in the web client now goes through MatrixRTC with a LiveKit
SFU, the model Element Call and Element X use; the legacy 1:1 m.call.*
calls are gone. In a room of two the other person is rung and can answer
or decline; in a bigger room a banner offers to join the call. Calls show
a grid of participant tiles with mute, camera, screen sharing and leave,
and media is end-to-end encrypted in encrypted rooms.
Server:
- MSC4140 delayed events (send/state with a delay, plus the
delayed_events list/restart/cancel/send API), stored and scheduled, so
a member whose client drops off is taken out of the call.
- POST /user/{userId}/openid/request_token, which lk-jwt-service uses to
hand out LiveKit tokens.
- org.matrix.msc4143.rtc_foci in /.well-known/matrix/client, configured
under client_api.rtc.
- Room presets let members send call membership state.
- Migration 0014 for both SQL dialects.
Deploy: LiveKit and lk-jwt-service in compose (calls.yml) and the helm
chart. Docs: docs/calls.md, configuration and deployment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
111 lines
4.2 KiB
Go
111 lines
4.2 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
)
|
|
|
|
// ErrNoSuchDelayedEvent is returned for a delay ID that is unknown, belongs
|
|
// to someone else, or is no longer scheduled.
|
|
var ErrNoSuchDelayedEvent = errors.New("no such delayed event")
|
|
|
|
// DelayedEvent is an event a client asked to have sent later (MSC4140).
|
|
//
|
|
// While it is scheduled FinalisedAtMS is zero. Once it has been sent or
|
|
// cancelled it is kept for a while with its outcome, so a client that comes
|
|
// back can find out what became of it.
|
|
type DelayedEvent struct {
|
|
DelayID string
|
|
UserID string
|
|
DeviceID string
|
|
RoomID string
|
|
Type string
|
|
|
|
// StateKey is nil for a timeline event.
|
|
StateKey *string
|
|
Content json.RawMessage
|
|
|
|
// DelayMS is the delay the client asked for. A restart counts it again
|
|
// from now.
|
|
DelayMS int64
|
|
|
|
// RunningSinceMS is when the delay was last (re)started, and SendAtMS
|
|
// when it runs out: RunningSinceMS + DelayMS.
|
|
RunningSinceMS int64
|
|
SendAtMS int64
|
|
|
|
// The outcome, once finalised: Outcome is "send" or "cancel", Reason
|
|
// "delay", "action" or "error". EventID is the event that was sent,
|
|
// and Error the Matrix error that stopped it.
|
|
FinalisedAtMS int64
|
|
Outcome string
|
|
Reason string
|
|
EventID string
|
|
Error json.RawMessage
|
|
}
|
|
|
|
// DelayedEventStore keeps the delayed events of every user.
|
|
type DelayedEventStore interface {
|
|
// InsertDelayedEvent schedules an event.
|
|
InsertDelayedEvent(ctx context.Context, e DelayedEvent) error
|
|
|
|
// DelayedEvent returns one of userID's events, scheduled or finalised.
|
|
DelayedEvent(ctx context.Context, userID, delayID string) (DelayedEvent, error)
|
|
|
|
// ScheduledDelayedEvent returns a scheduled event whoever owns it: the
|
|
// action endpoints are addressed by the delay ID alone.
|
|
ScheduledDelayedEvent(ctx context.Context, delayID string) (DelayedEvent, error)
|
|
|
|
// DelayedEvents lists userID's events, scheduled ones first by when
|
|
// they are due, then finalised ones newest first.
|
|
DelayedEvents(ctx context.Context, userID string) ([]DelayedEvent, error)
|
|
|
|
// CountScheduledDelayedEvents counts userID's scheduled events.
|
|
CountScheduledDelayedEvents(ctx context.Context, userID string) (int, error)
|
|
|
|
// RestartDelayedEvent starts a scheduled event's delay again from nowMS.
|
|
// It returns ErrNoSuchDelayedEvent if the event is not scheduled.
|
|
RestartDelayedEvent(ctx context.Context, delayID string, nowMS int64) error
|
|
|
|
// FinaliseDelayedEvent records what became of a scheduled event. It
|
|
// returns ErrNoSuchDelayedEvent if the event was already finalised,
|
|
// which is how two racing finalisers are told apart: only one of them
|
|
// gets to send.
|
|
FinaliseDelayedEvent(ctx context.Context, e DelayedEvent) error
|
|
|
|
// DueDelayedEvents returns up to limit scheduled events whose delay
|
|
// has run out at nowMS, the earliest first.
|
|
DueDelayedEvents(ctx context.Context, nowMS int64, limit int) ([]DelayedEvent, error)
|
|
|
|
// NextDelayedEventDue reports when the next scheduled event is due,
|
|
// and false when nothing is scheduled.
|
|
NextDelayedEventDue(ctx context.Context) (int64, bool, error)
|
|
|
|
// ScheduledDelayedStateEvents lists the scheduled state events for one
|
|
// piece of room state, of every user.
|
|
ScheduledDelayedStateEvents(ctx context.Context, roomID, eventType, stateKey string) ([]DelayedEvent, error)
|
|
|
|
// PurgeFinalisedDelayedEvents forgets the events finalised before
|
|
// beforeMS.
|
|
PurgeFinalisedDelayedEvents(ctx context.Context, beforeMS int64) error
|
|
}
|
|
|
|
// ErrNoSuchOpenIDToken is returned for an OpenID token that is unknown or
|
|
// has expired.
|
|
var ErrNoSuchOpenIDToken = errors.New("no such OpenID token")
|
|
|
|
// OpenIDTokenStore keeps the OpenID tokens users hand to third parties, so
|
|
// those can find out who the user is (and nothing more) from this server.
|
|
type OpenIDTokenStore interface {
|
|
// InsertOpenIDToken stores a token by its hash.
|
|
InsertOpenIDToken(ctx context.Context, tokenHash, userID string, expiresAtMS int64) error
|
|
|
|
// OpenIDTokenUser returns the user a token was issued to, or
|
|
// ErrNoSuchOpenIDToken once it has expired at nowMS.
|
|
OpenIDTokenUser(ctx context.Context, tokenHash string, nowMS int64) (string, error)
|
|
|
|
// PurgeOpenIDTokens forgets tokens that expired before beforeMS.
|
|
PurgeOpenIDTokens(ctx context.Context, beforeMS int64) error
|
|
}
|