mostly getting device and rooms correctly
parent
c6670adec0
commit
2555c3082f
|
|
@ -8,6 +8,8 @@
|
|||
"name": "example-dashboard",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"humanize-duration": "^3.28.0",
|
||||
"luxon": "^3.3.0",
|
||||
"pocketbase": "^0.15.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -1802,6 +1804,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/humanize-duration": {
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.28.0.tgz",
|
||||
"integrity": "sha512-jMAxraOOmHuPbffLVDKkEKi/NeG8dMqP8lGRd6Tbf7JgAeG33jjgPWDbXXU7ypCI0o+oNKJFgbSB9FKVdWNI2A=="
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
|
|
@ -2034,6 +2041,14 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
|
||||
"integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
|
||||
|
|
@ -4383,6 +4398,11 @@
|
|||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"humanize-duration": {
|
||||
"version": "3.28.0",
|
||||
"resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.28.0.tgz",
|
||||
"integrity": "sha512-jMAxraOOmHuPbffLVDKkEKi/NeG8dMqP8lGRd6Tbf7JgAeG33jjgPWDbXXU7ypCI0o+oNKJFgbSB9FKVdWNI2A=="
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
|
|
@ -4563,6 +4583,11 @@
|
|||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"luxon": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
|
||||
"integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg=="
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.30.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
|
||||
|
|
|
|||
|
|
@ -21,16 +21,18 @@
|
|||
"eslint-plugin-svelte": "^2.30.0",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
"sass": "^1.63.6",
|
||||
"svelte": "^4.0.0",
|
||||
"svelte-check": "^3.4.3",
|
||||
"svelte-preprocess": "^5.0.4",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.3.6",
|
||||
"sass": "^1.63.6"
|
||||
"vite": "^4.3.6"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"humanize-duration": "^3.28.0",
|
||||
"luxon": "^3.3.0",
|
||||
"pocketbase": "^0.15.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicons/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { currentUser, pb } from '../velconnect';
|
||||
import { currentUser, pb } from '$lib/js/velconnect';
|
||||
|
||||
let email: string;
|
||||
let password: string;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { currentDevice, currentUser, pb, type Device, pairedDevices } from '../velconnect';
|
||||
import { currentDevice, currentUser, pb, type DeviceData, pairedDevices } from '$lib/js/velconnect';
|
||||
|
||||
let pairingCode: string;
|
||||
let errorMessage: string | null;
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
try {
|
||||
let device = (await pb
|
||||
.collection('Device')
|
||||
.getFirstListItem(`pairing_code="${pairingCode}"`)) as Device;
|
||||
.getFirstListItem(`pairing_code="${pairingCode}"`)) as DeviceData;
|
||||
|
||||
// add it to the local data
|
||||
currentDevice.set(device.id);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { DateTime } from 'luxon';
|
||||
import humanizeDuration from 'humanize-duration';
|
||||
|
||||
export function prettyDate(date: string | Date | DateTime, includeYear = false) {
|
||||
if (date == null) return '';
|
||||
|
||||
let d: DateTime;
|
||||
if (date instanceof Date) {
|
||||
d = DateTime.fromJSDate(date);
|
||||
} else if (date instanceof DateTime) {
|
||||
d = date;
|
||||
} else {
|
||||
date = date.replace(' ', 'T');
|
||||
d = DateTime.fromISO(date);
|
||||
}
|
||||
// return DateTime.fromISO(date).toFormat("yyyy-LL-dd hh:mm a ZZZZ");
|
||||
const fromNow = DateTime.utc().minus(d.toMillis()).toMillis();
|
||||
const yearReplace = includeYear ? '' : ', 2023';
|
||||
if (fromNow > 0) {
|
||||
return `${d.toLocaleString(DateTime.DATETIME_MED)} (${humanizeDuration(fromNow, {
|
||||
round: true,
|
||||
largest: 1
|
||||
})} ago)`.replaceAll(yearReplace, '');
|
||||
} else {
|
||||
return `${d.toLocaleString(DateTime.DATETIME_MED)} (in ${humanizeDuration(fromNow, {
|
||||
round: true,
|
||||
largest: 1
|
||||
})})`.replaceAll(yearReplace, '');
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ export const currentDevice = writable('');
|
|||
interface HasData extends Record {
|
||||
data: { [key: string]: string };
|
||||
}
|
||||
export interface Device extends Record {
|
||||
export interface DeviceData extends Record {
|
||||
current_room: string;
|
||||
current_app: string;
|
||||
data: { [key: string]: string };
|
||||
|
|
@ -2,23 +2,26 @@
|
|||
import { onDestroy, onMount } from 'svelte';
|
||||
import {
|
||||
currentDevice,
|
||||
type Device,
|
||||
type DeviceData,
|
||||
pairedDevices,
|
||||
pb,
|
||||
type RoomData,
|
||||
currentUser
|
||||
} from '../lib/velconnect';
|
||||
} from '$lib/js/velconnect';
|
||||
import Login from '$lib/components/Login.svelte';
|
||||
import Pair from '$lib/components/Pair.svelte';
|
||||
import { prettyDate } from '$lib/js/util';
|
||||
|
||||
if ($currentDevice == '' && $pairedDevices.length > 0) {
|
||||
currentDevice.set($pairedDevices[0]);
|
||||
}
|
||||
|
||||
let unsubscribeDeviceData: () => void;
|
||||
let unsubscribeRoomData: () => void;
|
||||
let unsubscribeCurrentDevice: () => void;
|
||||
let unsubscribeCurrentUser: () => void;
|
||||
|
||||
let deviceData: Device | null;
|
||||
let deviceData: DeviceData | null;
|
||||
let roomData: RoomData | null;
|
||||
|
||||
let sending = false;
|
||||
|
|
@ -38,21 +41,50 @@
|
|||
unsubscribeDeviceData?.();
|
||||
if (val != '') {
|
||||
deviceData = await pb.collection('Device').getOne($currentDevice);
|
||||
unsubscribeDeviceData = await pb.collection('Device').subscribe(val, (data) => {
|
||||
deviceData = data.record as Device;
|
||||
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(() => {
|
||||
unsubscribeCurrentDevice?.();
|
||||
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()');
|
||||
|
|
@ -106,6 +138,10 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>VEL-Connect</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1>VEL-Connect</h1>
|
||||
<img src="/img/velconnect_logo_1.png" alt="logo" width="70px" height="28px" />
|
||||
<p>
|
||||
|
|
@ -119,20 +155,22 @@
|
|||
|
||||
<div>
|
||||
<h3>Devices:</h3>
|
||||
{#each $pairedDevices as d}
|
||||
<div>
|
||||
<button
|
||||
on:click={() => {
|
||||
currentDevice.set(d);
|
||||
}}>{d}</button
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
removeDevice(d);
|
||||
}}>x</button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
<div class="device-list">
|
||||
{#each $pairedDevices as d}
|
||||
<div>
|
||||
<button
|
||||
on:click={() => {
|
||||
currentDevice.set(d);
|
||||
}}>{d}</button
|
||||
>
|
||||
<button
|
||||
on:click={() => {
|
||||
removeDevice(d);
|
||||
}}>x</button
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if $pairedDevices.length == 0}
|
||||
<p>No devices paired. Enter a pairing code above.</p>
|
||||
{/if}
|
||||
|
|
@ -158,11 +196,11 @@
|
|||
</device-field>
|
||||
<device-field>
|
||||
<h6>First Seen</h6>
|
||||
<p>{deviceData.created}</p>
|
||||
<p>{prettyDate(deviceData.created)}</p>
|
||||
</device-field>
|
||||
<device-field>
|
||||
<h6>Last Seen</h6>
|
||||
<p>{deviceData.updated}</p>
|
||||
<p>{prettyDate(deviceData.updated)}</p>
|
||||
</device-field>
|
||||
</div>
|
||||
|
||||
|
|
@ -218,8 +256,11 @@
|
|||
</device-field>
|
||||
</div>
|
||||
|
||||
<h6>Raw JSON:</h6>
|
||||
<h3>Raw JSON:</h3>
|
||||
<h6>Device Data</h6>
|
||||
<pre><code>{JSON.stringify(deviceData, null, 2)}</code></pre>
|
||||
<h6>Room Data</h6>
|
||||
<pre><code>{JSON.stringify(roomData, null, 2)}</code></pre>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
|
|
@ -232,4 +273,19 @@
|
|||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.device-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: fit-content;
|
||||
gap: 0.5em;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
gap: 0.2em;
|
||||
& > button:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
|
@ -35,17 +36,17 @@ namespace VELConnect
|
|||
|
||||
public class Device
|
||||
{
|
||||
public readonly string id;
|
||||
public readonly DateTime created;
|
||||
public readonly DateTime updated;
|
||||
public string device_id;
|
||||
public string os_info;
|
||||
public string friendly_name;
|
||||
public string modified_by;
|
||||
public string current_app;
|
||||
public string current_room;
|
||||
public string pairing_code;
|
||||
public DateTime last_online;
|
||||
[CanBeNull] public readonly string id;
|
||||
[CanBeNull] public string created = null;
|
||||
[CanBeNull] public string updated = null;
|
||||
[CanBeNull] public string device_id;
|
||||
[CanBeNull] public string os_info;
|
||||
[CanBeNull] public string friendly_name;
|
||||
[CanBeNull] public string modified_by;
|
||||
[CanBeNull] public string current_app;
|
||||
[CanBeNull] public string current_room;
|
||||
[CanBeNull] public string pairing_code;
|
||||
[CanBeNull] public string last_online;
|
||||
public Dictionary<string, string> data;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -88,9 +89,9 @@ namespace VELConnect
|
|||
|
||||
public class UserCount
|
||||
{
|
||||
public readonly string id;
|
||||
public readonly DateTime created;
|
||||
public readonly DateTime updated;
|
||||
[CanBeNull] public readonly string id;
|
||||
public readonly DateTime? created;
|
||||
public readonly DateTime? updated;
|
||||
public string device_id;
|
||||
public string app_id;
|
||||
public string room_id;
|
||||
|
|
@ -100,7 +101,20 @@ namespace VELConnect
|
|||
public string platform;
|
||||
}
|
||||
|
||||
public enum DeviceField
|
||||
{
|
||||
device_id,
|
||||
os_info,
|
||||
friendly_name,
|
||||
modified_by,
|
||||
current_app,
|
||||
current_room,
|
||||
pairing_code,
|
||||
last_online
|
||||
}
|
||||
|
||||
public State lastState;
|
||||
public State state;
|
||||
|
||||
public static Action<State> OnInitialState;
|
||||
public static Action<string, string> OnDeviceFieldChanged;
|
||||
|
|
@ -136,7 +150,7 @@ namespace VELConnect
|
|||
get
|
||||
{
|
||||
Hash128 hash = new Hash128();
|
||||
hash.Append(DeviceId);
|
||||
hash.Append(deviceId);
|
||||
// change once a day
|
||||
hash.Append(DateTime.UtcNow.DayOfYear);
|
||||
// between 1000 and 9999 inclusive (any 4 digit number)
|
||||
|
|
@ -144,52 +158,52 @@ namespace VELConnect
|
|||
}
|
||||
}
|
||||
|
||||
private static string DeviceId
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// allows running multiple builds on the same computer
|
||||
// return SystemInfo.deviceUniqueIdentifier + Hash128.Compute(Application.dataPath);
|
||||
return SystemInfo.deviceUniqueIdentifier + "_EDITOR";
|
||||
#else
|
||||
return SystemInfo.deviceUniqueIdentifier;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
private static string deviceId;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (_instance != null) Debug.LogError("VELConnectManager instance already exists", this);
|
||||
_instance = this;
|
||||
|
||||
// Compute device id
|
||||
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
|
||||
StringBuilder sb = new StringBuilder(SystemInfo.deviceUniqueIdentifier);
|
||||
sb.Append(Application.productName);
|
||||
#if UNITY_EDITOR
|
||||
// allows running multiple builds on the same computer
|
||||
// return SystemInfo.deviceUniqueIdentifier + Hash128.Compute(Application.dataPath);
|
||||
sb.Append(Application.dataPath);
|
||||
sb.Append("EDITOR");
|
||||
#endif
|
||||
string id = Convert.ToBase64String(md5.ComputeHash(Encoding.UTF8.GetBytes(sb.ToString())));
|
||||
deviceId = id[..15];
|
||||
}
|
||||
|
||||
// Start is called before the first frame update
|
||||
private void Start()
|
||||
{
|
||||
SetDeviceField(new State.Device
|
||||
SetDeviceField(new Dictionary<DeviceField, string>
|
||||
{
|
||||
os_info = SystemInfo.operatingSystem,
|
||||
friendly_name = SystemInfo.deviceName,
|
||||
current_app = Application.productName,
|
||||
pairing_code = PairingCode,
|
||||
{ DeviceField.os_info, SystemInfo.operatingSystem },
|
||||
{ DeviceField.friendly_name, SystemInfo.deviceName },
|
||||
{ DeviceField.current_app, Application.productName },
|
||||
{ DeviceField.pairing_code, PairingCode },
|
||||
});
|
||||
|
||||
UpdateUserCount();
|
||||
// UpdateUserCount();
|
||||
|
||||
StartCoroutine(SlowLoop());
|
||||
|
||||
VelNetManager.OnJoinedRoom += room =>
|
||||
{
|
||||
SetDeviceField(new State.Device
|
||||
SetDeviceField(new Dictionary<DeviceField, string>
|
||||
{
|
||||
current_app = Application.productName,
|
||||
current_room = room,
|
||||
{ DeviceField.current_app, Application.productName },
|
||||
{ DeviceField.current_room, room },
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void UpdateUserCount(bool leaving = false)
|
||||
{
|
||||
if (!VelNetManager.InRoom) return;
|
||||
|
|
@ -198,7 +212,7 @@ namespace VELConnect
|
|||
{
|
||||
UserCount postData = new UserCount
|
||||
{
|
||||
device_id = DeviceId,
|
||||
device_id = deviceId,
|
||||
app_id = Application.productName,
|
||||
room_id = VelNetManager.Room ?? "",
|
||||
total_users = rooms.rooms.Sum(r => r.numUsers) - (leaving ? 1 : 0),
|
||||
|
|
@ -219,9 +233,9 @@ namespace VELConnect
|
|||
{
|
||||
try
|
||||
{
|
||||
GetRequestCallback(velConnectUrl + "/state/device/" + DeviceId, json =>
|
||||
GetRequestCallback(velConnectUrl + "/state/device/" + deviceId, json =>
|
||||
{
|
||||
State state = JsonConvert.DeserializeObject<State>(json);
|
||||
state = JsonConvert.DeserializeObject<State>(json);
|
||||
if (state == null) return;
|
||||
|
||||
bool isInitialState = false;
|
||||
|
|
@ -380,6 +394,10 @@ namespace VELConnect
|
|||
}
|
||||
|
||||
lastState = state;
|
||||
if (lastState?.device?.pairing_code == null)
|
||||
{
|
||||
Debug.LogError("Pairing code nulllll");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -510,33 +528,46 @@ namespace VELConnect
|
|||
return _instance != null ? _instance.lastState?.room?.TryGetData(key) : null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets data on the device keys themselves
|
||||
/// These are fixed fields defined for every application
|
||||
/// </summary>
|
||||
public static void SetDeviceField(State.Device device)
|
||||
public static void SetDeviceField(Dictionary<DeviceField, string> device)
|
||||
{
|
||||
device.last_online = DateTime.UtcNow;
|
||||
device[DeviceField.last_online] = DateTime.UtcNow.ToLongDateString();
|
||||
|
||||
// update our local state, so we don't get change events on our own updates
|
||||
if (_instance.lastState?.device != null)
|
||||
if (_instance.state?.device != null)
|
||||
{
|
||||
FieldInfo[] fields = device.GetType().GetFields();
|
||||
|
||||
// loop through all the fields in the device
|
||||
foreach (FieldInfo fieldInfo in fields)
|
||||
foreach (DeviceField key in device.Keys.ToArray())
|
||||
{
|
||||
fieldInfo.SetValue(_instance.lastState.device, fieldInfo.GetValue(device));
|
||||
FieldInfo field = _instance.state.device.GetType().GetField(key.ToString());
|
||||
if ((string)field.GetValue(_instance.state.device) != device[key])
|
||||
{
|
||||
if (_instance.lastState?.device != null)
|
||||
{
|
||||
// update our local state, so we don't get change events on our own updates
|
||||
field.SetValue(_instance.lastState.device, device[key]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// don't send this field, since it's the same
|
||||
device.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
// last_online field always changes
|
||||
if (device.Keys.Count <= 1)
|
||||
{
|
||||
// nothing changed, don't send
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PostRequestCallback(
|
||||
_instance.velConnectUrl + "/device/" + DeviceId,
|
||||
JsonConvert.SerializeObject(device, Formatting.None, new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
})
|
||||
_instance.velConnectUrl + "/device/" + deviceId,
|
||||
JsonConvert.SerializeObject(device)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -545,23 +576,44 @@ namespace VELConnect
|
|||
/// </summary>
|
||||
public static void SetDeviceData(Dictionary<string, string> data)
|
||||
{
|
||||
State.Device device = new State.Device
|
||||
if (_instance.state?.device != null)
|
||||
{
|
||||
last_online = DateTime.UtcNow,
|
||||
data = data,
|
||||
};
|
||||
|
||||
// update our local state, so we don't get change events on our own updates
|
||||
if (_instance.lastState?.device != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> kvp in data)
|
||||
foreach (string key in data.Keys.ToList())
|
||||
{
|
||||
_instance.lastState.device.data[kvp.Key] = kvp.Value;
|
||||
// if the value is unchanged from the current state, remove it so we don't double-update
|
||||
if (_instance.state.device.data.TryGetValue(key, out string val) && val == data[key])
|
||||
{
|
||||
data.Remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update our local state, so we don't get change events on our own updates
|
||||
if (_instance.lastState?.device?.data != null)
|
||||
{
|
||||
_instance.lastState.device.data[key] = data[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nothing was changed
|
||||
if (data.Keys.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if we have no data, just set the whole thing
|
||||
if (_instance.lastState?.device != null) _instance.lastState.device.data ??= data;
|
||||
}
|
||||
|
||||
|
||||
Dictionary<string, object> device = new Dictionary<string, object>
|
||||
{
|
||||
{ "last_online", DateTime.UtcNow.ToLongDateString() },
|
||||
{ "data", data },
|
||||
};
|
||||
|
||||
PostRequestCallback(
|
||||
_instance.velConnectUrl + "/device/" + DeviceId,
|
||||
_instance.velConnectUrl + "/device/" + deviceId,
|
||||
JsonConvert.SerializeObject(device, Formatting.None, new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
|
|
@ -589,6 +641,24 @@ namespace VELConnect
|
|||
data = data
|
||||
};
|
||||
|
||||
// remove keys that already match our current state
|
||||
if (_instance.state?.room != null)
|
||||
{
|
||||
foreach (string key in data.Keys.ToArray())
|
||||
{
|
||||
if (_instance.state.room.data[key] == data[key])
|
||||
{
|
||||
data.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we have no changed values
|
||||
if (data.Keys.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// update our local state, so we don't get change events on our own updates
|
||||
if (_instance.lastState?.room != null)
|
||||
{
|
||||
|
|
@ -727,7 +797,7 @@ namespace VELConnect
|
|||
|
||||
private void OnApplicationFocus(bool focus)
|
||||
{
|
||||
UpdateUserCount(!focus);
|
||||
// UpdateUserCount(!focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/daos"
|
||||
m "github.com/pocketbase/pocketbase/migrations"
|
||||
"github.com/pocketbase/pocketbase/models/schema"
|
||||
)
|
||||
|
||||
func init() {
|
||||
m.Register(func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("fupstz47c55s69f")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add
|
||||
new_current_room_id := &schema.SchemaField{}
|
||||
json.Unmarshal([]byte(`{
|
||||
"system": false,
|
||||
"id": "wvpaovjo",
|
||||
"name": "current_room_id",
|
||||
"type": "relation",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "3qwwkz4wb0lyi78",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": []
|
||||
}
|
||||
}`), new_current_room_id)
|
||||
collection.Schema.AddField(new_current_room_id)
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
}, func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("fupstz47c55s69f")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove
|
||||
collection.Schema.RemoveField("wvpaovjo")
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/daos"
|
||||
m "github.com/pocketbase/pocketbase/migrations"
|
||||
"github.com/pocketbase/pocketbase/models/schema"
|
||||
)
|
||||
|
||||
func init() {
|
||||
m.Register(func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("fupstz47c55s69f")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove
|
||||
collection.Schema.RemoveField("wvpaovjo")
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
}, func(db dbx.Builder) error {
|
||||
dao := daos.New(db);
|
||||
|
||||
collection, err := dao.FindCollectionByNameOrId("fupstz47c55s69f")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add
|
||||
del_current_room_id := &schema.SchemaField{}
|
||||
json.Unmarshal([]byte(`{
|
||||
"system": false,
|
||||
"id": "wvpaovjo",
|
||||
"name": "current_room_id",
|
||||
"type": "relation",
|
||||
"required": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "3qwwkz4wb0lyi78",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": []
|
||||
}
|
||||
}`), del_current_room_id)
|
||||
collection.Schema.AddField(del_current_room_id)
|
||||
|
||||
return dao.SaveCollection(collection)
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue