337 lines
9.5 KiB
JavaScript
337 lines
9.5 KiB
JavaScript
class SocketManager {
|
|
constructor(io) {
|
|
this.io = io;
|
|
|
|
this.namespaces = new Map();
|
|
this.clients = new Map();
|
|
|
|
this.io.on('connection', socket => {});
|
|
}
|
|
|
|
|
|
add(namespace, exists) {
|
|
if (this.namespaces.has(namespace)) return this.namespaces.get(namespace);
|
|
|
|
const nsp = this.io.of(namespace);
|
|
const clients = new Map();
|
|
this.clients.set(namespace, clients);
|
|
|
|
nsp.on('connection', socket => {
|
|
const { objectGuid, sAMAccountName } = socket.handshake.auth || {};
|
|
if (!objectGuid) return;
|
|
|
|
clients.set(objectGuid, {
|
|
socket,
|
|
userName: sAMAccountName
|
|
});
|
|
|
|
// console.log(`${sAMAccountName} [${objectGuid}] connected to ${namespace}`);
|
|
|
|
socket.on('disconnect', () => {
|
|
clients.delete(objectGuid);
|
|
// console.log(`${sAMAccountName} [${objectGuid}] disconnected from ${namespace}`);
|
|
});
|
|
});
|
|
|
|
this.namespaces.set(namespace, nsp);
|
|
return nsp;
|
|
}
|
|
|
|
|
|
async addAsync(namespace, exists) {
|
|
return new Promise(resolve => {
|
|
this.add(namespace, exists)
|
|
|
|
// simulierter async Init (z. B. DB)
|
|
setTimeout(resolve, 0);
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Broadcast in namespace
|
|
* @param {string} namespace - Namespace-Name
|
|
* @param {string} event - Event-Name
|
|
* @param {any} data - Event-Data
|
|
*/
|
|
broadcast(namespace, event, data) {
|
|
const nsp = this.namespaces.get(namespace);
|
|
if (nsp) nsp.emit(event, data);
|
|
}
|
|
|
|
|
|
/**
|
|
* Event-Handler für einen Namespace registrieren
|
|
* @param {string} namespace - Namespace-Name
|
|
* @param {string} event - Event-Name
|
|
* @param {Function} callback - Callback mit (socket, data)
|
|
*/
|
|
// on(namespace, event, callback) {
|
|
// const nsp = this.namespaces.get(namespace);
|
|
// if (!nsp) {
|
|
// console.warn(`Namespace ${namespace} doesn't exist`);
|
|
// return;
|
|
// }
|
|
|
|
// nsp.on('connection', (socket) => {
|
|
// socket.on(event, (data) => {
|
|
// // übergibt socket als Kontext, damit sendTo automatisch weiß, wer anfragte
|
|
// callback(socket, data, (responseEvent, responseData, targetGuid = null) => {
|
|
// this.sendTo(namespace, targetGuid, responseEvent, responseData, socket);
|
|
// });
|
|
// });
|
|
// });
|
|
// }
|
|
on(namespace, event, callback) {
|
|
const nsp = this.namespaces.get(namespace);
|
|
if (!nsp) {
|
|
console.warn(`Namespace ${namespace} doesn't exist`);
|
|
return;
|
|
}
|
|
|
|
nsp.on('connection', (socket) => {
|
|
socket.on(event, (data) => callback(socket, data));
|
|
});
|
|
}
|
|
|
|
|
|
registerClient(namespace, socket) {
|
|
const nsp = this.namespaces.get(namespace);
|
|
if (!nsp) {
|
|
console.warn(`Namespace ${namespace} does not exist`);
|
|
return;
|
|
}
|
|
|
|
const auth = socket.handshake.auth;
|
|
const objectGuid = auth.objectGuid;
|
|
const sAMAccountName = auth.sAMAccountName;
|
|
|
|
if (!objectGuid) {
|
|
console.warn('Socket has no objectGuid, cannot register');
|
|
return;
|
|
}
|
|
|
|
socket.customId = objectGuid;
|
|
|
|
// In Map speichern
|
|
this.clients.set(objectGuid, {
|
|
userName: sAMAccountName,
|
|
socketId: socket.id,
|
|
socket: socket
|
|
});
|
|
|
|
console.log(`${sAMAccountName} [${objectGuid}] registered to namespace ${namespace}`);
|
|
|
|
// Disconnect-Handler
|
|
socket.on('disconnect', () => {
|
|
this.clients.delete(objectGuid);
|
|
console.log(`${sAMAccountName} [${objectGuid}] disconnected from namespace ${namespace}`);
|
|
});
|
|
};
|
|
|
|
|
|
/**
|
|
* Entfernt einen Client aus dem Namespace
|
|
* @param {string} objectGuid - GUID des Clients
|
|
* @param {string} [namespace] - optional, um Namespace-spezifisch zu loggen
|
|
*/
|
|
unregisterClient(objectGuid) {
|
|
try {
|
|
const client = this.clients.get(objectGuid);
|
|
if (!client) return;
|
|
|
|
// Optional: Socket trennen
|
|
client.socket.disconnect();
|
|
|
|
this.clients.delete(objectGuid);
|
|
const name = client.userName;
|
|
console.log(`${name} [${objectGuid}] manuell entfernt`);
|
|
} catch (err) {
|
|
console.log(err);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Send a personal message to ObjectGUID
|
|
* @param {string} namespace - Namespace-Name
|
|
* @param {string} objectGuid - Socket-ID
|
|
* @param {string} event - Event-Name
|
|
* @param {any} data - Event-Data
|
|
* @param {object} [senderSocket] - optionaler Absender-Socket
|
|
*/
|
|
sendTo(namespace, objectGuid, event, data, senderSocket = null) {
|
|
const clients = this.clients.get(namespace);
|
|
if (!clients) return;
|
|
|
|
// Antwort an Absender
|
|
if (!objectGuid && senderSocket) {
|
|
senderSocket.emit(event, data);
|
|
return;
|
|
}
|
|
|
|
const client = clients.get(objectGuid);
|
|
if (!client?.socket) return;
|
|
|
|
client.socket.emit(event, data);
|
|
}
|
|
}
|
|
|
|
module.exports = SocketManager;
|
|
|
|
// const WebSocket = require("ws");
|
|
// const url = require("url");
|
|
|
|
// class SocketManager {
|
|
// constructor() {
|
|
// this.namespaces = new Map(); // "/admin" → { clients:Set, handlers:Map }
|
|
// this.clients = new Map(); // objectGuid → { userName, socket }
|
|
|
|
// // Default-Namespaces wie bei Socket.IO
|
|
// this.add("/");
|
|
// this.add("/admin");
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Namespace erstellen
|
|
// */
|
|
// add(namespace) {
|
|
// if (this.namespaces.has(namespace)) return this.namespaces.get(namespace);
|
|
|
|
// const ns = {
|
|
// clients: new Set(),
|
|
// handlers: new Map() // event → callback
|
|
// };
|
|
|
|
// this.namespaces.set(namespace, ns);
|
|
// return ns;
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Upgrade (HTTP → WebSocket) pro Namespace auswerten
|
|
// */
|
|
// handleUpgrade(namespace, req, socket, head) {
|
|
// if (!this.namespaces.has(namespace)) {
|
|
// socket.destroy();
|
|
// return;
|
|
// }
|
|
|
|
// const ns = this.namespaces.get(namespace);
|
|
|
|
// const wss = new WebSocket.Server({ noServer: true });
|
|
|
|
// wss.handleUpgrade(req, socket, head, ws => {
|
|
// this._onConnection(namespace, ws, req);
|
|
// });
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Verbindung herstellen + authentifizieren
|
|
// */
|
|
// _onConnection(namespace, socket, req) {
|
|
// const params = new URLSearchParams(url.parse(req.url).query);
|
|
// const objectGuid = params.get("objectGuid");
|
|
// const sAMAccountName = params.get("sAMAccountName") || "Unknown";
|
|
|
|
// socket.namespace = namespace;
|
|
// socket.objectGuid = objectGuid;
|
|
// socket.userName = sAMAccountName;
|
|
|
|
// // Helper zum JSON-Senden
|
|
// socket.sendJSON = (obj) => socket.send(JSON.stringify(obj));
|
|
|
|
// const ns = this.namespaces.get(namespace);
|
|
// ns.clients.add(socket);
|
|
|
|
// if (objectGuid) {
|
|
// this.clients.set(objectGuid, { userName: sAMAccountName, socket: socket });
|
|
// console.log(`${sAMAccountName} [${objectGuid}] connected to [${namespace}]`);
|
|
// }
|
|
|
|
// // Nachrichten-Handling
|
|
// socket.on("message", raw => {
|
|
// let msg;
|
|
// try { msg = JSON.parse(raw); }
|
|
// catch { return; }
|
|
|
|
// const event = msg.event;
|
|
// const data = msg.data;
|
|
|
|
// const cb = ns.handlers.get(event);
|
|
// if (cb) cb(socket, data);
|
|
// });
|
|
|
|
// // Disconnect
|
|
// socket.on("close", () => {
|
|
// ns.clients.delete(socket);
|
|
|
|
// if (objectGuid) {
|
|
// this.clients.delete(objectGuid);
|
|
// console.log(`${sAMAccountName} [${objectGuid}] disconnected from namespace ${namespace}`);
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Events registrieren wie socket.on("event")
|
|
// */
|
|
// on(namespace, event, callback) {
|
|
// const ns = this.namespaces.get(namespace);
|
|
// if (!ns) return console.warn(`Namespace ${namespace} doesn't exist`);
|
|
// ns.handlers.set(event, callback);
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Broadcast in Namespace
|
|
// */
|
|
// broadcast(namespace, event, data) {
|
|
// const ns = this.namespaces.get(namespace);
|
|
// if (!ns) return;
|
|
|
|
// for (const client of ns.clients) {
|
|
// if (client.readyState === WebSocket.OPEN) {
|
|
// client.sendJSON({ event, data });
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Persönliche Nachricht an GUID
|
|
// */
|
|
// sendTo(namespace, objectGuid, event, data, sender = null) {
|
|
// if (!objectGuid && sender) {
|
|
// sender.sendJSON({ event, data });
|
|
// return;
|
|
// }
|
|
|
|
// const client = this.clients.get(objectGuid);
|
|
// if (!client) return;
|
|
|
|
// if (client.socket.readyState === WebSocket.OPEN) {
|
|
// client.socket.sendJSON({ event, data });
|
|
// }
|
|
// }
|
|
|
|
|
|
// /**
|
|
// * Client manuell entfernen
|
|
// */
|
|
// unregisterClient(objectGuid) {
|
|
// const client = this.clients.get(objectGuid);
|
|
// if (!client) return;
|
|
|
|
// client.socket.close(4000, "manual kick");
|
|
// this.clients.delete(objectGuid);
|
|
|
|
// console.log(`${client.userName} [${objectGuid}] manually removed`);
|
|
// }
|
|
// }
|
|
|
|
// module.exports = SocketManager;
|