velconnect v3 ---- GO!
parent
2555c3082f
commit
a9c74cb4ac
|
|
@ -15,6 +15,6 @@ jobs:
|
||||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
|
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
|
||||||
- name: connect and pull
|
- name: connect and pull
|
||||||
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd /home/ubuntu/VEL-Connect-PB/velconnect && git pull && docker compose up -d --build --remove-orphans && exit"
|
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd /home/ubuntu/VEL-Connect-v2/velconnect && git pull && docker compose up -d --build && exit"
|
||||||
- name: cleanup
|
- name: cleanup
|
||||||
run: rm -rf ~/.ssh
|
run: rm -rf ~/.ssh
|
||||||
|
|
@ -15,7 +15,7 @@ jobs:
|
||||||
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
|
ssh-keyscan -H ${{ secrets.SSH_HOST }} > ~/.ssh/known_hosts
|
||||||
- name: connect and pull
|
- name: connect and pull
|
||||||
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd ${{ secrets.SSH_WORK_DIR }}/../VEL-Connect-PB && git pull && docker compose up -d --build && exit"
|
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "cd /home/ubuntu/VEL-Connect-v3/velconnect && git pull && docker compose up -d --build && exit"
|
||||||
- name: cleanup
|
- name: cleanup
|
||||||
run: rm -rf ~/.ssh
|
run: rm -rf ~/.ssh
|
||||||
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import { type Record } from 'pocketbase';
|
import { type Record } from 'pocketbase';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
|
||||||
export const pb = new PocketBase('http://127.0.0.1:8090');
|
export const pb = new PocketBase('http://127.0.0.1:8090');
|
||||||
|
|
||||||
|
|
@ -11,8 +12,7 @@ pb.authStore.onChange((auth) => {
|
||||||
currentUser.set(pb.authStore.model);
|
currentUser.set(pb.authStore.model);
|
||||||
});
|
});
|
||||||
|
|
||||||
let pairedDevicesInit: string[] = [];
|
export const pairedDevices = writable<string[]>([]);
|
||||||
export const pairedDevices = writable(pairedDevicesInit);
|
|
||||||
export const currentDevice = writable('');
|
export const currentDevice = writable('');
|
||||||
|
|
||||||
interface HasData extends Record {
|
interface HasData extends Record {
|
||||||
|
|
@ -24,3 +24,129 @@ export interface DeviceData extends Record {
|
||||||
data: { [key: string]: string };
|
data: { [key: string]: string };
|
||||||
}
|
}
|
||||||
export interface RoomData extends HasData {}
|
export interface RoomData extends HasData {}
|
||||||
|
|
||||||
|
const device = get(currentDevice);
|
||||||
|
if (device == '' && device.length > 0) {
|
||||||
|
currentDevice.set(device[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let unsubscribeDeviceData: () => void;
|
||||||
|
let unsubscribeRoomData: () => void;
|
||||||
|
let unsubscribeCurrentDevice: () => void;
|
||||||
|
let unsubscribeCurrentUser: () => void;
|
||||||
|
|
||||||
|
export let deviceData = writable<DeviceData | null>(null);
|
||||||
|
export let roomData = writable<RoomData | null>(null);
|
||||||
|
|
||||||
|
export let sending = false;
|
||||||
|
|
||||||
|
export async function startListening() {
|
||||||
|
if (get(currentDevice) != '') {
|
||||||
|
deviceData = await pb.collection('Device').getOne(get(currentDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsubscribeCurrentDevice = currentDevice.subscribe(async (val) => {
|
||||||
|
console.log('current device changed');
|
||||||
|
unsubscribeDeviceData?.();
|
||||||
|
if (val != '') {
|
||||||
|
const d = (await pb.collection('Device').getOne(get(currentDevice))) as DeviceData;
|
||||||
|
deviceData.set(d);
|
||||||
|
if (d != null) getRoomData(d);
|
||||||
|
unsubscribeDeviceData = await pb.collection('Device').subscribe(val, async (data) => {
|
||||||
|
const d = data.record as DeviceData;
|
||||||
|
deviceData.set(d);
|
||||||
|
getRoomData(d);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
deviceData.set(null);
|
||||||
|
roomData.set(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
unsubscribeCurrentUser = currentUser.subscribe((user) => {
|
||||||
|
pairedDevices.set(user?.devices ?? []);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stopListening() {
|
||||||
|
unsubscribeCurrentDevice?.();
|
||||||
|
unsubscribeDeviceData?.();
|
||||||
|
unsubscribeRoomData?.();
|
||||||
|
unsubscribeCurrentUser?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getRoomData(deviceData: DeviceData) {
|
||||||
|
unsubscribeRoomData?.();
|
||||||
|
|
||||||
|
// create or just fetch room by name
|
||||||
|
const r = await fetch(
|
||||||
|
`${pb.baseUrl}/data_block/${deviceData.current_app}_${deviceData.current_room}`,
|
||||||
|
{
|
||||||
|
method: 'POST'
|
||||||
|
}
|
||||||
|
).then((r) => r.json());
|
||||||
|
roomData.set(r);
|
||||||
|
if (r) {
|
||||||
|
unsubscribeDeviceData = await pb.collection('DataBlock').subscribe(r.id, (data) => {
|
||||||
|
roomData.set(data.record as RoomData);
|
||||||
|
unsubscribeRoomData?.();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('Failed to get or create room');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let abortController = new AbortController();
|
||||||
|
export function delayedSend() {
|
||||||
|
console.log('fn: delayedSend()');
|
||||||
|
|
||||||
|
// abort the previous send
|
||||||
|
abortController.abort();
|
||||||
|
const newAbortController = new AbortController();
|
||||||
|
abortController = newAbortController;
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!newAbortController.signal.aborted) {
|
||||||
|
send();
|
||||||
|
} else {
|
||||||
|
console.log('aborted');
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function send() {
|
||||||
|
console.log('sending...');
|
||||||
|
sending = true;
|
||||||
|
let promises = [];
|
||||||
|
const r = get(roomData);
|
||||||
|
const d = get(deviceData);
|
||||||
|
if (d) {
|
||||||
|
promises.push(pb.collection('Device').update(d.id, d));
|
||||||
|
}
|
||||||
|
if (r) {
|
||||||
|
promises.push(pb.collection('DataBlock').update(r.id, r));
|
||||||
|
}
|
||||||
|
Promise.all(promises).then(() => {
|
||||||
|
sending = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeDevice(d: string) {
|
||||||
|
pairedDevices.set(get(pairedDevices).filter((i) => i != d));
|
||||||
|
|
||||||
|
if (get(currentDevice) == d) {
|
||||||
|
console.log('Removed current device');
|
||||||
|
|
||||||
|
// if there are still devices left
|
||||||
|
if (get(pairedDevices).length > 0) {
|
||||||
|
currentDevice.set(get(pairedDevices)[0]);
|
||||||
|
} else {
|
||||||
|
currentDevice.set('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = get(currentUser);
|
||||||
|
if (user) {
|
||||||
|
user.devices.filter((i: string) => i != d);
|
||||||
|
pb.collection('Users').update(user.id, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,141 +1,26 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy, onMount } from 'svelte';
|
|
||||||
import {
|
import {
|
||||||
currentDevice,
|
currentDevice,
|
||||||
type DeviceData,
|
delayedSend,
|
||||||
|
deviceData,
|
||||||
pairedDevices,
|
pairedDevices,
|
||||||
pb,
|
removeDevice,
|
||||||
type RoomData,
|
roomData,
|
||||||
currentUser
|
sending,
|
||||||
|
startListening,
|
||||||
|
stopListening
|
||||||
} from '$lib/js/velconnect';
|
} from '$lib/js/velconnect';
|
||||||
import Login from '$lib/components/Login.svelte';
|
import Login from '$lib/components/Login.svelte';
|
||||||
import Pair from '$lib/components/Pair.svelte';
|
import Pair from '$lib/components/Pair.svelte';
|
||||||
import { prettyDate } from '$lib/js/util';
|
import { prettyDate } from '$lib/js/util';
|
||||||
|
import { onDestroy, onMount } from 'svelte';
|
||||||
if ($currentDevice == '' && $pairedDevices.length > 0) {
|
|
||||||
currentDevice.set($pairedDevices[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let unsubscribeDeviceData: () => void;
|
|
||||||
let unsubscribeRoomData: () => void;
|
|
||||||
let unsubscribeCurrentDevice: () => void;
|
|
||||||
let unsubscribeCurrentUser: () => void;
|
|
||||||
|
|
||||||
let deviceData: DeviceData | null;
|
|
||||||
let roomData: RoomData | null;
|
|
||||||
|
|
||||||
let sending = false;
|
|
||||||
|
|
||||||
$: deviceData,
|
|
||||||
() => {
|
|
||||||
console.log('Device data changed');
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if ($currentDevice != '') {
|
await startListening();
|
||||||
deviceData = await pb.collection('Device').getOne($currentDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsubscribeCurrentDevice = currentDevice.subscribe(async (val) => {
|
|
||||||
console.log('current device changed');
|
|
||||||
unsubscribeDeviceData?.();
|
|
||||||
if (val != '') {
|
|
||||||
deviceData = await pb.collection('Device').getOne($currentDevice);
|
|
||||||
if (deviceData != null) getRoomData(deviceData);
|
|
||||||
unsubscribeDeviceData = await pb.collection('Device').subscribe(val, async (data) => {
|
|
||||||
deviceData = data.record as DeviceData;
|
|
||||||
getRoomData(deviceData);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
deviceData = null;
|
|
||||||
roomData = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
unsubscribeCurrentUser = currentUser.subscribe((user) => {
|
|
||||||
pairedDevices.set(user?.devices ?? []);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
unsubscribeCurrentDevice?.();
|
stopListening();
|
||||||
unsubscribeDeviceData?.();
|
|
||||||
unsubscribeRoomData?.();
|
|
||||||
unsubscribeCurrentUser?.();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getRoomData(deviceData: DeviceData) {
|
|
||||||
// get room data
|
|
||||||
unsubscribeRoomData?.();
|
|
||||||
// create or just fetch room by name
|
|
||||||
roomData = await fetch(
|
|
||||||
`${pb.baseUrl}/data_block/${deviceData.current_app}_${deviceData.current_room}`,
|
|
||||||
{
|
|
||||||
method: 'POST'
|
|
||||||
}
|
|
||||||
).then((r) => r.json());
|
|
||||||
console.log(roomData);
|
|
||||||
if (roomData) {
|
|
||||||
unsubscribeDeviceData = await pb.collection('DataBlock').subscribe(roomData.id, (data) => {
|
|
||||||
roomData = data.record as RoomData;
|
|
||||||
unsubscribeRoomData?.();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.error('Failed to get or create room');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let abortController = new AbortController();
|
|
||||||
function delayedSend() {
|
|
||||||
console.log('fn: delayedSend()');
|
|
||||||
|
|
||||||
// abort the previous send
|
|
||||||
abortController.abort();
|
|
||||||
const newAbortController = new AbortController();
|
|
||||||
abortController = newAbortController;
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!newAbortController.signal.aborted) {
|
|
||||||
send();
|
|
||||||
} else {
|
|
||||||
console.log('aborted');
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function send() {
|
|
||||||
console.log('sending...');
|
|
||||||
sending = true;
|
|
||||||
let promises = [];
|
|
||||||
if (deviceData) {
|
|
||||||
promises.push(pb.collection('Device').update(deviceData.id, deviceData));
|
|
||||||
}
|
|
||||||
if (roomData) {
|
|
||||||
promises.push(pb.collection('DataBlock').update(roomData.id, roomData));
|
|
||||||
}
|
|
||||||
Promise.all(promises).then(() => {
|
|
||||||
sending = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeDevice(d: string) {
|
|
||||||
pairedDevices.set($pairedDevices.filter((i) => i != d));
|
|
||||||
|
|
||||||
if ($currentDevice == d) {
|
|
||||||
console.log('Removed current device');
|
|
||||||
|
|
||||||
// if there are still devices left
|
|
||||||
if ($pairedDevices.length > 0) {
|
|
||||||
currentDevice.set($pairedDevices[0]);
|
|
||||||
} else {
|
|
||||||
currentDevice.set('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($currentUser) {
|
|
||||||
$currentUser.devices.filter((i: string) => i != d);
|
|
||||||
pb.collection('Users').update($currentUser.id, $currentUser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|
@ -182,25 +67,25 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if deviceData != null && deviceData.data != null}
|
{#if $deviceData != null && $deviceData.data != null}
|
||||||
<div>
|
<div>
|
||||||
<h3>Device Info</h3>
|
<h3>Device Info</h3>
|
||||||
|
|
||||||
<device-field>
|
<device-field>
|
||||||
<h6>Device ID:</h6>
|
<h6>Device ID:</h6>
|
||||||
<code>{deviceData.id}</code>
|
<code>{$deviceData.id}</code>
|
||||||
</device-field>
|
</device-field>
|
||||||
<device-field>
|
<device-field>
|
||||||
<h6>Pairing Code:</h6>
|
<h6>Pairing Code:</h6>
|
||||||
<code>{deviceData.pairing_code}</code>
|
<code>{$deviceData.pairing_code}</code>
|
||||||
</device-field>
|
</device-field>
|
||||||
<device-field>
|
<device-field>
|
||||||
<h6>First Seen</h6>
|
<h6>First Seen</h6>
|
||||||
<p>{prettyDate(deviceData.created)}</p>
|
<p>{prettyDate($deviceData.created)}</p>
|
||||||
</device-field>
|
</device-field>
|
||||||
<device-field>
|
<device-field>
|
||||||
<h6>Last Seen</h6>
|
<h6>Last Seen</h6>
|
||||||
<p>{prettyDate(deviceData.updated)}</p>
|
<p>{prettyDate($deviceData.updated)}</p>
|
||||||
</device-field>
|
</device-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -212,7 +97,7 @@
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter username..."
|
placeholder="Enter username..."
|
||||||
bind:value={deviceData.friendly_name}
|
bind:value={$deviceData.friendly_name}
|
||||||
on:input={delayedSend}
|
on:input={delayedSend}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -231,14 +116,14 @@
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="https://----.glb"
|
placeholder="https://----.glb"
|
||||||
bind:value={deviceData.data.avatar_url}
|
bind:value={$deviceData.data.avatar_url}
|
||||||
on:input={delayedSend}
|
on:input={delayedSend}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<device-field>
|
<device-field>
|
||||||
<h6>Current Room</h6>
|
<h6>Current Room</h6>
|
||||||
<a href="/join/{deviceData.current_app}/room_name" target="blank">
|
<a href="/join/{$deviceData.current_app}/room_name" target="blank">
|
||||||
Shareable Link
|
Shareable Link
|
||||||
<svg style="width:1em;height:1em;margin-bottom:-.15em;" viewBox="0 0 24 24">
|
<svg style="width:1em;height:1em;margin-bottom:-.15em;" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
|
|
@ -250,7 +135,7 @@
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="room_1"
|
placeholder="room_1"
|
||||||
bind:value={deviceData.current_room}
|
bind:value={$deviceData.current_room}
|
||||||
on:input={delayedSend}
|
on:input={delayedSend}
|
||||||
/>
|
/>
|
||||||
</device-field>
|
</device-field>
|
||||||
|
|
@ -258,9 +143,9 @@
|
||||||
|
|
||||||
<h3>Raw JSON:</h3>
|
<h3>Raw JSON:</h3>
|
||||||
<h6>Device Data</h6>
|
<h6>Device Data</h6>
|
||||||
<pre><code>{JSON.stringify(deviceData, null, 2)}</code></pre>
|
<pre><code>{JSON.stringify($deviceData, null, 2)}</code></pre>
|
||||||
<h6>Room Data</h6>
|
<h6>Room Data</h6>
|
||||||
<pre><code>{JSON.stringify(roomData, null, 2)}</code></pre>
|
<pre><code>{JSON.stringify($roomData, null, 2)}</code></pre>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
version: "2.0"
|
version: "3.0"
|
||||||
services:
|
services:
|
||||||
server:
|
server:
|
||||||
build: .
|
build: .
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue