diff --git a/frontend/public/assets/i18n/en_common.json b/frontend/public/assets/i18n/en_common.json index add50efa1..bfc62ecc9 100644 --- a/frontend/public/assets/i18n/en_common.json +++ b/frontend/public/assets/i18n/en_common.json @@ -85,7 +85,10 @@ "XTREAM_CODES": "xtream codes", "XC": "xc", "M3U": "m3u", - "PLAYLIST_BROWSER": "Playlist Browser" + "PLAYLIST_BROWSER": "Playlist Browser", + "RATE_LIMIT": "Rate Limit", + "PERIOD_MILLIS": "Period Millis", + "BURST_SIZE": "Burst Size" }, "TITLE": { "USER_BOUQUET_EDITOR": "User group editor" diff --git a/frontend/src/component/form-view/from-view.tsx b/frontend/src/component/form-view/from-view.tsx index 74295455b..b0ad37ae3 100644 --- a/frontend/src/component/form-view/from-view.tsx +++ b/frontend/src/component/form-view/from-view.tsx @@ -64,7 +64,15 @@ export default function FormView(props: FormViewProps) { const handleInputValueChange = useCallback((evt: any) => { const field = evt.target.dataset.field; - const value = evt.target.value; + let value = evt.target.value; + for (const fieldDef of fields) { + if (fieldDef.name === field) { + if (fieldDef.fieldType === FormFieldType.NUMBER) { + value = parseInt(value); + } + } + } + if (data) { data[field] = value; } diff --git a/frontend/src/component/main-config-view/main-config-view.tsx b/frontend/src/component/main-config-view/main-config-view.tsx index fe6abb7d2..b945f2d3d 100644 --- a/frontend/src/component/main-config-view/main-config-view.tsx +++ b/frontend/src/component/main-config-view/main-config-view.tsx @@ -4,7 +4,7 @@ import ServerConfig, { CacheConfig, LogConfig, MessagingConfig, - PushoverConfig, + PushoverConfig, RateLimitConfig, RestConfig, ReverseProxyConfig, ServerApiConfig, @@ -72,9 +72,14 @@ const CONFIG_REVERSE_PROXY_STREAM_BUFFER_FIELDS = [ const CONFIG_REVERSE_PROXY_CACHE_FIELDS = [ {name: 'enabled', label: 'LABEL.ENABLED', fieldType: FormFieldType.CHECK}, {name: 'size', label: 'LABEL.SIZE', fieldType: FormFieldType.TEXT}, - {name: 'sir', label: 'LABEL.CACHE_DIR', fieldType: FormFieldType.TEXT}, + {name: 'dir', label: 'LABEL.CACHE_DIR', fieldType: FormFieldType.TEXT}, ]; +const CONFIG_REVERSE_PROXY_RATE_LIMIT_FIELDS = [ + {name: 'enabled', label: 'LABEL.ENABLED', fieldType: FormFieldType.CHECK}, + {name: 'period_millis', label: 'LABEL.PERIOD_MILLIS', fieldType: FormFieldType.NUMBER}, + {name: 'burst_size', label: 'LABEL.BURST_SIZE', fieldType: FormFieldType.NUMBER}, +]; const CONFIG_MESSAGING_FIELDS = [ { @@ -147,6 +152,7 @@ export default function MainConfigView(props: MainConfigViewProps) { const reverseProxyStreamConfig = useMemo(() => config?.reverse_proxy?.stream || {} as any, [config]); const reverseProxyStreamBufferConfig = useMemo(() => config?.reverse_proxy?.stream?.buffer || {} as any, [config]); const reverseProxyCacheConfig = useMemo(() => config?.reverse_proxy?.cache || {} as any, [config]); + const reverseProxyRateLimitConfig = useMemo(() => config?.reverse_proxy?.rate_limit || {} as any, [config]); const logConfig = useMemo(() => config?.log || {} as any, [config]); const configs = useMemo(() => { const translations: any = { @@ -158,6 +164,7 @@ export default function MainConfigView(props: MainConfigViewProps) { reverse_proxy_stream_fields: translateLabels(CONFIG_REVERSE_PROXY_STREAM_FIELDS, translate), reverse_proxy_stream_buffer_fields: translateLabels(CONFIG_REVERSE_PROXY_STREAM_BUFFER_FIELDS, translate), reverse_proxy_cache_fields: translateLabels(CONFIG_REVERSE_PROXY_CACHE_FIELDS, translate), + reverse_proxy_rate_limit_fields: translateLabels(CONFIG_REVERSE_PROXY_RATE_LIMIT_FIELDS, translate), messaging_fields: translateLabels(CONFIG_MESSAGING_FIELDS, translate), telegram_fields: translateLabels(CONFIG_TELEGRAM_FIELDS, translate), rest_fields: translateLabels(CONFIG_REST_FIELDS, translate), @@ -200,6 +207,7 @@ export default function MainConfigView(props: MainConfigViewProps) { resource_rewrite_disabled: reverseProxyConfig.resource_rewrite_disabled, stream: cfgReverseProxyStreamBuffer ?? undefined, cache: reverseProxyCacheConfig ?? undefined, + rate_limit: reverseProxyRateLimitConfig ?? undefined, }; const cfgVideo = { @@ -234,7 +242,7 @@ export default function MainConfigView(props: MainConfigViewProps) { } }, [mainConfig, apiConfig, videoConfig, messagingConfig, telegramConfig, restConfig, pushoverConfig, videoDownloadConfig, reverseProxyConfig, enqueueSnackbar, services, logConfig, - reverseProxyCacheConfig, reverseProxyStreamConfig, reverseProxyStreamBufferConfig, + reverseProxyRateLimitConfig, reverseProxyCacheConfig, reverseProxyStreamConfig, reverseProxyStreamBufferConfig, translate]); const handleTabChange = useCallback((tab: string) => { @@ -277,6 +285,8 @@ export default function MainConfigView(props: MainConfigViewProps) { fields={configs.reverse_proxy_stream_buffer_fields}> + +
diff --git a/frontend/src/model/server-config.ts b/frontend/src/model/server-config.ts index b5bc048a8..f686118f7 100644 --- a/frontend/src/model/server-config.ts +++ b/frontend/src/model/server-config.ts @@ -203,9 +203,15 @@ export interface CacheConfig { dir?: string, } +export interface RateLimitConfig { + enabled: boolean, + period_millis: number, + burst_size: number, +} export interface ReverseProxyConfig { stream?: StreamConfig, cache?: CacheConfig, + rate_limit?: RateLimitConfig, resource_rewrite_disabled: boolean, } diff --git a/src/model/config.rs b/src/model/config.rs index 7e8bf96ca..b9f00653a 100644 --- a/src/model/config.rs +++ b/src/model/config.rs @@ -1193,7 +1193,6 @@ impl StreamConfig { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(deny_unknown_fields)] pub struct RateLimitConfig { - #[serde(default)] pub enabled: bool, pub period_millis: u64, pub burst_size: u32,