peers/peerjs-server

View on GitHub
src/services/checkBrokenConnections/index.ts

Summary

Maintainability
A
30 mins
Test Coverage
A
96%
import type { IConfig } from "../../config/index.ts";
import type { IClient } from "../../models/client.ts";
import type { IRealm } from "../../models/realm.ts";

const DEFAULT_CHECK_INTERVAL = 300;

type CustomConfig = Pick<IConfig, "alive_timeout">;

export class CheckBrokenConnections {
    public readonly checkInterval: number;
    private timeoutId: NodeJS.Timeout | null = null;
    private readonly realm: IRealm;
    private readonly config: CustomConfig;
    private readonly onClose?: (client: IClient) => void;

    constructor({
        realm,
        config,
        checkInterval = DEFAULT_CHECK_INTERVAL,
        onClose,
    }: {
        realm: IRealm;
        config: CustomConfig;
        checkInterval?: number;
        onClose?: (client: IClient) => void;
    }) {
        this.realm = realm;
        this.config = config;
        this.onClose = onClose;
        this.checkInterval = checkInterval;
    }

    public start(): void {
        if (this.timeoutId) {
            clearTimeout(this.timeoutId);
        }

        this.timeoutId = setTimeout(() => {
            this.checkConnections();

            this.timeoutId = null;

            this.start();
        }, this.checkInterval);
    }

    public stop(): void {
        if (this.timeoutId) {
            clearTimeout(this.timeoutId);
            this.timeoutId = null;
        }
    }

    private checkConnections(): void {
        const clientsIds = this.realm.getClientsIds();

        const now = new Date().getTime();
        const { alive_timeout: aliveTimeout } = this.config;

        for (const clientId of clientsIds) {
            const client = this.realm.getClientById(clientId);

            if (!client) continue;

            const timeSinceLastPing = now - client.getLastPing();

            if (timeSinceLastPing < aliveTimeout) continue;

            try {
                client.getSocket()?.close();
            } finally {
                this.realm.clearMessageQueue(clientId);
                this.realm.removeClientById(clientId);

                client.setSocket(null);

                this.onClose?.(client);
            }
        }
    }
}