// matrix-appservice-kakaotalk - A Matrix-KakaoTalk puppeting bridge. // Copyright (C) 2022 Tulir Asokan, Andrew Ferrazzutti // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import net from "net" import fs from "fs" import path from "path" import PeerClient from "./client.js" import { promisify } from "./util.js" export default class ClientManager { constructor(listenConfig, registerTimeout) { this.listenConfig = listenConfig this.registerTimeout = registerTimeout || 3000 this.server = net.createServer(this.acceptConnection) this.connections = [] this.clients = new Map() this.connIDSequence = 0 this.stopped = false } log(...text) { console.log("[API]", ...text) } acceptConnection = sock => { if (this.stopped) { sock.end() sock.destroy() } else { const connID = this.connIDSequence++ this.connections[connID] = sock new PeerClient(this, sock, connID).start() } } async startUnix(socketPath, force) { try { await fs.promises.access(path.dirname(socketPath)) } catch (err) { await fs.promises.mkdir(path.dirname(socketPath), 0o700) } if (force) { try { await fs.promises.unlink(socketPath) } catch (err) {} } await promisify(cb => this.server.listen(socketPath, cb)) await fs.promises.chmod(socketPath, 0o700) this.log("Now listening at", socketPath) } async startTCP(port, host) { await promisify(cb => this.server.listen(port, host, cb)) this.log(`Now listening at ${host || ""}:${port}`) } async start() { this.log("Starting server") if (this.listenConfig.type === "unix") { await this.startUnix(this.listenConfig.path, this.listenConfig.force) } else if (this.listenConfig.type === "tcp") { await this.startTCP(this.listenConfig.port, this.listenConfig.host) } } async stop() { this.stopped = true for (const client of this.clients.values()) { await client.stop("Server is shutting down") } for (const socket of this.connections) { socket.end() socket.destroy() } this.log("Stopping server") await promisify(cb => this.server.close(cb)) if (this.listenConfig.type === "unix") { try { await fs.promises.unlink(this.listenConfig.path) } catch (err) {} } } }