var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { Buffer } from 'buffer';
import { Subject } from 'rxjs';
import { debug } from './debug';
import { bufferToHexString } from '@iotize/common/byte-converter';
const TAG = 'Relay';
export class RelayServer {
    constructor(_server, params) {
        this._server = _server;
        this._params = params || {
            port: 2000,
        };
        this._clients = [];
    }
    get server() {
        return this._server;
    }
    addClient(socket) {
        this._clients.push(socket);
        return this;
    }
    removeClient(client) {
        let index = this._clients.indexOf(client);
        if (index >= 0) {
            client.close();
            debug(TAG, `Removing client ${client.getClientName()}...`);
            delete this._clients[index];
        }
        return this;
    }
    start() {
        this._subscription = new Subject();
        this._server
            .connections()
            .subscribe((socket) => __awaiter(this, void 0, void 0, function* () {
            // Identify this client
            let clientName = socket.getClientName();
            debug(TAG, `[NEW_CLIENT] ${clientName}`);
            yield socket.ready();
            debug(TAG, `[NEW_CLIENT] ${clientName} IS READY`);
            // Put this new client in the list
            this.addClient(socket);
            socket.events().subscribe({
                next: (event) => {
                    switch (event.type) {
                        case 'data':
                            let messageString = this.messageToLog(event.payload);
                            debug(TAG, `[MESSAGE] ${messageString} from ${clientName}`);
                            this.broadcastMessage(event.payload, socket);
                            break;
                        case 'error':
                            debug(TAG, `[ERROR] ${clientName} `, event.payload);
                            // Do we have to remove client every time ?
                            this.removeClient(socket);
                            break;
                        case 'end':
                            debug(TAG, `[CLIENTEND] ${clientName}`);
                            this.removeClient(socket);
                            break;
                    }
                },
            });
        }));
        return this._server.listen(this._params);
    }
    stop() {
        return __awaiter(this, void 0, void 0, function* () {
            this._clients.forEach((client) => {
                client.close();
            });
            if (this._server) {
                yield this._server.stop();
            }
            if (this._subscription) {
                this._subscription.complete();
            }
        });
    }
    broadcastMessage(message, sender) {
        let messageString = this.messageToLog(message);
        debug(TAG, `[BROADCAST] ${messageString} from ${sender.getClientName()}`);
        if (this._clients.length == 0) {
            debug(TAG, 'There is no client yet');
            return;
        }
        // Send a message to all clients
        this._clients.forEach(function (client) {
            // Don't want to send it to sender
            try {
                if (client === sender) {
                    debug(TAG, `\t- Skip sender ${client.getClientName()}`);
                    return;
                }
                if (client.isWritable()) {
                    debug(TAG, `\t- Sent to ${client.getClientName()}`);
                    client.write(message);
                }
                else {
                    debug(TAG, `Client ${client.getClientName()} is not writable. Cannot send to it`);
                }
            }
            catch (err) {
                debug(`Cannot broadcast to ${client.getClientName()}`, err);
            }
        });
    }
    messageToLog(message) {
        if (typeof message === 'string') {
            return `"${message}"`;
        }
        else if (message instanceof Buffer) {
            return bufferToHexString(message);
        }
        else {
            return message;
        }
    }
}
//# sourceMappingURL=data:application/json;base64, 