feat: sending wake packets, closes #10

This commit is contained in:
axel 2025-04-19 21:54:58 +02:00
parent f1143551d6
commit 96d2696e17
5 changed files with 81 additions and 36 deletions

View File

@ -34,7 +34,7 @@
}}
>
{#if data.Icon}
<data.Icon class="sm:-ml-2 {data.spin ? 'animate-spin' : ''}" />
<data.Icon class="-ml-2 {data.spin ? 'animate-spin' : ''} w-5 sm:w-auto" />
{/if}
<p role="alert">{data.content}</p>
{#if data.dismissable}

View File

@ -1,9 +1,10 @@
<script lang="ts">
import { enhance } from '$app/forms';
import { Button } from 'bits-ui';
import IconEdit from '~icons/tabler/edit';
import IconPlay from '~icons/tabler/player-play';
let { title, subtitle, editHref = null, wakePost = null } = $props();
let { title, subtitle, editHref = null, wakeId = null } = $props();
</script>
<div
@ -25,13 +26,16 @@
</Button.Root>
{/if}
{#if wakePost}
{#if wakeId}
<form use:enhance method="POST" action="?/wake">
<input type="hidden" name="id" value={wakeId} />
<Button.Root
class="bg-emerald-600 hover:bg-emerald-800 transition-all duration-300 ease-in-out
border border-emerald-500 rounded-full p-4 text-neutral-100 cursor-pointer"
>
<IconPlay />
</Button.Root>
</form>
{/if}
</div>
</div>

View File

@ -1,5 +1,7 @@
import { FORBIDDEN, SUCCESS } from '$lib/server/commonResponses';
import { users } from '$lib/server/db';
import type { ServerLoad } from '@sveltejs/kit';
import { fail, type Actions, type ServerLoad } from '@sveltejs/kit';
import { wake } from 'wake_on_lan';
export const load: ServerLoad = async ({ locals: { guard } }) => {
const user = guard.requiresAuth().orRedirects().getUser();
@ -7,3 +9,44 @@ export const load: ServerLoad = async ({ locals: { guard } }) => {
devices: await users.fetchDevices(user.id),
};
};
export const actions = {
wake: async ({ locals: { guard }, request }) => {
guard = guard.requiresAuth();
if (guard.isFailed()) return FORBIDDEN;
const deviceId = (await request.formData()).get('id');
const device = (await users.fetchDevices(guard.getUser().id)).find((d) => d.id === deviceId);
if (!device) {
return fail(404, { error: 'Could not find device.' });
}
console.log(
`Sending WOL packets to ${device.name} (${device.mac}) on ${guard.getUser().name}'s request.`,
);
const err = await new Promise<any>((resolve) => {
wake(
device.mac,
{
address: device.broadcast,
port: device.port,
num_packets: device.packets,
},
(err: any) => {
resolve(err);
},
);
});
if (err) {
console.error(err);
return fail(500, {
error: 'An error occured while trying to wake the device. Please see logs.',
});
}
return { ...SUCCESS, deviceName: device.name };
},
} satisfies Actions;

View File

@ -1,11 +1,31 @@
<script>
import { store } from '$lib/v2/globalStore.svelte.js';
import ListPage from '$lib/v2/snippets/ListPage.svelte';
import { Toast } from '$lib/v2/toast/notification.js';
import ResCard from '$lib/v2/ui/ResCard.svelte';
import { untrack } from 'svelte';
import IconCheck from '~icons/tabler/check';
import IconX from '~icons/tabler/x';
let { data } = $props();
let { data, form } = $props();
store.pageTitle = 'Listing all devices';
$effect(() => {
if (form?.error && !form.success) {
untrack(() => {
Toast.add({ Icon: IconX, content: form.error, theme: 'error' });
});
} else if (form?.success) {
untrack(() => {
Toast.add({
Icon: IconCheck,
content: `Sent magic packets to ${form.deviceName}.`,
theme: 'success',
});
});
}
});
</script>
<ListPage createHref={data.user.admin ? '/dash/devices/new' : null} msgAdd="Add Device">
@ -15,7 +35,7 @@
title={device.name}
subtitle={device.mac}
editHref={data.user.admin ? `/dash/devices/${device.id}` : null}
wakePost={`/dash/devices/${device.id}/wake`}
wakeId={device.id}
/>
{/each}
</div>

View File

@ -1,9 +1,8 @@
import { FORBIDDEN, PARSE_ERROR, SUCCESS } from '$lib/server/commonResponses';
import { devices, users } from '$lib/server/db/index.js';
import { fail, redirect, type Actions, type ServerLoad } from '@sveltejs/kit';
import { devices } from '$lib/server/db/index.js';
import { redirect, type Actions, type ServerLoad } from '@sveltejs/kit';
import { decode } from 'decode-formdata';
import validator from 'validator';
import { wake } from 'wake_on_lan';
import { z } from 'zod';
export const load: ServerLoad = async ({ locals: { guard }, params }) => {
@ -65,25 +64,4 @@ export const actions = {
const err = await devices.delete(params.id ?? '');
return err ? err.toFail() : SUCCESS;
},
wake: async ({ params, locals: { guard } }) => {
guard = guard.requiresAuth();
if (guard.isFailed()) return FORBIDDEN;
const device = (await users.fetchDevices(guard.getUser().id)).find((d) => d.id === params.id);
if (!device) {
return fail(404);
}
console.log('Trying to wake ' + device.name);
wake(device.mac, {
address: device.broadcast,
port: device.port,
num_packets: device.packets,
});
return SUCCESS;
},
} satisfies Actions;