mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
* fix(ws): resolve an empty READ audience for a channel whose row is gone channelReadAudience already failed closed on a GetChannel error; a deleted channel returns (nil, nil) and fell through to the role scan. Return nobody for a missing row too — voice teardown callers union the room's participants and the leaver back in, so their signals still land. Test locks both halves: the non-participant hears nothing, the leaver still gets voice_leave. (OC-0090) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ws): re-elect the key holder in CleanupVoiceForChannel Every other voice-removal path re-elects (finishVoiceLeave, the LiveKit webhook, registerNow, rollbackVoiceJoin, sweepStaleVoiceStates); the channel delete/archive path did not, so a torn-down channel's voiceKeyHolders entry lived for the process lifetime. One updateKeyHolder call at the end of the teardown deletes it. (OC-0012) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ws): implement BroadcastMemberUnban so unban reaches connected clients The admin unban path reaches the hub through an optional-capability type assertion that *ws.Hub never satisfied, so it always missed silently and clients connected during a ban kept the user missing from their member store. Implement the mirror of BroadcastMemberBan: fan out the same member_join a fresh connect sends (clients already map it to addMember), reporting offline since the unbanned user cannot be connected. A compile-time assertion in admin pins the wiring so the assertion can never silently miss again. (OC-0058) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(db): exclude the requester's own flag from the video-cap stream count EnableCameraIfUnderLimit and EnableScreenshareIfUnderLimit counted every stream in the channel including the very flag the UPDATE sets, so a user whose server-side flag was already 1 (client lost track and retried) was refused at the cap against their own stream, with no path out. Subtract the outer row's own bit from the correlated count: re-enable becomes idempotent while the requester's other stream and everyone else's still count. sqlc layer regenerated. (OC-0081) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(ledger): resolve the six blocked batch-4 findings Four fixed in this branch (OC-0012, OC-0058, OC-0081, OC-0090), each with an independent revert-proof pass. Two were already fixed on main by later sibling fixes and are recorded as such: OC-0086 by the OC-0017 pre-delete re-check (#1374), OC-0101 by the OC-0206 early watermark bump (#1375). The ledger holds zero open and zero blocked findings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
132 lines
5.6 KiB
SQL
132 lines
5.6 KiB
SQL
-- server_muted / server_deafened are deliberately absent from both upserts'
|
|
-- reset lists: a moderator-imposed mute must survive a channel switch, which
|
|
-- reaches the ON CONFLICT branch. It is scoped to the voice session:
|
|
-- leaving voice deletes the row, so a rejoin starts clean.
|
|
|
|
-- name: JoinVoiceChannel :exec
|
|
INSERT INTO voice_states (user_id, channel_id, muted, deafened, speaking, camera, screenshare, joined_at)
|
|
VALUES (?, ?, 0, 0, 0, 0, 0, ?)
|
|
ON CONFLICT(user_id) DO UPDATE SET
|
|
channel_id = excluded.channel_id,
|
|
muted = 0,
|
|
deafened = 0,
|
|
speaking = 0,
|
|
camera = 0,
|
|
screenshare = 0,
|
|
joined_at = excluded.joined_at;
|
|
|
|
-- name: JoinVoiceChannelIfCapacity :execresult
|
|
INSERT INTO voice_states (user_id, channel_id, muted, deafened, speaking, camera, screenshare, joined_at)
|
|
SELECT ?, ?, 0, 0, 0, 0, 0, ?
|
|
WHERE (SELECT COUNT(*) FROM voice_states AS vs2 WHERE vs2.channel_id = ?) < ?
|
|
ON CONFLICT(user_id) DO UPDATE SET
|
|
channel_id = excluded.channel_id,
|
|
muted = 0,
|
|
deafened = 0,
|
|
speaking = 0,
|
|
camera = 0,
|
|
screenshare = 0,
|
|
joined_at = excluded.joined_at;
|
|
|
|
-- name: LeaveVoiceChannel :exec
|
|
DELETE FROM voice_states WHERE user_id = ?;
|
|
|
|
-- name: LeaveVoiceChannelIfMatch :execresult
|
|
DELETE FROM voice_states WHERE user_id = ? AND channel_id = ? AND joined_at = ?;
|
|
|
|
-- name: GetUserVoiceState :one
|
|
SELECT vs.user_id, vs.channel_id, u.username,
|
|
vs.muted, vs.deafened, vs.speaking,
|
|
vs.camera, vs.screenshare,
|
|
vs.server_muted, vs.server_deafened, vs.joined_at
|
|
FROM voice_states vs
|
|
JOIN users u ON u.id = vs.user_id
|
|
WHERE vs.user_id = ?;
|
|
|
|
-- name: GetChannelVoiceStates :many
|
|
SELECT vs.user_id, vs.channel_id, u.username,
|
|
vs.muted, vs.deafened, vs.speaking,
|
|
vs.camera, vs.screenshare,
|
|
vs.server_muted, vs.server_deafened, vs.joined_at
|
|
FROM voice_states vs
|
|
JOIN users u ON u.id = vs.user_id
|
|
WHERE vs.channel_id = ?
|
|
ORDER BY vs.joined_at ASC;
|
|
|
|
-- name: GetAllVoiceStates :many
|
|
SELECT vs.user_id, vs.channel_id, u.username,
|
|
vs.muted, vs.deafened, vs.speaking,
|
|
vs.camera, vs.screenshare,
|
|
vs.server_muted, vs.server_deafened, vs.joined_at
|
|
FROM voice_states vs
|
|
JOIN users u ON u.id = vs.user_id
|
|
ORDER BY vs.channel_id, vs.joined_at ASC;
|
|
|
|
-- name: UpdateVoiceMute :exec
|
|
UPDATE voice_states SET muted = ? WHERE user_id = ?;
|
|
|
|
-- name: UpdateVoiceDeafen :exec
|
|
UPDATE voice_states SET deafened = ? WHERE user_id = ?;
|
|
|
|
-- name: UpdateVoiceCamera :exec
|
|
UPDATE voice_states SET camera = ? WHERE user_id = ?;
|
|
|
|
-- name: UpdateVoiceScreenshare :exec
|
|
UPDATE voice_states SET screenshare = ? WHERE user_id = ?;
|
|
|
|
-- Scoped to channel_id as well as user_id: the moderator's authorization is
|
|
-- checked against a channel snapshot several round trips before this write
|
|
-- lands, so an unscoped `WHERE user_id = ?` would follow the target onto
|
|
-- whatever channel their row points at by then -- including a DM call the
|
|
-- moderator was never authorized against (OC-0005). :execresult so the
|
|
-- caller can tell a real no-op (target moved) from a normal apply.
|
|
|
|
-- name: ApplyVoiceServerMute :execresult
|
|
UPDATE voice_states SET server_muted = 1, muted = 1 WHERE user_id = ? AND channel_id = ?;
|
|
|
|
-- name: ClearVoiceServerMute :execresult
|
|
UPDATE voice_states SET server_muted = 0 WHERE user_id = ? AND channel_id = ?;
|
|
|
|
-- name: ApplyVoiceServerDeafen :execresult
|
|
UPDATE voice_states SET server_deafened = 1, deafened = 1 WHERE user_id = ? AND channel_id = ?;
|
|
|
|
-- name: ClearVoiceServerDeafen :execresult
|
|
UPDATE voice_states SET server_deafened = 0 WHERE user_id = ? AND channel_id = ?;
|
|
|
|
-- Camera and screenshare share one voice_max_video budget, counted in
|
|
-- STREAMS, not rows: a channel capped at N simultaneous video streams must
|
|
-- not let a camera publish ignore screenshare occupants (or vice versa,
|
|
-- OC-0023), and a single user with both flags set must consume two of the N
|
|
-- slots, not one (OC-0006) -- so both gates sum `vs2.camera + vs2.screenshare`
|
|
-- across the channel's rows rather than counting rows where either is set.
|
|
-- The enabling user's own bit for the flag being set CAN already be 1 at
|
|
-- gate time (a client that lost track of the server-side flag retries the
|
|
-- enable), so each gate excludes exactly that one bit from the count --
|
|
-- see the per-query comments below (OC-0081).
|
|
|
|
-- name: EnableCameraIfUnderLimit :execresult
|
|
-- The channel-wide stream count excludes the requester's own camera flag
|
|
-- (subtracted via the correlated outer-row reference), so re-enabling an
|
|
-- already-set camera is idempotent at the cap instead of being refused
|
|
-- against the requester's own stream (OC-0081). Their screenshare, and
|
|
-- every other user's streams, still count.
|
|
UPDATE voice_states SET camera = 1
|
|
WHERE voice_states.user_id = ? AND voice_states.channel_id = ?
|
|
AND (SELECT COALESCE(SUM(vs2.camera), 0) + COALESCE(SUM(vs2.screenshare), 0) FROM voice_states AS vs2 WHERE vs2.channel_id = ?) - voice_states.camera < sqlc.arg(max_video);
|
|
|
|
-- name: EnableScreenshareIfUnderLimit :execresult
|
|
-- Mirror of EnableCameraIfUnderLimit: the count excludes the requester's
|
|
-- own screenshare flag so re-enable is idempotent at the cap (OC-0081).
|
|
UPDATE voice_states SET screenshare = 1
|
|
WHERE voice_states.user_id = ? AND voice_states.channel_id = ?
|
|
AND (SELECT COALESCE(SUM(vs2.camera), 0) + COALESCE(SUM(vs2.screenshare), 0) FROM voice_states AS vs2 WHERE vs2.channel_id = ?) - voice_states.screenshare < sqlc.arg(max_video);
|
|
|
|
-- name: ClearVoiceState :exec
|
|
DELETE FROM voice_states WHERE user_id = ?;
|
|
|
|
-- name: ClearAllVoiceStates :exec
|
|
DELETE FROM voice_states;
|
|
|
|
-- name: CountActiveCameras :one
|
|
SELECT COUNT(*) FROM voice_states WHERE channel_id = ? AND camera = 1;
|