This commit is contained in:
marlon-erler
2024-07-09 11:39:23 +02:00
parent 4003ab701a
commit ff0f3d9499
3 changed files with 66 additions and 42 deletions
+60 -28
View File
@@ -3,46 +3,42 @@ import * as React from "bloatless-react";
import { UDN, isConnected } from "./model"; import { UDN, isConnected } from "./model";
import { decryptString, encryptString } from "../cryptUtility"; import { decryptString, encryptString } from "../cryptUtility";
import { Message } from "udn-frontend";
import { senderName } from "./viewModel"; import { senderName } from "./viewModel";
import { storageKeys } from "../utility"; import { storageKeys } from "../utility";
// TYPES // TYPES
// message // message
export interface Message { export interface ChatMessage {
channel: string; channel: string;
sender: string; sender: string;
body: string; body: string;
isoDate: string; isoDate: string;
} }
export class Message {
constructor(
public channel: string,
public sender: string,
public body: string,
public isoDate: string
) {}
}
// chat // chat
export class Chat { export class Chat {
id: string; id: string;
primaryChannel: React.State<string>; isSubscribed = new React.State(false);
currentChannel = new React.State("");
primaryChannelInput: React.State<string>;
secondaryChannels: React.ListState<string>; secondaryChannels: React.ListState<string>;
encryptionKey: React.State<string>; encryptionKey: React.State<string>;
messages: React.ListState<Message>; messages: React.ListState<ChatMessage>;
composingMessage: React.State<string>; composingMessage: React.State<string>;
cannotSendMessage: React.State<boolean>;
newSecondaryChannelName: React.State<string>; newSecondaryChannelName: React.State<string>;
cannotSendMessage: React.State<boolean>;
cannotAddSecondaryChannel: React.State<boolean>; cannotAddSecondaryChannel: React.State<boolean>;
cannotSetChannel: React.State<boolean>;
// init // init
constructor(id: string = React.UUID()) { constructor(id: string = React.UUID()) {
this.primaryChannel = React.restoreState( this.primaryChannelInput = React.restoreState(
storageKeys.primaryChannel(id), storageKeys.primaryChannel(id),
"" ""
); );
@@ -60,16 +56,48 @@ export class Chat {
this.newSecondaryChannelName = new React.State(""); this.newSecondaryChannelName = new React.State("");
this.cannotSendMessage = React.createProxyState( this.cannotSendMessage = React.createProxyState(
[this.primaryChannel, this.composingMessage, isConnected], [
this.primaryChannelInput,
this.composingMessage,
this.isSubscribed,
isConnected,
],
() => () =>
this.primaryChannel.value == "" || this.primaryChannelInput.value == "" ||
this.composingMessage.value == "" || this.composingMessage.value == "" ||
this.isSubscribed.value == false ||
isConnected.value == false isConnected.value == false
); );
this.cannotAddSecondaryChannel = React.createProxyState( this.cannotAddSecondaryChannel = React.createProxyState(
[this.newSecondaryChannelName], [this.newSecondaryChannelName],
() => this.newSecondaryChannelName.value == "" () => this.newSecondaryChannelName.value == ""
); );
this.cannotSetChannel = React.createProxyState(
[this.primaryChannelInput, this.currentChannel],
() =>
this.primaryChannelInput.value == "" ||
this.primaryChannelInput.value == this.currentChannel.value
);
}
// handlers
onmessage(data: Message): void {
if (data.messageChannel && data.messageChannel != this.currentChannel.value)
return;
if (data.subscribed != undefined) this.handleSubscription(data.subscribed);
if (!data.messageBody) return;
const { sender, body, channel, isoDate } = JSON.parse(data.messageBody);
this.handleMessage({ sender, body, channel, isoDate });
}
handleSubscription(isSubscribed: boolean): void {
this.isSubscribed.value = isSubscribed;
}
handleMessage(chatMessage: ChatMessage): void {
this.messages.add(chatMessage);
} }
// messages // messages
@@ -81,7 +109,7 @@ export class Chat {
...this.secondaryChannels.value.values(), ...this.secondaryChannels.value.values(),
].map((channel) => channel); ].map((channel) => channel);
const allChannelNames: string[] = [ const allChannelNames: string[] = [
this.primaryChannel.value, this.primaryChannelInput.value,
...secondaryChannelNames, ...secondaryChannelNames,
]; ];
@@ -95,12 +123,12 @@ export class Chat {
// create object // create object
const joinedChannelName = allChannelNames.join("/"); const joinedChannelName = allChannelNames.join("/");
const messageObject = new Message( const messageObject: ChatMessage = {
joinedChannelName, channel: joinedChannelName,
senderName.value, sender: senderName.value,
encrypted, body: encrypted,
new Date().toISOString() isoDate: new Date().toISOString(),
); };
const messageString = JSON.stringify(messageObject); const messageString = JSON.stringify(messageObject);
// send // send
@@ -114,17 +142,21 @@ export class Chat {
this.messages.clear(); this.messages.clear();
} }
deleteMessage(message: Message): void { deleteMessage(message: ChatMessage): void {
this.messages.remove(message); this.messages.remove(message);
} }
async decryptReceivedMessage(message: Message): Promise<void> { async decryptReceivedMessage(message: ChatMessage): Promise<void> {
message.body = await decryptString(message.body, this.encryptionKey.value); message.body = await decryptString(message.body, this.encryptionKey.value);
this.messages.callSubscriptions(); this.messages.callSubscriptions();
} }
// channel // channel
setChannel(): void {} setChannel(): void {
if (this.cannotSetChannel.value == true) return;
this.currentChannel.value = this.primaryChannelInput.value;
UDN.subscribe(this.currentChannel.value);
}
addSecondaryChannel(): void { addSecondaryChannel(): void {
if (this.cannotAddSecondaryChannel.value == true) return; if (this.cannotAddSecondaryChannel.value == true) return;
@@ -146,7 +178,7 @@ export const chats = new React.ListState<Chat>(chatArray);
// METHODS // METHODS
export function createChatWithName(name: string): void { export function createChatWithName(name: string): void {
const newChat = new Chat(); const newChat = new Chat();
newChat.primaryChannel.value = name; newChat.primaryChannelInput.value = name;
chatIds.add(newChat.id); chatIds.add(newChat.id);
} }
+4 -11
View File
@@ -1,17 +1,8 @@
import * as React from "bloatless-react"; import * as React from "bloatless-react";
import {
arrayToUint8,
decrypt,
encrypt,
generateIV,
importKey,
uInt8ToArray,
} from "../cryptUtility";
import UDNFrontend from "udn-frontend"; import UDNFrontend from "udn-frontend";
import { chats } from "./chatModel";
import { serverAddress } from "./viewModel"; import { serverAddress } from "./viewModel";
import { translation } from "../translations";
export const UDN = new UDNFrontend(); export const UDN = new UDNFrontend();
@@ -52,7 +43,9 @@ UDN.onconnect = () => {
UDN.onmessage = (data) => { UDN.onmessage = (data) => {
chats.value.forEach((chat) => {
chat.onmessage(data);
})
}; };
UDN.ondisconnect = () => { UDN.ondisconnect = () => {
+2 -3
View File
@@ -1,5 +1,6 @@
import * as React from "bloatless-react"; import * as React from "bloatless-react";
import { Chat } from "./chatModel";
import { translation } from "../translations"; import { translation } from "../translations";
// connection // connection
@@ -16,6 +17,4 @@ export const isEncryptionUnavailable = window.crypto.subtle == undefined;
export const senderName = React.restoreState("sender-name", ""); export const senderName = React.restoreState("sender-name", "");
// chat // chat
export const newChatPrimaryChannelName = new React.State(""); export const selectedChat = new React.State<Chat | undefined>(undefined);
export const newChatSecondaryChannelName = new React.State("");
export const newChatSecondaryChannelNames = new React.ListState<string>();