Browse Source

perf: merge client status in linear time (#2700)

pull/2703/head
potatosips 19 hours ago
parent
commit
ce869e7870
  1. 33
      src/server/utils/WireGuard.ts
  2. 30
      src/server/utils/clientStatus.ts
  3. 53
      src/test/unit/clientStatus.spec.ts

33
src/server/utils/WireGuard.ts

@ -3,6 +3,7 @@ import fs from 'node:fs/promises';
import { createDebug } from 'obug';
import Database from '#server/utils/Database';
import { mergeClientStatuses } from '#server/utils/clientStatus';
import { OLD_ENV, WG_ENV } from '#server/utils/config';
import { firewall } from '#server/utils/firewall';
import { encodeQRCode } from '#server/utils/qr';
@ -103,21 +104,7 @@ class WireGuard {
// Loop WireGuard status
const dump = await wg.dump(wgInterface.name);
dump.forEach(
({ publicKey, latestHandshakeAt, endpoint, transferRx, transferTx }) => {
const client = clients.find((client) => client.publicKey === publicKey);
if (!client) {
return;
}
client.latestHandshakeAt = latestHandshakeAt;
client.endpoint = endpoint;
client.transferRx = transferRx;
client.transferTx = transferTx;
}
);
return clients;
return mergeClientStatuses(clients, dump);
}
async dumpByPublicKey(publicKey: string) {
@ -146,21 +133,7 @@ class WireGuard {
// Loop WireGuard status
const dump = await wg.dump(wgInterface.name);
dump.forEach(
({ publicKey, latestHandshakeAt, endpoint, transferRx, transferTx }) => {
const client = clients.find((client) => client.publicKey === publicKey);
if (!client) {
return;
}
client.latestHandshakeAt = latestHandshakeAt;
client.endpoint = endpoint;
client.transferRx = transferRx;
client.transferTx = transferTx;
}
);
return clients;
return mergeClientStatuses(clients, dump);
}
async getClientConfiguration({ clientId }: { clientId: ID }) {

30
src/server/utils/clientStatus.ts

@ -0,0 +1,30 @@
type StatusFields = {
publicKey: string;
latestHandshakeAt: Date | null;
endpoint: string | null;
transferRx: number | null;
transferTx: number | null;
};
export function mergeClientStatuses<T extends StatusFields>(
clients: T[],
statuses: readonly StatusFields[]
): T[] {
const clientsByPublicKey = new Map(
clients.map((client) => [client.publicKey, client])
);
for (const status of statuses) {
const client = clientsByPublicKey.get(status.publicKey);
if (!client) {
continue;
}
client.latestHandshakeAt = status.latestHandshakeAt;
client.endpoint = status.endpoint;
client.transferRx = status.transferRx;
client.transferTx = status.transferTx;
}
return clients;
}

53
src/test/unit/clientStatus.spec.ts

@ -0,0 +1,53 @@
import { describe, expect, test } from 'vitest';
import { mergeClientStatuses } from '#server/utils/clientStatus';
describe('mergeClientStatuses', () => {
test('merges matching status records by public key', () => {
const clients = [
{
id: 1,
publicKey: 'first',
latestHandshakeAt: null,
endpoint: null,
transferRx: null,
transferTx: null,
},
{
id: 2,
publicKey: 'second',
latestHandshakeAt: null,
endpoint: null,
transferRx: null,
transferTx: null,
},
];
const handshake = new Date('2026-07-20T00:00:00Z');
const result = mergeClientStatuses(clients, [
{
publicKey: 'second',
latestHandshakeAt: handshake,
endpoint: '192.0.2.1:51820',
transferRx: 100,
transferTx: 200,
},
{
publicKey: 'unknown',
latestHandshakeAt: null,
endpoint: null,
transferRx: 0,
transferTx: 0,
},
]);
expect(result).toBe(clients);
expect(result[0]?.endpoint).toBeNull();
expect(result[1]).toMatchObject({
latestHandshakeAt: handshake,
endpoint: '192.0.2.1:51820',
transferRx: 100,
transferTx: 200,
});
});
});
Loading…
Cancel
Save