diff --git a/app/routes/machines/components/machine.tsx b/app/routes/machines/components/machine.tsx
index c40e44d..11203cd 100644
--- a/app/routes/machines/components/machine.tsx
+++ b/app/routes/machines/components/machine.tsx
@@ -159,7 +159,7 @@ export default function MachineRow({ machine, routes, magic, users, stats }: Pro
{hinfo.getTSVersion(stats)}
-
+
{hinfo.getOSInfo(stats)}
>
diff --git a/app/utils/host-info.ts b/app/utils/host-info.ts
index f3dad7a..bb105a1 100644
--- a/app/utils/host-info.ts
+++ b/app/utils/host-info.ts
@@ -1,4 +1,4 @@
-import type { HostInfo } from '~/utils/types';
+import type { HostInfo } from '~/types';
export function getTSVersion(host: HostInfo) {
const { IPNVersion } = host;
diff --git a/app/utils/ws-agent.ts b/app/utils/ws-agent.ts
index f562613..a28cf3a 100644
--- a/app/utils/ws-agent.ts
+++ b/app/utils/ws-agent.ts
@@ -4,7 +4,7 @@ import { setTimeout as pSetTimeout } from 'node:timers/promises';
import type { LoaderFunctionArgs } from 'react-router';
import type { HostInfo } from '~/types';
import { WebSocket } from 'ws';
-import { log } from './log';
+import log from './log';
// Essentially a HashMap which invalidates entries after a certain time.
// It also is capable of syncing as a compressed file to disk.
@@ -13,6 +13,7 @@ class TimedCache {
private _timeCache = new Map();
private defaultTTL: number;
private filepath: string;
+ private writeLock = false;
constructor(defaultTTL: number, filepath: string) {
this.defaultTTL = defaultTTL;
@@ -51,21 +52,28 @@ class TimedCache {
this._timeCache.set(key, expires);
}
} catch (e) {
- if (e['code'] !== 'ENOENT') {
- // log.error('CACH', 'Failed to load cache from file', e);
+ if (e.code === 'ENOENT') {
+ log.debug('CACH', 'Cache file not found, creating new cache');
return;
}
- // log.debug('CACH', 'Cache file not found, creating new cache');
+ log.error('CACH', 'Failed to load cache from file', e);
}
}
private async syncToFile() {
+ while (this.writeLock) {
+ await pSetTimeout(100);
+ }
+
+ this.writeLock = true;
const data = Array.from(this._cache.entries()).map(([key, value]) => {
return { key, value, expires: this._timeCache.get(key) }
});
await writeFile(this.filepath, JSON.stringify(data), 'utf-8');
+ await this.loadFromFile();
+ this.writeLock = false;
}
}
@@ -92,7 +100,7 @@ export async function queryAgent(nodes: string[]) {
const cached: Record = {};
await Promise.all(nodes.map(async node => {
- const cachedData = await cache.get(node);
+ const cachedData = await cache?.get(node);
if (cachedData) {
cached[node] = cachedData;
}
@@ -114,17 +122,17 @@ export async function queryAgent(nodes: string[]) {
agentSocket.send(JSON.stringify({ NodeIDs: uncached }));
const returnData = await new Promise | void>((resolve, reject) => {
const timeout = setTimeout(() => {
- agentSocket.removeAllListeners('message');
+ agentSocket?.removeAllListeners('message');
resolve();
}, 3000);
- agentSocket.on('message', async (message: string) => {
+ agentSocket?.on('message', async (message: string) => {
const data = JSON.parse(message.toString());
if (Object.keys(data).length === 0) {
resolve();
}
- agentSocket.removeAllListeners('message');
+ agentSocket?.removeAllListeners('message');
resolve(data);
});
});