prepare FileModel to manage files, cleanup

This commit is contained in:
marlon-erler
2024-07-21 23:32:20 +02:00
parent 5443d045db
commit e2c01138bb
5 changed files with 98 additions and 23 deletions
+4
View File
@@ -3,3 +3,7 @@ export const DATA_VERSION = "v2"
export function checkIsValidObject(object: any): boolean { export function checkIsValidObject(object: any): boolean {
return object.dataVersion == DATA_VERSION; return object.dataVersion == DATA_VERSION;
} }
export interface ValidObject {
dataVersion: "v2";
}
+6 -6
View File
@@ -2,6 +2,7 @@
import FileModel, { File } from "./fileModel"; import FileModel, { File } from "./fileModel";
import StorageModel, { storageKeys } from "./storageModel"; import StorageModel, { storageKeys } from "./storageModel";
import { ValidObject, checkIsValidObject } from "./Utility/typeSafety";
import { import {
createTimestamp, createTimestamp,
parse, parse,
@@ -14,7 +15,6 @@ import ChatListModel from "./chatListModel";
import { Color } from "../ViewModel/colors"; import { Color } from "../ViewModel/colors";
import ConnectionModel from "./connectionModel"; import ConnectionModel from "./connectionModel";
import SettingsModel from "./settingsModel"; import SettingsModel from "./settingsModel";
import { checkIsValidObject } from "./Utility/typeSafety";
import { v4 } from "uuid"; import { v4 } from "uuid";
export default class ChatModel { export default class ChatModel {
@@ -230,12 +230,14 @@ export default class ChatModel {
connectionModel.setMessageSentHandler(this.handleMessageSent); connectionModel.setMessageSentHandler(this.handleMessageSent);
this.fileModel = new FileModel(this); this.fileModel = new FileModel(this, this.storageModel);
} }
// utility // utility
static generateChatInfo = (primaryChannel: string): ChatInfo => { static generateChatInfo = (primaryChannel: string): ChatInfo => {
return { return {
dataVersion: "v2",
primaryChannel, primaryChannel,
secondaryChannels: [], secondaryChannels: [],
encryptionKey: "", encryptionKey: "",
@@ -281,7 +283,7 @@ export default class ChatModel {
} }
// types // types
export interface ChatInfo { export interface ChatInfo extends ValidObject {
primaryChannel: string; primaryChannel: string;
secondaryChannels: string[]; secondaryChannels: string[];
encryptionKey: string; encryptionKey: string;
@@ -295,9 +297,7 @@ export enum ChatMessageStatus {
Received = "received", Received = "received",
} }
export interface ChatMessage { export interface ChatMessage extends ValidObject {
dataVersion: "v2";
id: string; id: string;
channel: string; channel: string;
+75 -11
View File
@@ -1,11 +1,14 @@
// this file is responsible for managing files within chats. // this file is responsible for managing files within chats.
import ChatModel, { ChatMessage } from "./chatModel"; import ChatModel, { ChatMessage } from "./chatModel";
import StorageModel, { storageKeys } from "./storageModel";
import { parseValidObject, stringify } from "./Utility/utility";
import { parseValidObject } from "./Utility/utility"; import { ValidObject } from "./Utility/typeSafety";
export default class FileModel { export default class FileModel {
chatModel: ChatModel; chatModel: ChatModel;
storageModel: StorageModel;
// handler // handler
handleStringifiedFile = (stringifiedFile: string): void => { handleStringifiedFile = (stringifiedFile: string): void => {
@@ -18,25 +21,86 @@ export default class FileModel {
this.chatModel.sendMessage("", file); this.chatModel.sendMessage("", file);
}; };
// storage
storeFile = (file: File): void => {
for (const fileContent of file.contentVersions) {
this.storeFileContent(file, fileContent);
}
};
storeFileContent = (file: File, fileContent: FileContent): void => {
const fileContentName: string = FileModel.getFileContentName(fileContent);
const fileContentPath: string[] = FileModel.getFileContentPath(
file,
fileContentName
);
const stringifiedContent: string = stringify(fileContent);
this.storageModel.write(fileContentPath, stringifiedContent);
};
listFileIds = (): string[] => {
return this.storageModel.list(storageKeys.chatFiles);
};
listFileContents = (file: File): string[] => {
const filePath: string[] = FileModel.getFilePath(file.id);
return this.storageModel.list(filePath);
};
getFile = (fileId: string): File | null => {
const filePath = FileModel.getFilePath(fileId);
const fileOrNull: File | null =
this.storageModel.readStringifiable<File>(filePath);
return fileOrNull;
};
getLatestFileContentName = (fileContentNames: string[]): string | null => {
return fileContentNames[fileContentNames.length - 1];
};
getFileContent = (
file: File,
fileContentName: string
): FileContent | null => {
const filePath = FileModel.getFileContentPath(file, fileContentName);
const fileContentOrNull: FileContent | null =
this.storageModel.readStringifiable<FileContent>(filePath);
return fileContentOrNull;
};
// init // init
constructor(chatModel: ChatModel) { constructor(chatModel: ChatModel, storageModel: StorageModel) {
this.chatModel = chatModel; this.chatModel = chatModel;
this.storageModel = storageModel;
} }
// utility
static getFilePath = (fileId: string): string[] => {
return [...storageKeys.chatFiles, fileId];
};
static getFileContentName = (fileContent: FileContent): string => {
return fileContent.creationDate + fileContent.id;
};
static getFileContentPath = (
file: File,
fileContentName: string
): string[] => {
const filePath: string[] = FileModel.getFilePath(file.id);
return [...filePath, fileContentName];
};
} }
// types // types
export interface File { export interface File extends ValidObject {
dataVersion: "v2";
id: string; id: string;
title: string; contentVersions: FileContent[];
contentVersions: { [id: string]: FileContent };
} }
export interface FileContent { export interface FileContent extends ValidObject {
dataVersion: "v2";
id: string; id: string;
creationDate: string; creationDate: string;
type: string;
} }
+1
View File
@@ -0,0 +1 @@
// this file is responsible for managing message objects.c
+12 -6
View File
@@ -1,8 +1,12 @@
// this file is responsible for reading and writing persistent data; all storage shall be handled by this file. // this file is responsible for reading and writing persistent data; all storage shall be handled by this file.
import { localeCompare, parse, stringify } from "./Utility/utility"; import { DATA_VERSION, ValidObject } from "./Utility/typeSafety";
import {
import { DATA_VERSION } from "./Utility/typeSafety"; localeCompare,
parse,
parseValidObject,
stringify,
} from "./Utility/utility";
export const PATH_COMPONENT_SEPARATOR = "\\"; export const PATH_COMPONENT_SEPARATOR = "\\";
@@ -69,16 +73,17 @@ export default class StorageModel {
}; };
// stringifiable // stringifiable
writeStringifiable = (pathComponents: string[], value: any): void => { writeStringifiable = (pathComponents: string[], value: ValidObject): void => {
const valueString: string = stringify(value); const valueString: string = stringify(value);
this.write(pathComponents, valueString); this.write(pathComponents, valueString);
}; };
readStringifiable = (pathComponents: string[]): any | null => { readStringifiable = <T extends ValidObject>(pathComponents: string[]): T | null => {
const valueString: string | null = this.read(pathComponents); const valueString: string | null = this.read(pathComponents);
if (!valueString) return null; if (!valueString) return null;
return parse(valueString); const object: T | null = parseValidObject(valueString);
return object;
}; };
// init // init
@@ -168,4 +173,5 @@ export const storageKeys = {
], ],
chatColor: (id: string) => [DATA_VERSION, "chat", id, "color"], chatColor: (id: string) => [DATA_VERSION, "chat", id, "color"],
chatMessages: (id: string) => [DATA_VERSION, "chat", id, "messages"], chatMessages: (id: string) => [DATA_VERSION, "chat", id, "messages"],
chatFiles: [DATA_VERSION, "chat", "files"],
}; };