initial files
This commit is contained in:
336
src/services/socketManager.js
Normal file
336
src/services/socketManager.js
Normal file
@@ -0,0 +1,336 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user