mime-chat/src/background/session.ts
2021-03-12 14:01:51 -06:00

159 lines
No EOL
4 KiB
TypeScript

"use strict";
import WebSocket from 'ws';
import { backgroundMitt } from './emitter';
import { ipcMain } from "electron";
import { play } from './audio';
import { UserCreds, ClientMessage, RenderMessage, Annotation } from "@/types/message/index";
import { clientMessage, initRenderMessageFromString } from '@/modules/message';
import { v4 as uuidv4 } from 'uuid';
const ip = 'ws://127.0.0.1';
const port = 8760;
const reconnectTimeout = 3000; //ms
let socket: WebSocket;
let success = false;
let auth = false;
const onAuthSession = async (e: any, payload: string | UserCreds | null): Promise<string> => {
return new Promise((resolve, reject) => {
console.log('authenticating...');
backgroundMitt.once('auth-res', (res: string) => {
if (res === 'locked') {
reject(res);
} else {
console.log('Success!');
auth = true;
resolve(res);
}
});
if (!payload) {
socket.send('no-token');
} else if (payload instanceof String || typeof payload === 'string') {
socket.send(payload);
} else {
socket.send(JSON.stringify(payload));
}
});
};
const onMessage = (message_str: string): void => {
while (!auth) {
backgroundMitt.emit('auth-res', message_str);
return;
}
// Decode the message.
const m = JSON.parse(message_str)
let message: RenderMessage | Annotation;
// Check to see if this is a Render Message.
if (m.content) {
message = initRenderMessageFromString(message_str)
// Play audio if any.
if (message.content.audio) {
const audioBytes = Buffer.from(m.content.audio as string, 'hex');
m.content.audio = true;
play(audioBytes);
}
}
else {
message = m // Annotation
}
// Send it to the frontend.
backgroundMitt.emit('ipc-renderer', {
endpoint: 'render-message',
message: message
});
};
const onClientMessage = (e: any, payload: ClientMessage): void => {
console.log('sending message');
socket.send(JSON.stringify(payload));
}
const restart = () => {
auth = false;
initSession();
}
// Run every time we want to connect to backend.
export function initSession(): void {
// Close existing sockets.
if (socket) {
socket.removeAllListeners();
socket.terminate();
socket.close();
success = false;
}
// Init new socket.
socket = new WebSocket(`${ip}:${port}`);
socket.binaryType = 'arraybuffer';
// handle renderer auth-token event
ipcMain.removeHandler('auth-session'); // avoid setting duplicate handlers
ipcMain.handle('auth-session', onAuthSession);
// handle user message event
ipcMain.removeAllListeners('client-message');
ipcMain.on('client-message', onClientMessage);
// handle renderer logout event
ipcMain.removeAllListeners('logout');
ipcMain.on('logout', (_event, _payload: string) => restart());
// Connect to the backend.
socket.on('open', () => {
console.log('Connected to Crimata Servers.');
// call auth renderer event on connection
backgroundMitt.emit('ipc-renderer', {
endpoint: 'auth',
message: null
});
success = true;
});
// Handle for failed connect, try again.
socket.on('error', (_e) => {
console.log('ERROR: Failed to connect.');
socket.removeAllListeners();
socket.close();
setTimeout(() => {
if (!success) {
console.log('Reconnecting...');
initSession();
}
}, reconnectTimeout);
});
socket.on('close', () => {
console.log('Connection droped! Restarting...');
restart();
});
socket.on("message", onMessage);
}
export function sendAudio(audio: string, uid: string): void {
const m = clientMessage("", audio, uid);
socket.send(JSON.stringify(m));
}