2024-07-19 17:56:25 +02:00
|
|
|
// this file is responsible for managing UDN connections.
|
|
|
|
|
|
2024-07-22 01:38:08 +02:00
|
|
|
import { ChatMessage, ChatMessageReference } from "./chatModel";
|
2024-07-20 02:56:44 +02:00
|
|
|
import StorageModel, { storageKeys } from "./storageModel";
|
2024-07-19 17:56:25 +02:00
|
|
|
import UDNFrontend, { Message } from "udn-frontend";
|
|
|
|
|
|
2024-07-19 23:45:07 +02:00
|
|
|
import { stringify } from "./Utility/utility";
|
2024-07-19 17:56:25 +02:00
|
|
|
|
|
|
|
|
export default class ConnectionModel {
|
|
|
|
|
udn: UDNFrontend;
|
2024-07-20 02:56:44 +02:00
|
|
|
storageModel: StorageModel;
|
2024-07-19 17:56:25 +02:00
|
|
|
|
|
|
|
|
// data
|
|
|
|
|
get isConnected(): boolean {
|
|
|
|
|
return this.udn.ws != undefined && this.udn.ws.readyState == 1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-19 18:02:23 +02:00
|
|
|
get address(): string | undefined {
|
2024-07-19 17:56:25 +02:00
|
|
|
return this.udn.ws?.url;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-20 22:44:23 +02:00
|
|
|
connectionChangeHandler: () => void = () => {};
|
|
|
|
|
messageHandler: (data: Message) => void = () => {};
|
2024-07-21 14:15:26 +02:00
|
|
|
messageSentHandler: (chatMessage: ChatMessage) => void = () => {};
|
2024-07-20 22:44:23 +02:00
|
|
|
|
2024-07-21 01:12:35 +02:00
|
|
|
channelsToSubscribe: Set<string> = new Set();
|
|
|
|
|
|
2024-07-19 17:56:25 +02:00
|
|
|
// connection
|
2024-07-19 18:02:23 +02:00
|
|
|
connect = (address: string): void => {
|
2024-07-19 17:56:25 +02:00
|
|
|
this.udn.connect(address);
|
2024-07-19 18:02:23 +02:00
|
|
|
};
|
2024-07-21 14:16:20 +02:00
|
|
|
|
2024-07-19 18:02:23 +02:00
|
|
|
disconnect = (): void => {
|
2024-07-19 17:56:25 +02:00
|
|
|
this.udn.disconnect();
|
2024-07-21 03:41:10 +02:00
|
|
|
|
|
|
|
|
// do not reconnect
|
|
|
|
|
const reconnectAddressPath: string[] = storageKeys.reconnectAddress;
|
|
|
|
|
this.storageModel.remove(reconnectAddressPath);
|
2024-07-19 18:02:23 +02:00
|
|
|
};
|
2024-07-19 17:56:25 +02:00
|
|
|
|
2024-07-20 22:44:23 +02:00
|
|
|
handleMessage = (data: Message): void => {
|
|
|
|
|
this.messageHandler(data);
|
|
|
|
|
};
|
2024-07-20 20:42:43 +02:00
|
|
|
|
2024-07-20 02:18:15 +02:00
|
|
|
handleConnectionChange = (): void => {
|
2024-07-19 18:02:23 +02:00
|
|
|
console.log("connection status:", this.isConnected, this.address);
|
2024-07-20 22:44:23 +02:00
|
|
|
this.connectionChangeHandler();
|
2024-07-21 03:41:10 +02:00
|
|
|
|
2024-07-20 02:56:44 +02:00
|
|
|
if (this.isConnected == false) return;
|
2024-07-21 01:12:35 +02:00
|
|
|
if (!this.address) return;
|
2024-07-20 02:56:44 +02:00
|
|
|
|
2024-07-21 15:15:24 +02:00
|
|
|
this.connectMailbox();
|
2024-07-21 01:12:35 +02:00
|
|
|
this.storeAddress(this.address);
|
|
|
|
|
this.sendSubscriptionRequest();
|
2024-07-20 22:44:23 +02:00
|
|
|
this.sendMessagesInOutbox();
|
2024-07-19 18:02:23 +02:00
|
|
|
};
|
2024-07-19 17:56:25 +02:00
|
|
|
|
2024-07-21 15:15:24 +02:00
|
|
|
// mailbox
|
|
|
|
|
requestNewMailbox = (): void => {
|
|
|
|
|
console.trace("requesting mailbox");
|
|
|
|
|
this.udn.requestMailbox();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
connectMailbox = (): void => {
|
|
|
|
|
if (this.address == undefined) return;
|
|
|
|
|
const path = [...storageKeys.mailboxes, this.address];
|
2024-07-21 21:41:19 +02:00
|
|
|
const mailboxId = this.storageModel.read(path);
|
2024-07-22 01:38:08 +02:00
|
|
|
console.log("connecting mailbox", mailboxId);
|
2024-07-21 15:15:24 +02:00
|
|
|
if (mailboxId == null) return this.requestNewMailbox();
|
|
|
|
|
|
|
|
|
|
this.udn.connectMailbox(mailboxId);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
storeMailbox = (mailboxId: string): void => {
|
|
|
|
|
if (this.address == undefined) return;
|
|
|
|
|
const path = [...storageKeys.mailboxes, this.address];
|
2024-07-21 21:41:19 +02:00
|
|
|
this.storageModel.write(path, mailboxId);
|
2024-07-21 15:15:24 +02:00
|
|
|
};
|
|
|
|
|
|
2024-07-21 01:12:35 +02:00
|
|
|
// subscription
|
|
|
|
|
addChannel = (channel: string): void => {
|
|
|
|
|
this.channelsToSubscribe.add(channel);
|
|
|
|
|
this.sendSubscriptionRequest();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
sendSubscriptionRequest = (): void => {
|
2024-07-21 03:41:10 +02:00
|
|
|
if (this.isConnected == false) return;
|
2024-07-21 14:15:26 +02:00
|
|
|
|
2024-07-21 01:12:35 +02:00
|
|
|
for (const channel of this.channelsToSubscribe) {
|
|
|
|
|
this.udn.subscribe(channel);
|
|
|
|
|
}
|
2024-07-21 15:15:24 +02:00
|
|
|
// update mailbox
|
|
|
|
|
this.connectMailbox();
|
2024-07-21 01:12:35 +02:00
|
|
|
};
|
|
|
|
|
|
2024-07-20 20:03:46 +02:00
|
|
|
// outbox
|
|
|
|
|
getOutboxMessags = (): ChatMessage[] => {
|
|
|
|
|
const outboxPath: string[] = storageKeys.outbox;
|
|
|
|
|
const messageIds: string[] = this.storageModel.list(outboxPath);
|
|
|
|
|
|
2024-07-22 01:38:08 +02:00
|
|
|
let chatMessages: ChatMessage[] = [];
|
2024-07-20 20:03:46 +02:00
|
|
|
for (const messageId of messageIds) {
|
2024-07-22 01:38:08 +02:00
|
|
|
const chatMessage: ChatMessage | null =
|
|
|
|
|
this.storageModel.readStringifiable(
|
|
|
|
|
[...outboxPath, messageId],
|
|
|
|
|
ChatMessageReference
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (chatMessage == null) continue;
|
|
|
|
|
chatMessages.push(chatMessage);
|
2024-07-20 20:03:46 +02:00
|
|
|
}
|
|
|
|
|
|
2024-07-22 01:38:08 +02:00
|
|
|
return chatMessages;
|
2024-07-20 20:03:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
addToOutbox = (chatMessage: ChatMessage): void => {
|
|
|
|
|
const messagePath: string[] = [...storageKeys.outbox, chatMessage.id];
|
2024-07-21 21:41:19 +02:00
|
|
|
this.storageModel.writeStringifiable(messagePath, chatMessage);
|
2024-07-20 20:03:46 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
removeFromOutbox = (chatMessage: ChatMessage): void => {
|
|
|
|
|
const messagePath: string[] = [...storageKeys.outbox, chatMessage.id];
|
|
|
|
|
this.storageModel.remove(messagePath);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
sendMessagesInOutbox = (): void => {
|
|
|
|
|
const messages: ChatMessage[] = this.getOutboxMessags();
|
|
|
|
|
|
|
|
|
|
for (const message of messages) {
|
2024-07-21 14:15:26 +02:00
|
|
|
const isSent: boolean = this.tryToSendMessage(message);
|
2024-07-20 20:03:46 +02:00
|
|
|
if (isSent == false) return;
|
|
|
|
|
|
|
|
|
|
this.removeFromOutbox(message);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-19 17:56:25 +02:00
|
|
|
// messaging
|
2024-07-20 20:03:46 +02:00
|
|
|
sendMessageOrStore = (chatMessage: ChatMessage): void => {
|
|
|
|
|
const isSent = this.tryToSendMessage(chatMessage);
|
|
|
|
|
if (isSent == true) return;
|
|
|
|
|
|
|
|
|
|
this.addToOutbox(chatMessage);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tryToSendMessage = (chatMessage: ChatMessage): boolean => {
|
2024-07-19 20:50:42 +02:00
|
|
|
const stringifiedBody: string = stringify(chatMessage);
|
2024-07-21 14:15:26 +02:00
|
|
|
const isSent: boolean = this.udn.sendMessage(
|
|
|
|
|
chatMessage.channel,
|
|
|
|
|
stringifiedBody
|
|
|
|
|
);
|
|
|
|
|
if (isSent) this.messageSentHandler(chatMessage);
|
|
|
|
|
return isSent;
|
2024-07-19 18:02:23 +02:00
|
|
|
};
|
2024-07-19 17:56:25 +02:00
|
|
|
|
2024-07-20 02:56:44 +02:00
|
|
|
// storage
|
|
|
|
|
private getAddressPath = (address: string): string[] => {
|
|
|
|
|
const dirPath = storageKeys.previousAddresses;
|
|
|
|
|
return [...dirPath, address];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
storeAddress = (address: string): void => {
|
2024-07-21 03:41:10 +02:00
|
|
|
// history
|
2024-07-20 02:56:44 +02:00
|
|
|
const addressPath = this.getAddressPath(address);
|
2024-07-21 21:41:19 +02:00
|
|
|
this.storageModel.write(addressPath, "");
|
2024-07-21 03:41:10 +02:00
|
|
|
|
|
|
|
|
// reconnect
|
|
|
|
|
const reconnectAddressPath: string[] = storageKeys.reconnectAddress;
|
2024-07-21 21:41:19 +02:00
|
|
|
this.storageModel.write(reconnectAddressPath, address);
|
2024-07-20 02:56:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
removeAddress = (address: string): void => {
|
|
|
|
|
const addressPath = this.getAddressPath(address);
|
|
|
|
|
this.storageModel.remove(addressPath);
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-20 02:59:40 +02:00
|
|
|
get addresses(): string[] {
|
2024-07-20 02:56:44 +02:00
|
|
|
const dirPath = storageKeys.previousAddresses;
|
|
|
|
|
return this.storageModel.list(dirPath);
|
2024-07-20 20:03:46 +02:00
|
|
|
}
|
2024-07-20 02:56:44 +02:00
|
|
|
|
2024-07-20 22:44:23 +02:00
|
|
|
// handlers
|
|
|
|
|
setConnectionChangeHandler = (handler: () => void): void => {
|
|
|
|
|
this.connectionChangeHandler = handler;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setMessageHandler = (handler: (data: Message) => void): void => {
|
|
|
|
|
this.messageHandler = handler;
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-21 14:15:26 +02:00
|
|
|
setMessageSentHandler = (
|
|
|
|
|
handler: (chatMessage: ChatMessage) => void
|
|
|
|
|
): void => {
|
|
|
|
|
this.messageSentHandler = handler;
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-19 17:56:25 +02:00
|
|
|
// setup
|
2024-07-20 20:42:43 +02:00
|
|
|
constructor(storageModel: StorageModel) {
|
2024-07-19 18:17:00 +02:00
|
|
|
// create frontend
|
2024-07-19 17:56:25 +02:00
|
|
|
this.udn = new UDNFrontend();
|
2024-07-20 20:42:43 +02:00
|
|
|
this.storageModel = storageModel;
|
2024-07-19 18:17:00 +02:00
|
|
|
|
|
|
|
|
// setup handlers
|
|
|
|
|
this.udn.onmessage = (data: Message) => {
|
2024-07-20 20:42:43 +02:00
|
|
|
this.handleMessage(data);
|
2024-07-19 18:17:00 +02:00
|
|
|
};
|
|
|
|
|
this.udn.onconnect = () => {
|
2024-07-20 02:56:44 +02:00
|
|
|
this.handleConnectionChange();
|
2024-07-19 18:17:00 +02:00
|
|
|
};
|
|
|
|
|
this.udn.ondisconnect = () => {
|
2024-07-20 02:56:44 +02:00
|
|
|
this.handleConnectionChange();
|
2024-07-19 18:17:00 +02:00
|
|
|
};
|
2024-07-21 03:41:10 +02:00
|
|
|
|
2024-07-21 15:15:24 +02:00
|
|
|
this.udn.onmailboxcreate = (mailboxId: string) => {
|
|
|
|
|
console.log("created mailbox", mailboxId);
|
|
|
|
|
this.storeMailbox(mailboxId);
|
|
|
|
|
this.connectMailbox();
|
|
|
|
|
};
|
|
|
|
|
this.udn.onmailboxdelete = (mailboxId: string) => {
|
|
|
|
|
console.log(`mailbox ${mailboxId} deleted`);
|
|
|
|
|
this.requestNewMailbox();
|
|
|
|
|
};
|
|
|
|
|
this.udn.onmailboxconnect = (mailboxId: string) => {
|
|
|
|
|
console.log(`using mailbox ${mailboxId}`);
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-21 03:41:10 +02:00
|
|
|
// reconnect
|
|
|
|
|
const reconnectAddressPath: string[] = storageKeys.reconnectAddress;
|
|
|
|
|
const reconnectAddress: string | null =
|
2024-07-21 21:41:19 +02:00
|
|
|
storageModel.read(reconnectAddressPath);
|
2024-07-21 03:41:10 +02:00
|
|
|
if (reconnectAddress != null) {
|
|
|
|
|
this.connect(reconnectAddress);
|
|
|
|
|
}
|
2024-07-19 17:56:25 +02:00
|
|
|
}
|
2024-07-20 22:44:23 +02:00
|
|
|
}
|