mime-chat/src/background/session.ts

166 lines
4.3 KiB
TypeScript

/*
* Creates a websocket session with Crimata Servers.
*
* Connects to Servers and attempts key authentication. Server will respond
* with key and user profile. We send the profile to the browser. We also
* resend this information on new broser window. We then serve as a
* communication interface between the window and the servers. It will
* automatically try to reconnect on websocket disconnect.
*/
import { backgroundMitt } from "@/modules/emitter";
import { ipcEmit, loadState, saveToJson } from './helpers';
import { ipcMain, IpcMainEvent, IpcMainInvokeEvent } from "electron";
import useWebSockets from "@/modules/websockets";
import { play } from "./audio";
import { renderMessage } from "@/modules/message";
import { AuthProtocol, SessionState, Profile } from "@/types";
let win = true;
// Info saved to json on quit (key, newMessages).
let state: SessionState;
// Profile of current user.
let profile: Profile | boolean;
// Called when server sends auth message.
const updateState = (res: AuthProtocol) => {
console.log("SESS:Auth message received: \n" +
` key: ${res.key}\n` +
` alias: ${res.profile}`)
if (state) {
// Update key.
state.key = res.key;
// Update the user profile.
profile = res.profile;
// Send upated profile to frontend.
console.log("SESS:Sending updated user profile to browser.")
ipcEmit("update-state", {
profile: profile,
newMessages: state.newMessages
})
// Save the updated state to json.
console.log("SESS:Saving session state.")
saveToJson("session.json", state)
}
}
// Send state on new window.
const onNewBrowserWindow = (_event: IpcMainInvokeEvent, _payload: any) => {
if (typeof profile !== 'undefined') {
console.log("SESS:Sending user profile to browser.")
ipcEmit("update-state", {
profile: profile,
newMessages: state.newMessages
})
}
}
// Calls appropriate endpoint for a server message.
const onMessage = (data: string) => {
let message = JSON.parse(data)
// AuthProtocol message.
if (message.hasOwnProperty("key")) {
updateState(message)
}
// Standard message.
else if (message.content) {
// Convert to render message
message = renderMessage(
message.content.text,
message.content.audio,
message.context,
message.modifier
);
if (win) {
console.log("SESS:Emitting standard message.")
if (message.audio) {
play(message.audio)
}
ipcEmit("render-message", message)
}
else {
console.log("SESS:No window: saving message.")
state.newMessages.push(message);
}
}
else {
if (win) {
ipcEmit("render-message", message)
}
}
};
// When socket connects, we update state.
const onOpen = () => {
console.log(`SESS:Sending key: ${state.key}`)
if (state) {
sendMessage({
"key": state.key,
"usr": false,
"pwd": false
})
}
}
// Websockets module.
const { createSocket, sendMessage } = useWebSockets(onMessage, onOpen);
// Handle messages from window/client.
const onClientMessage = (_event: IpcMainEvent, payload: any) => {
console.log("New client message")
const success = sendMessage(payload)
if (!success) {
console.log("Unable to send message: ", payload)
}
}
// Call this to initialize session with Crimata servers.
export const initSession = () => {
console.log("SESS:Creating new session.")
// Load Json or createState.
state = loadState("session.json")
console.log("SESS:State loaded: \n" +
` key: ${state.key}\n` +
` new: ${state.newMessages}`)
// Open socket connection.
createSocket()
// Attack browser window init listener.
ipcMain.removeAllListeners("app-mounted")
ipcMain.on("app-mounted", onNewBrowserWindow);
// Attach listeners for frontend.
ipcMain.removeAllListeners("client-message")
ipcMain.on("client-message", onClientMessage);
// Keep win up-to-date.
backgroundMitt.on('window-active', (state: boolean) => {
win = state;
});
}