"use strict"; import WebSocket from 'ws'; import { backgroundMitt } from './emitter'; import { ipcMain } from "electron"; import { play } from './audio'; import { AuthMessage, Profile, Annotation, StandardMessage, ClientMessage } from "@/types/message/index"; import { clientMessage, renderMessage } from '@/modules/message'; 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, token: string) => { return new Promise((resolve, reject) => { console.log('Authenticating...'); // Handle auth response from server. backgroundMitt.once('auth-res', (res: string) => { if (res == "locked") { reject(res); } else { console.log('Success!'); auth = true; resolve(res); } }); if (token) { socket.send(token); } else { socket.send("no-token"); } }); }; //---Message Handlers----------------------------------------------- const handleAuthMessage = (message: string) => { backgroundMitt.emit('auth-res', message); } const handleProfileMessage = (message: Profile) => { backgroundMitt.emit('ipc-renderer', { endpoint: 'update-profile', message: message }); } const handleStandardMessage = (m: StandardMessage) => { // Create a render message object. const message = renderMessage( m.content.text, m.content.audio, m.context, m.modifier); // Play audio if any. if (message.content.audio) { const audioBytes = Buffer.from(m.content.audio as string, 'hex'); m.content.audio = true; play(audioBytes); } backgroundMitt.emit('ipc-renderer', { endpoint: 'render-message', message: message }); } const handleAnnotationMessage = (message: Annotation) => { backgroundMitt.emit('ipc-renderer', { endpoint: 'annotate-message', message: message }); } //------------------------------------------------------------------ const onMessage = (messageStr: string): void => { // Auth messages are strings. if (!auth) handleAuthMessage(messageStr) const message = JSON.parse(messageStr) if (message.content) { handleStandardMessage(message) } else if (message.first) { handleProfileMessage(message) } else { handleAnnotationMessage(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)); }