-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathrequests.go
More file actions
205 lines (188 loc) · 7.32 KB
/
Copy pathrequests.go
File metadata and controls
205 lines (188 loc) · 7.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// Copyright 2025 Element Creations Ltd.
// Copyright 2023 - 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
// requests.go: HTTP request / response DTOs used by the handler —
// SFURequest, DelegateDelayedLeaveRequest, LegacySFURequest,
// SFUResponse, MatrixErrorResponse — together with their Validate()
// methods. Each type lives next to its validator (idiomatic Go).
package main
import (
"log/slog"
"net/http"
)
type MatrixRTCMemberType struct {
ID string `json:"id"`
ClaimedUserID string `json:"claimed_user_id"`
ClaimedDeviceID string `json:"claimed_device_id"`
}
type OpenIDTokenType struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
MatrixServerName string `json:"matrix_server_name"`
ExpiresIn int `json:"expires_in"`
}
// Deprecated: LegacySFURequest is the request body for /sfu/get, the
// pre-Matrix-2.0 endpoint. Remove once all in-the-wild clients have
// migrated to /get_token (SFURequest).
type LegacySFURequest struct {
Room string `json:"room"`
OpenIDToken OpenIDTokenType `json:"openid_token"`
DeviceID string `json:"device_id"`
DelayId string `json:"delay_id,omitempty"`
DelayTimeout int `json:"delay_timeout,omitempty"`
// Deprecated and ignored to allow transition. Server discovery or explicit overrides via
// LIVEKIT_CS_API_URL_OVERRIDES will be used instead.
DelayCsApiUrl string `json:"delay_cs_api_url,omitempty"`
}
type SFURequest struct {
RoomID string `json:"room_id"`
SlotID string `json:"slot_id"`
OpenIDToken OpenIDTokenType `json:"openid_token"`
Member MatrixRTCMemberType `json:"member"`
// Deprecated.
// TODO: These were only supported in an earlier version of the MSC. Later versions
// split token request and disconnect delegation into separate endpoints. We should
// remove these parameters and the related code at some point.
DelayId string `json:"delay_id,omitempty"`
DelayTimeout int `json:"delay_timeout,omitempty"`
// Deprecated and ignored to allow transition. Server discovery or explicit overrides via
// LIVEKIT_CS_API_URL_OVERRIDES will be used instead.
DelayCsApiUrl string `json:"delay_cs_api_url,omitempty"`
}
type SFUResponse struct {
URL string `json:"url"`
JWT string `json:"jwt"`
}
// DelegateDelayedLeaveRequest is the body of POST /delegate_delayed_leave.
// It is used when the client is already connected to the SFU and wants to
// hand over the delayed disconnect event after the fact — i.e. no JWT is
// needed and the LiveKit room already exists.
//
// All three delayed-event fields are mandatory (unlike SFURequest where they
// are optional). The participant is assumed to be already present on the SFU,
// so the participant-lookup goroutine uses its backoff to confirm presence
// rather than waiting for the webhook (which has already fired).
type DelegateDelayedLeaveRequest struct {
RoomID string `json:"room_id"`
SlotID string `json:"slot_id"`
OpenIDToken OpenIDTokenType `json:"openid_token"`
Member MatrixRTCMemberType `json:"member"`
DelayId string `json:"delay_id"`
DelayTimeout int `json:"delay_timeout"`
// Deprecated and ignored to allow transition. Server discovery or explicit overrides via
// LIVEKIT_CS_API_URL_OVERRIDES will be used instead.
DelayCsApiUrl string `json:"delay_cs_api_url"`
}
func (r *DelegateDelayedLeaveRequest) Validate() error {
if r.RoomID == "" || r.SlotID == "" {
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body is missing `room_id` or `slot_id`",
}
}
if r.Member.ID == "" || r.Member.ClaimedUserID == "" || r.Member.ClaimedDeviceID == "" {
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body `member` is missing `id`, `claimed_user_id` or `claimed_device_id`",
}
}
if r.OpenIDToken.AccessToken == "" || r.OpenIDToken.MatrixServerName == "" {
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body `openid_token` is missing `access_token` or `matrix_server_name`",
}
}
if r.DelayId == "" || r.DelayTimeout <= 0 {
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body is missing `delay_id` or `delay_timeout`",
}
}
return nil
}
type DelegateDelayedLeaveResponse struct {
}
type MatrixErrorResponse struct {
Status int
ErrCode string
Err string
}
func (e *MatrixErrorResponse) Error() string {
return e.Err
}
func (r *SFURequest) Validate() error {
if r.RoomID == "" || r.SlotID == "" {
slog.Error("Missing room_id or slot_id", "room_id", r.RoomID, "slot_id", r.SlotID)
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body is missing `room_id` or `slot_id`",
}
}
if r.Member.ID == "" || r.Member.ClaimedUserID == "" || r.Member.ClaimedDeviceID == "" {
slog.Error("Handler -> SFURequest: Missing member parameters", "Member", r.Member)
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body `member` is missing a `id`, `claimed_user_id` or `claimed_device_id`",
}
}
if r.OpenIDToken.AccessToken == "" || r.OpenIDToken.MatrixServerName == "" {
slog.Error("Handler -> SFURequest: Missing OpenID token parameters:", "OpenIDToken", r.OpenIDToken)
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body `openid_token` is missing a `access_token` or `matrix_server_name`",
}
}
allDelayedEventParamsPresent := r.DelayId != "" && r.DelayTimeout > 0
atLeastOneDelayedEventParamPresent := r.DelayId != "" || r.DelayTimeout > 0
if atLeastOneDelayedEventParamPresent && !allDelayedEventParamsPresent {
slog.Error("Handler -> SFURequest: Missing delayed event delegation parameters",
"delayId", r.DelayId,
"delayTimeout", r.DelayTimeout,
)
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body is missing `delay_id` or `delay_timeout`",
}
}
return nil
}
func (r *LegacySFURequest) Validate() error {
if r.Room == "" {
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "Missing room parameter",
}
}
if r.OpenIDToken.AccessToken == "" || r.OpenIDToken.MatrixServerName == "" {
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "Missing OpenID token parameters",
}
}
allDelayedEventParamsPresent := r.DelayId != "" && r.DelayTimeout > 0
atLeastOneDelayedEventParamPresent := r.DelayId != "" || r.DelayTimeout > 0
if atLeastOneDelayedEventParamPresent && !allDelayedEventParamsPresent {
slog.Error("Handler -> SFURequest: Missing delayed event delegation parameters",
"delayId", r.DelayId,
"delayTimeout", r.DelayTimeout,
)
return &MatrixErrorResponse{
Status: http.StatusBadRequest,
ErrCode: "M_BAD_JSON",
Err: "The request body is missing `delay_id` or `delay_timeout`",
}
}
return nil
}