mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
chore: delete dead code and tracked junk (deletion audit 2026-07-23)
Verified-safe deletions from the 2026-07-23 deletion audit, applied now that the permission-consolidation work (which deferred IsOwnerRole) has landed: - Server/service/voice.go: VoiceService was constructed in service.New and never called by any handler, ws routine, or test. - permissions.IsOwnerRole: zero callers. - Server/admin/static/admin-mockup.html: 1299 lines embedded into every release binary via //go:embed static, referenced by nothing. - .cache/project-map/*.json: tool cache committed before .gitignore grew the .cache/ rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,619 +0,0 @@
|
||||
{
|
||||
"timestamp": "2026-03-31T09:23:48.747Z",
|
||||
"sessions": [
|
||||
{
|
||||
"date": "2025-03-24",
|
||||
"summary": "Comprehensive file reference documentation review — 28 bugs fixed, all docs updated to match code reality",
|
||||
"tasksCompleted": 28,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"stores",
|
||||
"components",
|
||||
"tauri-rust",
|
||||
"protocol",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2025-03-24-file-reference-review.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"summary": "Completed all 13 CEO review fixes and raised server test coverage to 80%+",
|
||||
"tasksCompleted": 14,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"config",
|
||||
"stores",
|
||||
"tauri-rust",
|
||||
"tests",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-17-ceo-fixes-and-coverage.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"summary": "CEO plan review sections 1-8 (HOLD SCOPE) for tauri-migration branch",
|
||||
"tasksCompleted": 0,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"storage",
|
||||
"config",
|
||||
"stores",
|
||||
"pages",
|
||||
"tauri-rust",
|
||||
"tests",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-17-ceo-review-sections-1-8.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"summary": "CEO plan review of tauri-migration branch — HOLD SCOPE",
|
||||
"tasksCompleted": 0,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"permissions",
|
||||
"storage",
|
||||
"components",
|
||||
"pages",
|
||||
"tauri-rust",
|
||||
"protocol",
|
||||
"tests",
|
||||
"security"
|
||||
],
|
||||
"fileName": "2026-03-17-ceo-review.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"summary": "Fixed all golangci-lint issues blocking CI, set up project brain vault",
|
||||
"tasksCompleted": 2,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"ws",
|
||||
"voice",
|
||||
"tauri-rust",
|
||||
"tests",
|
||||
"docs",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-17-lint-fixes-and-vault-setup.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"summary": "Pre-landing review of tauri-migration, commit, push, and PR #15 to dev",
|
||||
"tasksCompleted": 0,
|
||||
"modulesTouched": [
|
||||
"auth",
|
||||
"db",
|
||||
"config",
|
||||
"tauri-rust",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-17-merge-review-and-pr.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-18",
|
||||
"summary": "Channel management, file uploads, URL previews, voice fixes, UX polish",
|
||||
"tasksCompleted": 15,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"voice",
|
||||
"storage",
|
||||
"components",
|
||||
"tauri-rust",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-18-features.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-18",
|
||||
"summary": "Added native E2E testing via WebView2 CDP",
|
||||
"tasksCompleted": 1,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"voice",
|
||||
"storage",
|
||||
"config",
|
||||
"lib",
|
||||
"tauri-rust",
|
||||
"e2e",
|
||||
"tests",
|
||||
"docs",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-18-native-e2e.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-18",
|
||||
"summary": "Voice chat NAT fix, audio pipeline overhaul, debugging infrastructure",
|
||||
"tasksCompleted": 12,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"voice",
|
||||
"stores",
|
||||
"components",
|
||||
"tauri-rust",
|
||||
"tests",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-18-voice-audio-fixes.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-19",
|
||||
"summary": "Go code review (4 passes, 19 fixes), admin panel redesign, live server logs, audit log filters, console output cleanup",
|
||||
"tasksCompleted": 7,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"permissions",
|
||||
"storage",
|
||||
"config",
|
||||
"lib",
|
||||
"components",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-19-admin-panel-and-server-review.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-20",
|
||||
"summary": "Camera button delay fix, video feed flicker fix, security hardening, documentation sync",
|
||||
"tasksCompleted": 4,
|
||||
"modulesTouched": [
|
||||
"auth",
|
||||
"db",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"stores",
|
||||
"pages",
|
||||
"tauri-rust",
|
||||
"protocol",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-20-livekit-camera-fixes.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-20",
|
||||
"summary": "",
|
||||
"tasksCompleted": 0,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"stores",
|
||||
"protocol",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-20-research-report.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-21",
|
||||
"summary": "Implemented 30 actionable fixes from code review audit across server and client",
|
||||
"tasksCompleted": 30,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"storage",
|
||||
"stores",
|
||||
"components",
|
||||
"pages",
|
||||
"tauri-rust",
|
||||
"e2e",
|
||||
"tests",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-21-code-review-fixes.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-22",
|
||||
"summary": "Competitive research, feature roadmap, GitHub issues, vault build-out",
|
||||
"tasksCompleted": 10,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"lib",
|
||||
"stores",
|
||||
"components",
|
||||
"tauri-rust",
|
||||
"protocol",
|
||||
"e2e",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-22-competitive-research.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-26",
|
||||
"summary": "Implemented client-side fixes from Codex/code review findings and added targeted regression coverage.",
|
||||
"tasksCompleted": 1,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"ws",
|
||||
"voice",
|
||||
"config",
|
||||
"stores",
|
||||
"components",
|
||||
"tests",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-26-client-review-fixes.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-27",
|
||||
"summary": "Code review (27 fixes), connection quality indicator, remember-password fix, login redesign with OC branding, new app icon.",
|
||||
"tasksCompleted": 38,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"storage",
|
||||
"config",
|
||||
"lib",
|
||||
"stores",
|
||||
"components",
|
||||
"tauri-rust",
|
||||
"protocol",
|
||||
"tests",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-27-dual-model-code-review.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-28",
|
||||
"summary": "Spec audit (18 files, 50 fixes), 143 unit tests, E2E overhaul, CSS injection fix",
|
||||
"tasksCompleted": 8,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"storage",
|
||||
"lib",
|
||||
"stores",
|
||||
"components",
|
||||
"tauri-rust",
|
||||
"e2e",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-28-specs-tests-e2e.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-29",
|
||||
"summary": "Client-side 2FA integration — TOTP enrollment/disable UI, api.ts fixes, documentation sync",
|
||||
"tasksCompleted": 5,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"stores",
|
||||
"components",
|
||||
"e2e",
|
||||
"tests",
|
||||
"docs",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-29-2fa-client-integration.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-29",
|
||||
"summary": "Full-project security + code quality audit, 30 issues fixed",
|
||||
"tasksCompleted": 27,
|
||||
"modulesTouched": [
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"ws",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"lib",
|
||||
"tests",
|
||||
"security",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-29-security-audit-fixes.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-30",
|
||||
"summary": "Fixed 10 test quality bugs (BUG-058 through BUG-067)",
|
||||
"tasksCompleted": 10,
|
||||
"modulesTouched": [
|
||||
"auth",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"tauri-rust",
|
||||
"e2e",
|
||||
"tests",
|
||||
"docs",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-30-bug-remediation.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-30",
|
||||
"summary": "Full documentation update — README, Changelog, Dashboard, task tracking",
|
||||
"tasksCompleted": 5,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"db",
|
||||
"voice",
|
||||
"permissions",
|
||||
"config",
|
||||
"components",
|
||||
"e2e",
|
||||
"tests",
|
||||
"docs",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-30-documentation-update.md"
|
||||
},
|
||||
{
|
||||
"date": "2026-03-30",
|
||||
"summary": "Sidebar stream preview + screenshare focus fix",
|
||||
"tasksCompleted": 0,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"voice",
|
||||
"components",
|
||||
"ci"
|
||||
],
|
||||
"fileName": "2026-03-30-stream-preview.md"
|
||||
}
|
||||
],
|
||||
"progressOverTime": [
|
||||
{
|
||||
"date": "2025-03-24",
|
||||
"cumulativeDone": 28,
|
||||
"sessionDone": 28
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"cumulativeDone": 42,
|
||||
"sessionDone": 14
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"cumulativeDone": 42,
|
||||
"sessionDone": 0
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"cumulativeDone": 42,
|
||||
"sessionDone": 0
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"cumulativeDone": 44,
|
||||
"sessionDone": 2
|
||||
},
|
||||
{
|
||||
"date": "2026-03-17",
|
||||
"cumulativeDone": 44,
|
||||
"sessionDone": 0
|
||||
},
|
||||
{
|
||||
"date": "2026-03-18",
|
||||
"cumulativeDone": 59,
|
||||
"sessionDone": 15
|
||||
},
|
||||
{
|
||||
"date": "2026-03-18",
|
||||
"cumulativeDone": 60,
|
||||
"sessionDone": 1
|
||||
},
|
||||
{
|
||||
"date": "2026-03-18",
|
||||
"cumulativeDone": 72,
|
||||
"sessionDone": 12
|
||||
},
|
||||
{
|
||||
"date": "2026-03-19",
|
||||
"cumulativeDone": 79,
|
||||
"sessionDone": 7
|
||||
},
|
||||
{
|
||||
"date": "2026-03-20",
|
||||
"cumulativeDone": 83,
|
||||
"sessionDone": 4
|
||||
},
|
||||
{
|
||||
"date": "2026-03-20",
|
||||
"cumulativeDone": 83,
|
||||
"sessionDone": 0
|
||||
},
|
||||
{
|
||||
"date": "2026-03-21",
|
||||
"cumulativeDone": 113,
|
||||
"sessionDone": 30
|
||||
},
|
||||
{
|
||||
"date": "2026-03-22",
|
||||
"cumulativeDone": 123,
|
||||
"sessionDone": 10
|
||||
},
|
||||
{
|
||||
"date": "2026-03-26",
|
||||
"cumulativeDone": 124,
|
||||
"sessionDone": 1
|
||||
},
|
||||
{
|
||||
"date": "2026-03-27",
|
||||
"cumulativeDone": 162,
|
||||
"sessionDone": 38
|
||||
},
|
||||
{
|
||||
"date": "2026-03-28",
|
||||
"cumulativeDone": 170,
|
||||
"sessionDone": 8
|
||||
},
|
||||
{
|
||||
"date": "2026-03-29",
|
||||
"cumulativeDone": 175,
|
||||
"sessionDone": 5
|
||||
},
|
||||
{
|
||||
"date": "2026-03-29",
|
||||
"cumulativeDone": 202,
|
||||
"sessionDone": 27
|
||||
},
|
||||
{
|
||||
"date": "2026-03-30",
|
||||
"cumulativeDone": 212,
|
||||
"sessionDone": 10
|
||||
},
|
||||
{
|
||||
"date": "2026-03-30",
|
||||
"cumulativeDone": 217,
|
||||
"sessionDone": 5
|
||||
},
|
||||
{
|
||||
"date": "2026-03-30",
|
||||
"cumulativeDone": 217,
|
||||
"sessionDone": 0
|
||||
}
|
||||
],
|
||||
"streaks": {
|
||||
"current": 5,
|
||||
"longest": 6,
|
||||
"totalSessions": 22
|
||||
},
|
||||
"lastSession": {
|
||||
"date": "2026-03-30",
|
||||
"summary": "Sidebar stream preview + screenshare focus fix",
|
||||
"tasksCompleted": 0,
|
||||
"modulesTouched": [
|
||||
"api",
|
||||
"auth",
|
||||
"voice",
|
||||
"components",
|
||||
"ci"
|
||||
]
|
||||
},
|
||||
"inProgress": [],
|
||||
"recentlyDone": [
|
||||
{
|
||||
"id": "T-197",
|
||||
"description": "Discord-style video grid with fixed 16:9 aspect ratio",
|
||||
"date": "2026-03-30"
|
||||
},
|
||||
{
|
||||
"id": "T-198",
|
||||
"description": "Sidebar stream preview + screenshare focus fix",
|
||||
"date": "2026-03-30"
|
||||
},
|
||||
{
|
||||
"id": "T-199",
|
||||
"description": "Fix 10 test quality bugs (BUG-058–067) and resolve 115 TS type errors",
|
||||
"date": "2026-03-30"
|
||||
},
|
||||
{
|
||||
"id": "T-200",
|
||||
"description": "Regenerate codemaps from current codebase",
|
||||
"date": "2026-03-30"
|
||||
},
|
||||
{
|
||||
"id": "T-201",
|
||||
"description": "Full documentation update (README, Changelog, Dashboard, all docs)",
|
||||
"date": "2026-03-30"
|
||||
},
|
||||
{
|
||||
"id": "T-192",
|
||||
"description": "Client 2FA enrollment/disable settings UI",
|
||||
"date": "2026-03-29"
|
||||
},
|
||||
{
|
||||
"id": "T-193",
|
||||
"description": "Client 2FA test coverage — 27 new tests",
|
||||
"date": "2026-03-29"
|
||||
},
|
||||
{
|
||||
"id": "T-194",
|
||||
"description": "Full regression validation pass — all green",
|
||||
"date": "2026-03-29"
|
||||
},
|
||||
{
|
||||
"id": "T-023",
|
||||
"description": "Add TOTP 2FA support — Login challenge: DONE; Server endpoints: DONE; Client enrollment UI: DONE; Client tests: DONE",
|
||||
"date": "2026-03-29"
|
||||
},
|
||||
{
|
||||
"id": "T-190",
|
||||
"description": "Propagate `context.Context` from WS upgrade through all handlers — added `ctx context.Context` field to Client struct (set from `r.Context()` on WS upgrade), updated `MessageHandler` type signature, threaded ctx through all 17 WS handlers across 9 files (chat, presence, reaction, voice, ping). Added `ExecContext`/`QueryRowContext`/`QueryContext`/`BeginTx` context-accepting methods to DB wrapper. Go build + all ws/api/auth/db tests pass",
|
||||
"date": "2026-03-29"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,13 +47,6 @@ const (
|
||||
// operations reserved for the owner.
|
||||
const OwnerRolePosition = 100
|
||||
|
||||
// IsOwnerRole reports whether the given role ID is the built-in owner role.
|
||||
// Use this as an explicit guard in role-modification handlers to prevent
|
||||
// non-owners from escalating to owner privileges.
|
||||
func IsOwnerRole(roleID int64) bool {
|
||||
return roleID == OwnerRoleID
|
||||
}
|
||||
|
||||
// ─── Permission helper functions ─────────────────────────────────────────────
|
||||
|
||||
// HasPerm reports whether rolePerms contains all bits in requiredPerm.
|
||||
|
||||
@@ -20,7 +20,6 @@ type Services struct {
|
||||
Invites *InviteService
|
||||
Blocks *BlockService
|
||||
Moderation *ModerationService
|
||||
Voice *VoiceService
|
||||
}
|
||||
|
||||
// New creates all domain services wired together.
|
||||
@@ -36,6 +35,5 @@ func New(st Store, limiter *auth.RateLimiter) *Services {
|
||||
Invites: NewInviteService(st),
|
||||
Blocks: NewBlockService(st),
|
||||
Moderation: NewModerationService(st, permSvc),
|
||||
Voice: NewVoiceService(st, permSvc),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,150 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/owncord/server/db"
|
||||
"github.com/owncord/server/permissions"
|
||||
"github.com/owncord/server/telemetry"
|
||||
)
|
||||
|
||||
// VoiceService handles voice state business logic.
|
||||
type VoiceService struct {
|
||||
st Store
|
||||
perm *PermissionService
|
||||
}
|
||||
|
||||
// NewVoiceService creates a VoiceService.
|
||||
func NewVoiceService(st Store, perm *PermissionService) *VoiceService {
|
||||
return &VoiceService{st: st, perm: perm}
|
||||
}
|
||||
|
||||
// JoinChannel validates the channel, checks ConnectVoice permission, and
|
||||
// joins the user to the voice channel respecting capacity limits.
|
||||
// Returns the channel on success so callers can access voice config fields.
|
||||
func (s *VoiceService) JoinChannel(userID, channelID int64) (*db.Channel, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/voice").Start(context.Background(), "VoiceService.JoinChannel",
|
||||
telemetry.Int64("user_id", userID),
|
||||
telemetry.Int64("channel_id", channelID),
|
||||
)
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
telemetry.TimeSince(ctx, telemetry.NewAppMetrics().ServiceCallDurationSec, start,
|
||||
telemetry.String("method", "JoinChannel"))
|
||||
span.End()
|
||||
}()
|
||||
|
||||
if channelID <= 0 {
|
||||
return nil, fmt.Errorf("%w: channel_id must be a positive integer", ErrBadRequest)
|
||||
}
|
||||
|
||||
ch, err := s.st.GetChannel(channelID)
|
||||
if err != nil || ch == nil {
|
||||
return nil, fmt.Errorf("%w: channel not found", ErrNotFound)
|
||||
}
|
||||
|
||||
if !s.perm.HasChannelPerm(userID, channelID, permissions.ConnectVoice) {
|
||||
return nil, fmt.Errorf("%w: missing CONNECT_VOICE permission", ErrForbidden)
|
||||
}
|
||||
|
||||
maxUsers := ch.VoiceMaxUsers
|
||||
if maxUsers > 0 {
|
||||
if err := s.st.JoinVoiceChannelIfCapacity(userID, channelID, maxUsers); err != nil {
|
||||
if errors.Is(err, db.ErrChannelFull) {
|
||||
return nil, fmt.Errorf("%w: voice channel is full", ErrForbidden)
|
||||
}
|
||||
slog.Error("VoiceService.JoinChannel JoinVoiceChannelIfCapacity", "err", err, "user_id", userID)
|
||||
return nil, fmt.Errorf("%w: failed to join voice channel", ErrInternal)
|
||||
}
|
||||
} else {
|
||||
if err := s.st.JoinVoiceChannel(userID, channelID); err != nil {
|
||||
slog.Error("VoiceService.JoinChannel JoinVoiceChannel", "err", err, "user_id", userID)
|
||||
return nil, fmt.Errorf("%w: failed to join voice channel", ErrInternal)
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("voice join", "user_id", userID, "channel_id", channelID)
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// LeaveChannel removes the user from their current voice channel.
|
||||
func (s *VoiceService) LeaveChannel(userID int64) error {
|
||||
if err := s.st.LeaveVoiceChannel(userID); err != nil {
|
||||
slog.Error("VoiceService.LeaveChannel", "err", err, "user_id", userID)
|
||||
return fmt.Errorf("%w: failed to leave voice channel", ErrInternal)
|
||||
}
|
||||
|
||||
slog.Info("voice leave", "user_id", userID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateMute toggles the mute state for the given user.
|
||||
func (s *VoiceService) UpdateMute(userID int64, muted bool) error {
|
||||
if err := s.st.UpdateVoiceMute(userID, muted); err != nil {
|
||||
slog.Error("VoiceService.UpdateMute", "err", err, "user_id", userID)
|
||||
return fmt.Errorf("%w: failed to update mute state", ErrInternal)
|
||||
}
|
||||
|
||||
slog.Debug("voice mute changed", "user_id", userID, "muted", muted)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDeafen toggles the deafen state for the given user.
|
||||
func (s *VoiceService) UpdateDeafen(userID int64, deafened bool) error {
|
||||
if err := s.st.UpdateVoiceDeafen(userID, deafened); err != nil {
|
||||
slog.Error("VoiceService.UpdateDeafen", "err", err, "user_id", userID)
|
||||
return fmt.Errorf("%w: failed to update deafen state", ErrInternal)
|
||||
}
|
||||
|
||||
slog.Debug("voice deafen changed", "user_id", userID, "deafened", deafened)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToggleCamera enables or disables the user's camera. When enabling, it
|
||||
// enforces the maxVideo limit via an atomic check-and-update. Returns true
|
||||
// if the camera was successfully enabled (or disabled), false if the video
|
||||
// limit was reached.
|
||||
func (s *VoiceService) ToggleCamera(userID, channelID int64, enable bool, maxVideo int) (bool, error) {
|
||||
if !s.perm.HasChannelPerm(userID, channelID, permissions.UseVideo) {
|
||||
return false, fmt.Errorf("%w: missing USE_VIDEO permission", ErrForbidden)
|
||||
}
|
||||
|
||||
if enable && maxVideo > 0 {
|
||||
ok, err := s.st.EnableCameraIfUnderLimit(userID, channelID, maxVideo)
|
||||
if err != nil {
|
||||
slog.Error("VoiceService.ToggleCamera EnableCameraIfUnderLimit", "err", err, "user_id", userID)
|
||||
return false, fmt.Errorf("%w: failed to check video limit", ErrInternal)
|
||||
}
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
if err := s.st.UpdateVoiceCamera(userID, enable); err != nil {
|
||||
slog.Error("VoiceService.ToggleCamera UpdateVoiceCamera", "err", err, "user_id", userID)
|
||||
return false, fmt.Errorf("%w: failed to update camera state", ErrInternal)
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug("voice camera changed", "user_id", userID, "enabled", enable, "channel_id", channelID)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ToggleScreenshare enables or disables the user's screen share after
|
||||
// checking the ShareScreen permission.
|
||||
func (s *VoiceService) ToggleScreenshare(userID, channelID int64, enable bool) error {
|
||||
if !s.perm.HasChannelPerm(userID, channelID, permissions.ShareScreen) {
|
||||
return fmt.Errorf("%w: missing SHARE_SCREEN permission", ErrForbidden)
|
||||
}
|
||||
|
||||
if err := s.st.UpdateVoiceScreenshare(userID, enable); err != nil {
|
||||
slog.Error("VoiceService.ToggleScreenshare", "err", err, "user_id", userID)
|
||||
return fmt.Errorf("%w: failed to update screenshare state", ErrInternal)
|
||||
}
|
||||
|
||||
slog.Debug("voice screenshare changed", "user_id", userID, "enabled", enable, "channel_id", channelID)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user