perf: merge client status in linear time (#2703)
perf: merge client status in linear time (#2700) Co-authored-by: potatosips <potatosips@users.noreply.github.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import fs from 'node:fs/promises';
|
|||||||
import { createDebug } from 'obug';
|
import { createDebug } from 'obug';
|
||||||
|
|
||||||
import Database from '#server/utils/Database';
|
import Database from '#server/utils/Database';
|
||||||
|
import { mergeClientStatuses } from '#server/utils/clientStatus';
|
||||||
import { OLD_ENV, WG_ENV } from '#server/utils/config';
|
import { OLD_ENV, WG_ENV } from '#server/utils/config';
|
||||||
import { firewall } from '#server/utils/firewall';
|
import { firewall } from '#server/utils/firewall';
|
||||||
import { encodeQRCode } from '#server/utils/qr';
|
import { encodeQRCode } from '#server/utils/qr';
|
||||||
@@ -103,21 +104,7 @@ class WireGuard {
|
|||||||
|
|
||||||
// Loop WireGuard status
|
// Loop WireGuard status
|
||||||
const dump = await wg.dump(wgInterface.name);
|
const dump = await wg.dump(wgInterface.name);
|
||||||
dump.forEach(
|
return mergeClientStatuses(clients, dump);
|
||||||
({ 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async dumpByPublicKey(publicKey: string) {
|
async dumpByPublicKey(publicKey: string) {
|
||||||
@@ -146,21 +133,7 @@ class WireGuard {
|
|||||||
|
|
||||||
// Loop WireGuard status
|
// Loop WireGuard status
|
||||||
const dump = await wg.dump(wgInterface.name);
|
const dump = await wg.dump(wgInterface.name);
|
||||||
dump.forEach(
|
return mergeClientStatuses(clients, dump);
|
||||||
({ 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getClientConfiguration({ clientId }: { clientId: ID }) {
|
async getClientConfiguration({ clientId }: { clientId: ID }) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user