feat: sending wake packets, closes #10
This commit is contained in:
parent
f1143551d6
commit
96d2696e17
@ -34,7 +34,7 @@
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#if data.Icon}
|
{#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}
|
{/if}
|
||||||
<p role="alert">{data.content}</p>
|
<p role="alert">{data.content}</p>
|
||||||
{#if data.dismissable}
|
{#if data.dismissable}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
import { Button } from 'bits-ui';
|
import { Button } from 'bits-ui';
|
||||||
import IconEdit from '~icons/tabler/edit';
|
import IconEdit from '~icons/tabler/edit';
|
||||||
import IconPlay from '~icons/tabler/player-play';
|
import IconPlay from '~icons/tabler/player-play';
|
||||||
|
|
||||||
let { title, subtitle, editHref = null, wakePost = null } = $props();
|
let { title, subtitle, editHref = null, wakeId = null } = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -25,13 +26,16 @@
|
|||||||
</Button.Root>
|
</Button.Root>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if wakePost}
|
{#if wakeId}
|
||||||
|
<form use:enhance method="POST" action="?/wake">
|
||||||
|
<input type="hidden" name="id" value={wakeId} />
|
||||||
<Button.Root
|
<Button.Root
|
||||||
class="bg-emerald-600 hover:bg-emerald-800 transition-all duration-300 ease-in-out
|
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"
|
border border-emerald-500 rounded-full p-4 text-neutral-100 cursor-pointer"
|
||||||
>
|
>
|
||||||
<IconPlay />
|
<IconPlay />
|
||||||
</Button.Root>
|
</Button.Root>
|
||||||
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import { FORBIDDEN, SUCCESS } from '$lib/server/commonResponses';
|
||||||
import { users } from '$lib/server/db';
|
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 } }) => {
|
export const load: ServerLoad = async ({ locals: { guard } }) => {
|
||||||
const user = guard.requiresAuth().orRedirects().getUser();
|
const user = guard.requiresAuth().orRedirects().getUser();
|
||||||
@ -7,3 +9,44 @@ export const load: ServerLoad = async ({ locals: { guard } }) => {
|
|||||||
devices: await users.fetchDevices(user.id),
|
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;
|
||||||
|
|||||||
@ -1,11 +1,31 @@
|
|||||||
<script>
|
<script>
|
||||||
import { store } from '$lib/v2/globalStore.svelte.js';
|
import { store } from '$lib/v2/globalStore.svelte.js';
|
||||||
import ListPage from '$lib/v2/snippets/ListPage.svelte';
|
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 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';
|
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>
|
</script>
|
||||||
|
|
||||||
<ListPage createHref={data.user.admin ? '/dash/devices/new' : null} msgAdd="Add Device">
|
<ListPage createHref={data.user.admin ? '/dash/devices/new' : null} msgAdd="Add Device">
|
||||||
@ -15,7 +35,7 @@
|
|||||||
title={device.name}
|
title={device.name}
|
||||||
subtitle={device.mac}
|
subtitle={device.mac}
|
||||||
editHref={data.user.admin ? `/dash/devices/${device.id}` : null}
|
editHref={data.user.admin ? `/dash/devices/${device.id}` : null}
|
||||||
wakePost={`/dash/devices/${device.id}/wake`}
|
wakeId={device.id}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { FORBIDDEN, PARSE_ERROR, SUCCESS } from '$lib/server/commonResponses';
|
import { FORBIDDEN, PARSE_ERROR, SUCCESS } from '$lib/server/commonResponses';
|
||||||
import { devices, users } from '$lib/server/db/index.js';
|
import { devices } from '$lib/server/db/index.js';
|
||||||
import { fail, redirect, type Actions, type ServerLoad } from '@sveltejs/kit';
|
import { redirect, type Actions, type ServerLoad } from '@sveltejs/kit';
|
||||||
import { decode } from 'decode-formdata';
|
import { decode } from 'decode-formdata';
|
||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
import { wake } from 'wake_on_lan';
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const load: ServerLoad = async ({ locals: { guard }, params }) => {
|
export const load: ServerLoad = async ({ locals: { guard }, params }) => {
|
||||||
@ -65,25 +64,4 @@ export const actions = {
|
|||||||
const err = await devices.delete(params.id ?? '');
|
const err = await devices.delete(params.id ?? '');
|
||||||
return err ? err.toFail() : SUCCESS;
|
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;
|
} satisfies Actions;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user