clean model (A)

This commit is contained in:
marlon-erler
2026-04-18 11:55:01 +00:00
parent cae717066a
commit 2ae00924c8
75 changed files with 5139 additions and 5147 deletions
+32 -28
View File
@@ -1,13 +1,16 @@
// this file is responsible for managing UDN connections.
// cleanup: Phase A
import { ChatMessage, ChatMessageReference } from "../Chat/chatModel";
import { HandlerManager, stringify } from "../Utility/utility";
import StorageModel, { StorageModelSubPaths, filePaths } from "./storageModel";
import UDNFrontend, { Message } from "udn-frontend";
import StorageModel, { StorageModelSubPaths, filePaths } from "./storageModel";
import { HandlerManager, stringify } from "../Utility/utility";
import { ChatMessage, ChatMessageReference } from "../Chat/chatModel";
export default class ConnectionModel {
// models etc
readonly udn: UDNFrontend;
readonly storageModel: StorageModel;
// config
reconnectInterval: number | undefined = undefined;
shouldAttemptReconnect: boolean = false;
@@ -20,17 +23,18 @@ export default class ConnectionModel {
return this.udn.ws?.url;
}
// handler managers
readonly connectionChangeHandlerManager = new HandlerManager<void>();
readonly messageHandlerManager = new HandlerManager<Message>();
readonly messageSentHandlerManager = new HandlerManager<ChatMessage>();
readonly channelsToSubscribe = new Set<string>();
// handlers
handleMessage = (data: Message): void => {
readonly handleMessage = (data: Message): void => {
this.messageHandlerManager.trigger(data);
};
handleConnectionChange = (): void => {
readonly handleConnectionChange = (): void => {
console.log("connection status:", this.isConnected, this.address);
this.connectionChangeHandlerManager.trigger();
if (this.address == undefined) return;
@@ -41,13 +45,13 @@ export default class ConnectionModel {
};
// connection
connect = (address: string): void => {
readonly connect = (address: string): void => {
console.log("connecting...", address);
this.shouldAttemptReconnect = true;
this.udn.connect(address);
};
disconnect = (): void => {
readonly disconnect = (): void => {
this.shouldAttemptReconnect = false;
this.udn.disconnect();
@@ -59,7 +63,7 @@ export default class ConnectionModel {
this.storageModel.remove(reconnectAddressPath);
};
reconnect = (): void => {
readonly reconnect = (): void => {
const reconnectAddressPath: string[] = this.getReconnectAddressPath();
const reconnectAddress: string | null =
this.storageModel.read(reconnectAddressPath);
@@ -70,7 +74,7 @@ export default class ConnectionModel {
};
// mailbox
getMailboxPath = (address: string): string[] => {
readonly getMailboxPath = (address: string): string[] => {
const mailboxDirPath = StorageModel.getPath(
StorageModelSubPaths.ConnectionModel,
filePaths.connectionModel.mailboxes,
@@ -79,12 +83,12 @@ export default class ConnectionModel {
return mailboxFilePath;
};
requestNewMailbox = (): void => {
readonly requestNewMailbox = (): void => {
console.log("requesting new mailbox");
this.udn.requestMailbox();
};
connectMailbox = (): void => {
readonly connectMailbox = (): void => {
if (this.address == undefined) return;
const mailboxId = this.storageModel.read(
@@ -96,18 +100,18 @@ export default class ConnectionModel {
this.udn.connectMailbox(mailboxId);
};
storeMailbox = (mailboxId: string): void => {
readonly storeMailbox = (mailboxId: string): void => {
if (this.address == undefined) return;
this.storageModel.write(this.getMailboxPath(this.address), mailboxId);
};
// subscription
addChannel = (channel: string): void => {
readonly addChannel = (channel: string): void => {
this.channelsToSubscribe.add(channel);
this.sendSubscriptionRequest();
};
sendSubscriptionRequest = (): void => {
readonly sendSubscriptionRequest = (): void => {
if (this.isConnected == false) return;
for (const channel of this.channelsToSubscribe) {
@@ -118,14 +122,14 @@ export default class ConnectionModel {
};
// outbox
getOutboxPath = (): string[] => {
readonly getOutboxPath = (): string[] => {
return StorageModel.getPath(
StorageModelSubPaths.ConnectionModel,
filePaths.connectionModel.outbox,
);
};
getOutboxMessags = (): ChatMessage[] => {
readonly getOutboxMessags = (): ChatMessage[] => {
const outboxPath: string[] = this.getOutboxPath();
const messageIds: string[] = this.storageModel.list(outboxPath);
@@ -144,17 +148,17 @@ export default class ConnectionModel {
return chatMessages;
};
addToOutbox = (chatMessage: ChatMessage): void => {
readonly addToOutbox = (chatMessage: ChatMessage): void => {
const messagePath: string[] = [...this.getOutboxPath(), chatMessage.id];
this.storageModel.writeStringifiable(messagePath, chatMessage);
};
removeFromOutbox = (chatMessage: ChatMessage): void => {
readonly removeFromOutbox = (chatMessage: ChatMessage): void => {
const messagePath: string[] = [...this.getOutboxPath(), chatMessage.id];
this.storageModel.remove(messagePath);
};
sendMessagesInOutbox = (): void => {
readonly sendMessagesInOutbox = (): void => {
const messages: ChatMessage[] = this.getOutboxMessags();
for (const message of messages) {
@@ -166,14 +170,14 @@ export default class ConnectionModel {
};
// messaging
sendMessageOrStore = (chatMessage: ChatMessage): void => {
readonly sendMessageOrStore = (chatMessage: ChatMessage): void => {
const isSent = this.tryToSendMessage(chatMessage);
if (isSent == true) return;
this.addToOutbox(chatMessage);
};
tryToSendMessage = (chatMessage: ChatMessage): boolean => {
readonly tryToSendMessage = (chatMessage: ChatMessage): boolean => {
const stringifiedBody: string = stringify(chatMessage);
const isSent: boolean = this.sendPlainMessage(
chatMessage.channel,
@@ -183,31 +187,31 @@ export default class ConnectionModel {
return isSent;
};
sendPlainMessage = (channel: string, body: string): boolean => {
readonly sendPlainMessage = (channel: string, body: string): boolean => {
return this.udn.sendMessage(channel, body);
};
// storage
getPreviousAddressPath = (): string[] => {
readonly getPreviousAddressPath = (): string[] => {
return StorageModel.getPath(
StorageModelSubPaths.ConnectionModel,
filePaths.connectionModel.previousAddresses,
);
};
getAddressPath = (address: string): string[] => {
readonly getAddressPath = (address: string): string[] => {
const dirPath = this.getPreviousAddressPath();
return [...dirPath, address];
};
getReconnectAddressPath = (): string[] => {
readonly getReconnectAddressPath = (): string[] => {
return StorageModel.getPath(
StorageModelSubPaths.ConnectionModel,
filePaths.connectionModel.reconnectAddress,
);
};
storeAddress = (address: string): void => {
readonly storeAddress = (address: string): void => {
// history
const addressPath = this.getAddressPath(address);
this.storageModel.write(addressPath, "");
@@ -217,7 +221,7 @@ export default class ConnectionModel {
this.storageModel.write(reconnectAddressPath, address);
};
removeAddress = (address: string): void => {
readonly removeAddress = (address: string): void => {
const addressPath = this.getAddressPath(address);
this.storageModel.remove(addressPath);
};
+16 -15
View File
@@ -1,17 +1,16 @@
// this file is responsible for sending and handling files.
// cleanup: Phase A
import { Message } from "udn-frontend";
import StorageModel from "./storageModel";
import ConnectionModel from "./connectionModel";
import {
HandlerManager,
generateRandomToken,
parse,
stringify,
} from "../Utility/utility";
import { decryptString, encryptString } from "../Utility/crypto";
import ConnectionModel from "./connectionModel";
import { Message } from "udn-frontend";
import StorageModel from "./storageModel";
import { checkMatchesObjectStructure } from "../Utility/typeSafety";
import { decryptString, encryptString } from "../Utility/crypto";
export default class FileTransferModel {
readonly storageModel: StorageModel;
@@ -21,12 +20,14 @@ export default class FileTransferModel {
// data
transferData: TransferData | undefined;
readonly fileHandlerManager = new HandlerManager<string>();
readonly readyToSendHandlerManager = new HandlerManager<boolean>();
direction: TransferDirections = TransferDirections.Send;
// handler managers
readonly fileHandlerManager = new HandlerManager<string>();
readonly readyToSendHandlerManager = new HandlerManager<boolean>();
// general
generateTransferData = (): TransferData => {
readonly generateTransferData = (): TransferData => {
const transferData: TransferData = {
channel: generateRandomToken(4),
key: generateRandomToken(6),
@@ -35,12 +36,12 @@ export default class FileTransferModel {
return transferData;
};
prepareToSend = (): void => {
readonly prepareToSend = (): void => {
this.direction = TransferDirections.Send;
this.connectionModel.addChannel(this.transferData.channel);
};
prepareToReceive = (transferData: TransferData): void => {
readonly prepareToReceive = (transferData: TransferData): void => {
this.direction = TransferDirections.Receive;
this.connectionModel.addChannel(transferData.channel);
@@ -52,7 +53,7 @@ export default class FileTransferModel {
};
// handlers
handleMessage = (data: Message): void => {
readonly handleMessage = (data: Message): void => {
if (this.transferData == undefined) return;
if (data.messageChannel != this.transferData.channel) return;
if (
@@ -68,7 +69,7 @@ export default class FileTransferModel {
this.handleFile(data.messageBody);
};
handleFile = async (encryptedFileData: string): Promise<void> => {
readonly handleFile = async (encryptedFileData: string): Promise<void> => {
if (this.transferData == undefined) return;
const decrypted: string = await decryptString(
@@ -93,7 +94,7 @@ export default class FileTransferModel {
};
// sending
sendFiles = (
readonly sendFiles = (
directoryPaths: IteratorObject<string[]>,
callback: (path: string) => void,
): void => {
@@ -108,7 +109,7 @@ export default class FileTransferModel {
}
};
sendFile = async (filePath: string[]): Promise<void> => {
readonly sendFile = async (filePath: string[]): Promise<void> => {
if (this.transferData == undefined) return;
const fileContent: string | null = this.storageModel.read(filePath);
if (fileContent == null) return;
+12 -12
View File
@@ -1,4 +1,4 @@
// this file is responsible for all settings.
// cleanup: Phase A
import StorageModel, { StorageModelSubPaths, filePaths } from "./storageModel";
@@ -12,10 +12,10 @@ export default class SettingsModel {
theme: string;
// storage
private storeSetting(
private readonly storeSetting = (
pathName: keyof typeof filePaths.settingsModel,
value: string,
): void {
): void => {
const path = StorageModel.getPath(
StorageModelSubPaths.SettingsModel,
filePaths.settingsModel[pathName],
@@ -23,28 +23,28 @@ export default class SettingsModel {
this.storageModel.write(path, value);
}
setName = (newValue: string): void => {
readonly setName = (newValue: string): void => {
this.username = newValue;
this.storeSetting("username", newValue);
};
setFirstDayOfWeek = (newValue: string): void => {
readonly setFirstDayOfWeek = (newValue: string): void => {
this.firstDayOfWeek = newValue;
this.storeSetting("firstDayOfWeek", newValue);
};
setLanguage = (newValue: string): void => {
readonly setLanguage = (newValue: string): void => {
this.language = newValue;
this.storeSetting("language", newValue);
};
setTheme = (newValue: string): void => {
readonly setTheme = (newValue: string): void => {
this.theme = newValue;
this.storeSetting("theme", newValue);
};
// load
private readSetting = (
private readonly readSetting = (
pathName: keyof typeof filePaths.settingsModel,
): string => {
const path = StorageModel.getPath(
@@ -54,22 +54,22 @@ export default class SettingsModel {
return this.storageModel.read(path);
};
loadUsername = (): void => {
readonly loadUsername = (): void => {
const content: string | null = this.readSetting("username");
this.username = content ?? "";
};
loadFirstDayofWeek = (): void => {
readonly loadFirstDayofWeek = (): void => {
const content: string | null = this.readSetting("firstDayOfWeek");
this.firstDayOfWeek = content ?? "0";
};
loadLanguage = (): void => {
readonly loadLanguage = (): void => {
const content: string | null = this.readSetting("language");
this.language = content ?? SettingsModel.getSystemLanguage();
};
loadTheme = (): void => {
readonly loadTheme = (): void => {
const content: string | null = this.readSetting("theme");
this.theme = content ?? ThemeSettings.System;
};
+16 -16
View File
@@ -1,7 +1,7 @@
// this file is responsible for reading and writing persistent data.
// cleanup: Phase A
import { DATA_VERSION, ValidObject } from "../Utility/typeSafety";
import { localeCompare, parseValidObject, stringify } from "../Utility/utility";
import { DATA_VERSION, ValidObject } from "../Utility/typeSafety";
export const PATH_COMPONENT_SEPARATOR = "\\";
@@ -9,14 +9,14 @@ export default class StorageModel {
storageEntryTree: StorageEntry = {};
// read
read = (pathComponents: string[]): string | null => {
readonly read = (pathComponents: string[]): string | null => {
const pathString: string = StorageModel.pathComponentsToString(
...pathComponents,
);
return localStorage.getItem(pathString);
};
list = (pathComponents: string[]): string[] => {
readonly list = (pathComponents: string[]): string[] => {
let currentParent: StorageEntry = this.storageEntryTree;
for (const component of pathComponents) {
const nextParent: StorageEntry | undefined =
@@ -29,7 +29,7 @@ export default class StorageModel {
};
// write
write = (pathComponents: string[], value: string): void => {
readonly write = (pathComponents: string[], value: string): void => {
const pathString: string = StorageModel.pathComponentsToString(
...pathComponents,
);
@@ -37,7 +37,7 @@ export default class StorageModel {
this.updateTree(...pathComponents);
};
remove = (
readonly remove = (
pathComponents: string[],
shouldInitialize: boolean = true,
): void => {
@@ -51,7 +51,7 @@ export default class StorageModel {
}
};
rename = (
readonly rename = (
sourcePathComponents: string[],
destinationPathComponents: string[],
shouldInitialize: boolean = true,
@@ -69,7 +69,7 @@ export default class StorageModel {
};
// recursion
recurse = (rootDirectory: string[], fn: (path: string[]) => void): void => {
readonly recurse = (rootDirectory: string[], fn: (path: string[]) => void): void => {
loop_over_files: for (const key of Object.keys(localStorage)) {
// get path of current entity
const pathComponentsOfCurrentEntity: string[] =
@@ -92,14 +92,14 @@ export default class StorageModel {
this.initializeTree();
};
removeRecursively = (pathComponents: string[]): void => {
readonly removeRecursively = (pathComponents: string[]): void => {
this.recurse(pathComponents, (path: string[]) =>
this.remove(path, false),
);
this.initializeTree();
};
renameRecursively = (
readonly renameRecursively = (
sourcePathComponents: string[],
destinationPathComponents: string[],
): void => {
@@ -120,7 +120,7 @@ export default class StorageModel {
};
// stringifiable
writeStringifiable = (
readonly writeStringifiable = (
pathComponents: string[],
value: ValidObject,
): void => {
@@ -128,7 +128,7 @@ export default class StorageModel {
this.write(pathComponents, valueString);
};
readStringifiable = <T extends ValidObject>(
readonly readStringifiable = <T extends ValidObject>(
pathComponents: string[],
reference: T,
): T | null => {
@@ -142,7 +142,7 @@ export default class StorageModel {
};
// cleaning
removeJunk = (): void => {
readonly removeJunk = (): void => {
this.recurse([], (path: string[]) => {
if (path[0] == DATA_VERSION) return;
this.remove(path);
@@ -150,7 +150,7 @@ export default class StorageModel {
};
// tree
initializeTree = (): void => {
readonly initializeTree = (): void => {
console.log("initializing tree");
this.storageEntryTree = {};
@@ -161,7 +161,7 @@ export default class StorageModel {
}
};
updateTree = (...pathComponents: string[]): void => {
readonly updateTree = (...pathComponents: string[]): void => {
let currentParent: StorageEntry = this.storageEntryTree;
for (const pathPart of pathComponents) {
if (!currentParent[pathPart]) {
@@ -172,7 +172,7 @@ export default class StorageModel {
}
};
printTree = (): string => {
readonly printTree = (): string => {
return stringify(this.storageEntryTree);
};