mirror of
https://github.com/immich-app/yucca.git
synced 2026-09-30 13:33:00 +08:00
feat(yucca sdk): freeform bandwidth limit (#713)
This commit is contained in:
+13
-20
@@ -5,7 +5,7 @@
|
||||
defaultQuietHoursStart,
|
||||
toBandwidthDto,
|
||||
toBandwidthForm,
|
||||
unlimitedBandwidth,
|
||||
toBytesPerSec,
|
||||
useConfig,
|
||||
useUpdateConfig,
|
||||
} from "$lib/services/config.service";
|
||||
@@ -14,6 +14,7 @@
|
||||
Field,
|
||||
HStack,
|
||||
LoadingSpinner,
|
||||
NumberInput,
|
||||
Select,
|
||||
Stack,
|
||||
Switch,
|
||||
@@ -21,16 +22,6 @@
|
||||
} from "@immich/ui";
|
||||
import { mdiSpeedometerSlow } from "@mdi/js";
|
||||
|
||||
const bytesPerMegabyte = 1_000_000;
|
||||
|
||||
const speeds = [
|
||||
{ value: unlimitedBandwidth, label: "No limit" },
|
||||
...[0.5, 1, 2, 5, 10, 20, 50, 100].map((megabytes) => ({
|
||||
value: String(megabytes * bytesPerMegabyte),
|
||||
label: `${megabytes} MB/s`,
|
||||
})),
|
||||
];
|
||||
|
||||
const hours = Array.from({ length: 24 }, (_, hour) => ({
|
||||
value: `${String(hour).padStart(2, "0")}:00`,
|
||||
label: `${String(hour).padStart(2, "0")}:00`,
|
||||
@@ -39,7 +30,7 @@
|
||||
const config = useConfig();
|
||||
const mutation = useUpdateConfig();
|
||||
|
||||
let speed = $state(unlimitedBandwidth);
|
||||
let mbps = $state<number>();
|
||||
let quiet = $state(false);
|
||||
let quietStart = $state(defaultQuietHoursStart);
|
||||
let quietEnd = $state(defaultQuietHoursEnd);
|
||||
@@ -50,7 +41,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
({ speed, quiet, quietStart, quietEnd } = toBandwidthForm(
|
||||
({ mbps, quiet, quietStart, quietEnd } = toBandwidthForm(
|
||||
config.data.bandwidth,
|
||||
));
|
||||
};
|
||||
@@ -64,11 +55,11 @@
|
||||
load();
|
||||
});
|
||||
|
||||
const limited = $derived(speed !== unlimitedBandwidth);
|
||||
const limited = $derived(toBytesPerSec(mbps) > 0);
|
||||
|
||||
const onSave = () => {
|
||||
mutation.mutate({
|
||||
bandwidth: toBandwidthDto({ speed, quiet, quietStart, quietEnd }),
|
||||
bandwidth: toBandwidthDto({ mbps, quiet, quietStart, quietEnd }),
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -84,13 +75,15 @@
|
||||
{:else}
|
||||
<Field
|
||||
label="Upload speed"
|
||||
description="Slow down backup uploads without affecting restores."
|
||||
description="Slow down backup uploads without affecting restores. Leave empty for no limit."
|
||||
color="primary"
|
||||
>
|
||||
<Select
|
||||
options={speeds}
|
||||
value={speed}
|
||||
onChange={(value) => (speed = value)}
|
||||
<NumberInput
|
||||
bind:value={mbps}
|
||||
min={0}
|
||||
step={1}
|
||||
placeholder="No limit"
|
||||
trailingText="Mbps"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('toBandwidthForm', () => {
|
||||
expect(
|
||||
toBandwidthForm({ bytesPerSec: 5_000_000, quietHours: '23:00-07:00' }),
|
||||
).toEqual({
|
||||
speed: '5000000',
|
||||
mbps: 40,
|
||||
quiet: true,
|
||||
quietStart: '23:00',
|
||||
quietEnd: '07:00',
|
||||
@@ -24,7 +24,7 @@ describe('toBandwidthForm', () => {
|
||||
|
||||
it('falls back to the default quiet hours when none are saved', () => {
|
||||
expect(toBandwidthForm({ bytesPerSec: 0 })).toEqual({
|
||||
speed: '0',
|
||||
mbps: undefined,
|
||||
quiet: false,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
@@ -33,10 +33,10 @@ describe('toBandwidthForm', () => {
|
||||
});
|
||||
|
||||
describe('toBandwidthDto', () => {
|
||||
it('converts the selected speed to bytes per second with quiet hours', () => {
|
||||
it('converts megabits per second to bytes per second with quiet hours', () => {
|
||||
expect(
|
||||
toBandwidthDto({
|
||||
speed: '500000',
|
||||
mbps: 4,
|
||||
quiet: true,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
@@ -47,7 +47,7 @@ describe('toBandwidthDto', () => {
|
||||
it('clears quiet hours when they are switched off', () => {
|
||||
expect(
|
||||
toBandwidthDto({
|
||||
speed: '2000000',
|
||||
mbps: 16,
|
||||
quiet: false,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
@@ -58,7 +58,18 @@ describe('toBandwidthDto', () => {
|
||||
it('disables the limit and drops quiet hours when set to no limit', () => {
|
||||
expect(
|
||||
toBandwidthDto({
|
||||
speed: '0',
|
||||
mbps: 0,
|
||||
quiet: true,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
}),
|
||||
).toEqual({ bytesPerSec: 0, quietHours: undefined });
|
||||
});
|
||||
|
||||
it('treats an empty speed as no limit', () => {
|
||||
expect(
|
||||
toBandwidthDto({
|
||||
mbps: undefined,
|
||||
quiet: true,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
@@ -87,7 +98,7 @@ describe('useUpdateConfig', () => {
|
||||
|
||||
useUpdateConfig().mutate({
|
||||
bandwidth: toBandwidthDto({
|
||||
speed: '1000000',
|
||||
mbps: 8,
|
||||
quiet: true,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
@@ -106,7 +117,7 @@ describe('useUpdateConfig', () => {
|
||||
|
||||
useUpdateConfig().mutate({
|
||||
bandwidth: toBandwidthDto({
|
||||
speed: '0',
|
||||
mbps: 0,
|
||||
quiet: true,
|
||||
quietStart: '22:00',
|
||||
quietEnd: '06:00',
|
||||
|
||||
@@ -12,12 +12,12 @@ export const configKeys = {
|
||||
all: ['config'] as const,
|
||||
};
|
||||
|
||||
export const unlimitedBandwidth = '0';
|
||||
const bytesPerSecPerMbps = 125_000;
|
||||
export const defaultQuietHoursStart = '22:00';
|
||||
export const defaultQuietHoursEnd = '06:00';
|
||||
|
||||
export type BandwidthForm = {
|
||||
speed: string;
|
||||
mbps?: number;
|
||||
quiet: boolean;
|
||||
quietStart: string;
|
||||
quietEnd: string;
|
||||
@@ -31,25 +31,29 @@ export const toBandwidthForm = ({
|
||||
quietHours?.split('-') ?? [];
|
||||
|
||||
return {
|
||||
speed: String(bytesPerSec),
|
||||
mbps: bytesPerSec ? bytesPerSec / bytesPerSecPerMbps : undefined,
|
||||
quiet: Boolean(quietHours),
|
||||
quietStart,
|
||||
quietEnd,
|
||||
};
|
||||
};
|
||||
|
||||
export const toBytesPerSec = (mbps = 0) =>
|
||||
Math.max(0, Math.ceil(mbps)) * bytesPerSecPerMbps;
|
||||
|
||||
export const toBandwidthDto = ({
|
||||
speed,
|
||||
mbps,
|
||||
quiet,
|
||||
quietStart,
|
||||
quietEnd,
|
||||
}: BandwidthForm): BandwidthDto => ({
|
||||
bytesPerSec: Number(speed),
|
||||
quietHours:
|
||||
speed !== unlimitedBandwidth && quiet
|
||||
? `${quietStart}-${quietEnd}`
|
||||
: undefined,
|
||||
});
|
||||
}: BandwidthForm): BandwidthDto => {
|
||||
const bytesPerSec = toBytesPerSec(mbps);
|
||||
|
||||
return {
|
||||
bytesPerSec,
|
||||
quietHours: bytesPerSec && quiet ? `${quietStart}-${quietEnd}` : undefined,
|
||||
};
|
||||
};
|
||||
|
||||
export const useConfig = () =>
|
||||
createQuery(
|
||||
|
||||
Reference in New Issue
Block a user