Files
UDN/subscriptionHandler.ts
T

182 lines
4.2 KiB
TypeScript
Raw Normal View History

2024-07-08 21:13:56 +02:00
import {
WebSocketMessage,
sendWebSocketMessage,
subscriptionMap,
} from "./websocket-handler";
2024-07-08 19:48:49 +02:00
import Crypto from "crypto";
import { WS } from "./index";
export interface Subscriber {
send: (message: string, compress?: boolean, id?: string) => void;
}
2024-07-08 19:48:49 +02:00
export class Mailbox implements Subscriber {
2024-07-08 21:13:56 +02:00
// basic data
2024-07-08 19:48:49 +02:00
id = Crypto.randomUUID();
2024-07-08 23:34:16 +02:00
dateLastUsed = new Date();
2024-07-08 19:48:49 +02:00
2024-07-08 19:51:56 +02:00
get expiryDate() {
2024-07-08 23:34:16 +02:00
const expiryDate = new Date(this.dateLastUsed);
2024-07-08 21:14:26 +02:00
expiryDate.setDate(expiryDate.getDate() + 7);
2024-07-08 19:51:56 +02:00
return expiryDate;
}
2024-07-08 23:34:16 +02:00
get isExpired() {
2024-07-09 02:57:32 +02:00
if (this.ws && this.ws.readyState == 1) return false;
2024-07-08 23:34:16 +02:00
const today = new Date();
return this.expiryDate < today;
}
2024-07-09 00:27:14 +02:00
// manage
2024-07-08 21:13:56 +02:00
constructor(ws: WS) {
sendWebSocketMessage(
{
assignedMailboxId: this.id,
},
ws,
2024-07-08 21:13:56 +02:00
);
}
2024-07-08 23:34:16 +02:00
confirmConnection(): void {
if (!this.ws) return;
sendWebSocketMessage(
{
connectedMailboxId: this.id,
},
this.ws,
2024-07-08 23:34:16 +02:00
);
}
2024-07-09 00:27:14 +02:00
delete(): void {
subscriptionMap.deleteSubscriber(this);
if (!this.ws) return;
sendWebSocketMessage({ deletedMailbox: this.id }, this.ws);
}
2024-07-08 21:13:56 +02:00
// storage
messages = new Map<string, string>();
2024-07-08 21:13:56 +02:00
2024-07-08 19:48:49 +02:00
// websocket
2024-07-08 21:13:56 +02:00
private _ws: WS | undefined;
2024-07-08 19:48:49 +02:00
get ws(): WS | undefined {
return this._ws;
}
set ws(ws: WS) {
this._ws = ws;
2024-07-09 02:32:04 +02:00
this.update();
}
update() {
if (!this._ws) return;
2024-07-08 23:34:16 +02:00
this.dateLastUsed = new Date();
2024-07-08 21:13:56 +02:00
2024-07-08 23:34:16 +02:00
this.confirmConnection();
2024-07-08 19:48:49 +02:00
this.sendUnreadMessages();
2024-07-08 21:13:56 +02:00
2024-07-09 02:32:04 +02:00
const channels = subscriptionMap.getChannelList(this._ws);
2024-07-08 21:13:56 +02:00
channels?.forEach((channel) => this.subscribe(channel));
2024-07-09 02:32:04 +02:00
subscriptionMap.deleteSubscriber(this._ws);
2024-07-08 21:13:56 +02:00
}
// subscribing
subscribe(channelName: string): void {
subscriptionMap.set(this, channelName);
}
2024-07-08 19:48:49 +02:00
// sending
send(message: string, _?: boolean, uuid?: string): void {
this._ws?.send(message);
console.log(this.id, uuid, message, "sending");
if (!uuid) return;
this.messages.set(uuid, message);
2024-07-08 19:48:49 +02:00
}
2024-07-08 21:13:56 +02:00
sendUnreadMessages(): void {
2024-07-08 19:48:49 +02:00
this.messages.forEach((message) => {
2024-07-09 04:01:28 +02:00
if (this._ws?.readyState != 1) return;
2024-07-08 19:48:49 +02:00
this._ws.send(message);
this.messages.delete(message);
});
}
checkMessageReceivedConfirmation(uuid: string): void {
if (!this.messages.has(uuid)) return;
this.dateLastUsed = new Date();
this.messages.delete(uuid);
}
2024-07-08 19:48:49 +02:00
}
export class SubscriptionMap {
channelsPerSubscriber = new Map<Subscriber, Set<string>>();
subscribersPerChannel = new Map<string, Set<Subscriber>>();
// prepare
private prepareChannelSet(subscriber: Subscriber): void {
if (this.channelsPerSubscriber.has(subscriber)) return;
this.channelsPerSubscriber.set(subscriber, new Set());
}
private prepareSubscriberSet(channel: string): void {
if (this.subscribersPerChannel.has(channel)) return;
this.subscribersPerChannel.set(channel, new Set());
}
// utility
getChannelList(subscriber: Subscriber): Set<string> | undefined {
return this.channelsPerSubscriber.get(subscriber);
}
getClientList(channel: string): Set<Subscriber> | undefined {
return this.subscribersPerChannel.get(channel);
}
// modifications
set(subscriber: Subscriber, channel: string): void {
this.prepareChannelSet(subscriber);
this.prepareSubscriberSet(channel);
this.getChannelList(subscriber)?.add(channel);
this.getClientList(channel)?.add(subscriber);
}
delete(subscriber: Subscriber, channel: string): void {
const channelList = this.getChannelList(subscriber);
const clientList = this.getClientList(channel);
channelList?.delete(channel);
if (channelList?.size == 0) {
this.channelsPerSubscriber.delete(subscriber);
}
clientList?.delete(subscriber);
if (clientList?.size == 0) {
this.subscribersPerChannel.delete(channel);
}
}
2024-07-08 21:13:56 +02:00
deleteSubscriber(subscriber: Subscriber): void {
this.getChannelList(subscriber)?.forEach((channel) => {
this.delete(subscriber, channel);
});
}
// messages
2024-07-08 21:13:56 +02:00
forwardMessage(channels: string[], messageObject: WebSocketMessage): void {
channels.forEach((channel) => {
const subscribers = this.getClientList(channel);
2024-07-08 21:13:56 +02:00
subscribers?.forEach((subscriber) => {
sendWebSocketMessage(messageObject, subscriber);
});
});
}
}