Add a server-side instance_settings table (single-row, CHECK(id=1)) that stores admin-configurable streaming bounds: bitrate min/max/step, allowed resolutions, and allowed framerates. Backend: - New instance_settings schema + migrations (is_admin on users, default settings row, first-registered-user promoted to admin) - GET/PATCH /api/settings/streaming endpoints with admin-only writes and full input validation including cross-field checks Frontend: - settingsStore fetches limits on WebSocket ready, exposes isAdmin flag - ScreenShareSettingsPopover reads bounds from store instead of hardcoded constants, auto-clamps stale localStorage values - buildScreenShareOptions() clamps bitrate to server limits at build time as enforcement backstop - ServerSettings modal gains a "Streaming" tab (admin-only) with bitrate range sliders, resolution/framerate toggles, and save/reset
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { create } from 'zustand';
|
|
import type { InstanceStreamingLimits } from '@opencord/shared';
|
|
import { api } from '../api/client';
|
|
|
|
interface SettingsState {
|
|
streamingLimits: InstanceStreamingLimits | null;
|
|
isAdmin: boolean;
|
|
fetchStreamingLimits: () => Promise<void>;
|
|
updateStreamingLimits: (limits: Partial<InstanceStreamingLimits>) => Promise<void>;
|
|
setIsAdmin: (isAdmin: boolean) => void;
|
|
}
|
|
|
|
const DEFAULT_LIMITS: InstanceStreamingLimits = {
|
|
maxBitrateKbps: 20000,
|
|
minBitrateKbps: 500,
|
|
bitrateStepKbps: 500,
|
|
allowedResolutions: [540, 720, 1080],
|
|
allowedFramerates: [30, 45, 60],
|
|
maxResolution: 1080,
|
|
maxFramerate: 60,
|
|
};
|
|
|
|
export function getStreamingLimits(): InstanceStreamingLimits {
|
|
return useSettingsStore.getState().streamingLimits ?? DEFAULT_LIMITS;
|
|
}
|
|
|
|
export const useSettingsStore = create<SettingsState>((set) => ({
|
|
streamingLimits: null,
|
|
isAdmin: false,
|
|
|
|
fetchStreamingLimits: async () => {
|
|
try {
|
|
const limits = await api.settings.getStreaming();
|
|
set({ streamingLimits: limits });
|
|
} catch (err) {
|
|
console.warn('[Settings] Failed to fetch streaming limits, using defaults:', err);
|
|
set({ streamingLimits: DEFAULT_LIMITS });
|
|
}
|
|
},
|
|
|
|
updateStreamingLimits: async (limits: Partial<InstanceStreamingLimits>) => {
|
|
const updated = await api.settings.updateStreaming(limits);
|
|
set({ streamingLimits: updated });
|
|
},
|
|
|
|
setIsAdmin: (isAdmin: boolean) => set({ isAdmin }),
|
|
}));
|