Merge remote-tracking branch 'origin/main' into new_architecture
This commit is contained in:
commit
ab487e4f5e
9 changed files with 695 additions and 1 deletions
|
|
@ -24,7 +24,6 @@
|
||||||
"animejs": "^3.2.0",
|
"animejs": "^3.2.0",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"dotenv": "^10.0.0",
|
|
||||||
"electron-is-dev": "^2.0.0",
|
"electron-is-dev": "^2.0.0",
|
||||||
"electron-store": "^8.0.0",
|
"electron-store": "^8.0.0",
|
||||||
"electron-updater": "^4.3.8",
|
"electron-updater": "^4.3.8",
|
||||||
|
|
|
||||||
212
src/App.vue
Normal file
212
src/App.vue
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
<template>
|
||||||
|
<!-- Only render when profile has been set -->
|
||||||
|
<div id="app" v-if="(ready)">
|
||||||
|
|
||||||
|
<button id="titlebar" />
|
||||||
|
|
||||||
|
<!-- Minimize and exit buttons. -->
|
||||||
|
<span class="menu">
|
||||||
|
<button
|
||||||
|
class="menuButton exitButton"
|
||||||
|
@click.prevent="post('nav-bar', 'close')"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="menuButton minimizeButton"
|
||||||
|
@click.prevent="post('nav-bar', 'min')"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Main Pages -->
|
||||||
|
<Messenger
|
||||||
|
v-if="profile"
|
||||||
|
:profile="profile"
|
||||||
|
:newMessages="newMessages"
|
||||||
|
/>
|
||||||
|
<Login v-else />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Show spash screen if ready is false -->
|
||||||
|
<Splash v-else />
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, onMounted, onUnmounted, ref } from "vue";
|
||||||
|
import { IpcRendererEvent } from "electron";
|
||||||
|
import { useIpc } from "@/modules/ipc";
|
||||||
|
import { useProfile } from "@/modules/auth"
|
||||||
|
import { invokeProfile } from "@/ipcRend/account";
|
||||||
|
import { postInitSession, postMount } from "@/ipcRend/session";
|
||||||
|
|
||||||
|
import Splash from "@/components/splash.vue";
|
||||||
|
import Messenger from "@/components/messenger.vue";
|
||||||
|
import Login from "@/components/login.vue";
|
||||||
|
|
||||||
|
import { Profile } from "@/types";
|
||||||
|
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Splash,
|
||||||
|
Messenger,
|
||||||
|
Login
|
||||||
|
},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
const { post, invoke } = useIpc();
|
||||||
|
|
||||||
|
const { profile, setProfile, clearProfile } = useProfile();
|
||||||
|
|
||||||
|
// Whether browser has received user info yet.
|
||||||
|
const ready = ref(false);
|
||||||
|
|
||||||
|
// New messages that browser missed while closed.
|
||||||
|
const newMessages = ref([]);
|
||||||
|
|
||||||
|
// Receive updated information about the session.
|
||||||
|
const updateState = (_event: IpcRendererEvent, payload: any) => {
|
||||||
|
console.log('YAYAYAYAYA');
|
||||||
|
console.log("APP:Received updated profile and new messages: \n" +
|
||||||
|
` profile: ${payload.message.profile}\n` +
|
||||||
|
` new: ${payload.message.newMessages}`);
|
||||||
|
|
||||||
|
if (payload.message.profile) {
|
||||||
|
console.log(`APP:Logged-in, showing Messenger View.`);
|
||||||
|
} else {
|
||||||
|
console.log(`APP:Logged-out, showing Login View.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
newMessages.value = payload.message.newMessages;
|
||||||
|
|
||||||
|
ready.value = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSessionAuthFail = (_event: IpcRendererEvent, _payload: null) => {
|
||||||
|
clearProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
console.log("APP:mounted.");
|
||||||
|
|
||||||
|
window.ipcRenderer.on("session-auth-fail", onSessionAuthFail)
|
||||||
|
window.ipcRenderer.on("update-state", updateState)
|
||||||
|
window.ipcRenderer.on("update_available", () => {
|
||||||
|
console.log('testing auto update');
|
||||||
|
})
|
||||||
|
|
||||||
|
window.ipcRenderer.on("update_downloaded", () => {
|
||||||
|
console.log('testing update download');
|
||||||
|
})
|
||||||
|
|
||||||
|
postMount();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const profile = await invokeProfile() as Profile;
|
||||||
|
setProfile(profile);
|
||||||
|
} catch(e) {
|
||||||
|
console.log('[REND] Auth:', e);
|
||||||
|
clearProfile();
|
||||||
|
} finally {
|
||||||
|
ready.value = true;
|
||||||
|
if (profile.value.crimataId) {
|
||||||
|
// start session
|
||||||
|
postInitSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.ipcRenderer.removeAllListeners("update-state");
|
||||||
|
window.ipcRenderer.removeAllListeners("session-auth-fail");
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
ready,
|
||||||
|
post,
|
||||||
|
newMessages,
|
||||||
|
profile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
// Background color set in window.ts
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
font-family: "SF Pro Text";
|
||||||
|
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#titlebar {
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
|
width: 100vw;
|
||||||
|
height: 54px;
|
||||||
|
|
||||||
|
opacity: 0.75;
|
||||||
|
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
position: fixed;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuButton {
|
||||||
|
border: none;
|
||||||
|
outline:none;
|
||||||
|
min-width: 14px;
|
||||||
|
min-height: 14px;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exitButton {
|
||||||
|
background-color: #FF6157;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exitButton:active {
|
||||||
|
background: #c14645;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minimizeButton {
|
||||||
|
background-color: #FFC12F;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.minimizeButton:active {
|
||||||
|
background-color: #c08e38;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
13
src/authPayload.ts
Normal file
13
src/authPayload.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
import { store } from "@/background/store";
|
||||||
|
|
||||||
|
interface PlatformAuthProtocol {
|
||||||
|
key: string;
|
||||||
|
crimata_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getAuthPayload = (): PlatformAuthProtocol => ({
|
||||||
|
key: store.get('key'),
|
||||||
|
crimata_id: store.get('crimataId')
|
||||||
|
});
|
||||||
|
|
||||||
25
src/background.ts
Normal file
25
src/background.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Entry point for Crimata electron app.
|
||||||
|
* "Look on my Works, ye Mighty, and despair!"
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { initApp } from './background/init';
|
||||||
|
import { protocol } from "electron";
|
||||||
|
|
||||||
|
// Scheme must be registered before the app is ready
|
||||||
|
protocol.registerSchemesAsPrivileged([
|
||||||
|
{ scheme: "app", privileges: { secure: true, standard: true } }
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Load environment variable
|
||||||
|
const isDev = require('electron-is-dev');
|
||||||
|
|
||||||
|
// NOTE Program Begins Here
|
||||||
|
(() => {
|
||||||
|
|
||||||
|
console.log('Starting Crimata electron app.');
|
||||||
|
initApp(isDev);
|
||||||
|
|
||||||
|
})();
|
||||||
119
src/background/ipc/account.ts
Normal file
119
src/background/ipc/account.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { Profile } from "@/types";
|
||||||
|
import { submit, fetchProfile, logout } from "@/api/account";
|
||||||
|
import { ipcMain, IpcMainInvokeEvent } from "electron";
|
||||||
|
import { store } from "@/background/store";
|
||||||
|
import { endSession } from "@/background/session";
|
||||||
|
|
||||||
|
|
||||||
|
const parseAuthRes = (authRes: any) => {
|
||||||
|
const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string;
|
||||||
|
const profile = authRes.data as Profile;
|
||||||
|
return {
|
||||||
|
token,
|
||||||
|
profile
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const onProfile = async (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
_payload: null
|
||||||
|
): Promise<Profile | Error> => (
|
||||||
|
|
||||||
|
new Promise(async (resolve, reject) => {
|
||||||
|
console.log('[IPC]: user-profile');
|
||||||
|
|
||||||
|
// get jwt token and crimataId from store
|
||||||
|
const token = store.get('key');
|
||||||
|
const crimataId = store.get('crimataId');
|
||||||
|
|
||||||
|
// authenticate and fetch profile
|
||||||
|
try {
|
||||||
|
|
||||||
|
const res = await fetchProfile(
|
||||||
|
crimataId,
|
||||||
|
token
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsed = parseAuthRes(res);
|
||||||
|
resolve(parsed.profile);
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
reject(new Error('Unable to authenticate and fetch account profile.'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const onLogin = async (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
payload: string
|
||||||
|
): Promise<Profile | Error> => (
|
||||||
|
|
||||||
|
new Promise(async (resolve, reject) => {
|
||||||
|
console.log('[IPC]: user-login');
|
||||||
|
|
||||||
|
const account = JSON.parse(payload);
|
||||||
|
|
||||||
|
if ( account.password && account.email ) {
|
||||||
|
try {
|
||||||
|
const res = await submit(account.email, account.password);
|
||||||
|
const parsed = parseAuthRes(res);
|
||||||
|
|
||||||
|
// save jwt token and profile
|
||||||
|
store.set('key', parsed.token);
|
||||||
|
store.set('crimataId', parsed.profile.crimataId);
|
||||||
|
|
||||||
|
// return profile to renderer
|
||||||
|
resolve(parsed.profile);
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
console.log('[API]', e);
|
||||||
|
reject(new Error('Failed to authenticate'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const onLogout = async (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
_payload: null
|
||||||
|
): Promise<void> => (
|
||||||
|
|
||||||
|
new Promise(async (resolve, reject) => {
|
||||||
|
console.log('[IPC]: user-logout');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// post logout to backend
|
||||||
|
await logout();
|
||||||
|
|
||||||
|
// remove key and crimataId
|
||||||
|
store.delete('key');
|
||||||
|
store.delete('crimataId');
|
||||||
|
|
||||||
|
// TODO: kill crimata platform session
|
||||||
|
endSession();
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
} catch(e) {
|
||||||
|
reject(new Error('Failed to logout. Please try again.'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
export default function useAccountListeners(): void {
|
||||||
|
|
||||||
|
ipcMain.removeHandler("user-profile");
|
||||||
|
ipcMain.handle("user-profile", onProfile);
|
||||||
|
|
||||||
|
ipcMain.removeHandler("user-login");
|
||||||
|
ipcMain.handle("user-login", onLogin);
|
||||||
|
|
||||||
|
ipcMain.removeHandler("user-logout");
|
||||||
|
ipcMain.handle("user-logout", onLogout);
|
||||||
|
|
||||||
|
}
|
||||||
62
src/background/ipc/session.ts
Normal file
62
src/background/ipc/session.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { initSession, emitNewMessages, sendMessage } from '@/background/session';
|
||||||
|
import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron";
|
||||||
|
import { initAudioIO } from "@/background/audio";
|
||||||
|
import { ClientMessage } from "@/types";
|
||||||
|
|
||||||
|
|
||||||
|
// Instantiate socket session with crimata-platorm.
|
||||||
|
const onSessionInit = (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
_payload: null
|
||||||
|
): void => {
|
||||||
|
|
||||||
|
console.log('[IPC]: init-session');
|
||||||
|
|
||||||
|
initSession();
|
||||||
|
|
||||||
|
initAudioIO();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const onAppMounted = (
|
||||||
|
_event: IpcMainInvokeEvent,
|
||||||
|
_payload: null
|
||||||
|
): void => {
|
||||||
|
|
||||||
|
console.log('[IPC]: app-mounted');
|
||||||
|
|
||||||
|
emitNewMessages()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Handle messages from window/client.
|
||||||
|
const onClientMessage = (
|
||||||
|
_event: IpcMainEvent,
|
||||||
|
payload: ClientMessage
|
||||||
|
): void => {
|
||||||
|
|
||||||
|
console.log('[IPC]: client-message');
|
||||||
|
|
||||||
|
sendMessage(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default function useSessionListeners(): void {
|
||||||
|
|
||||||
|
console.log('[IPC]: Init session listeners.');
|
||||||
|
|
||||||
|
// Attach listeners for frontend.
|
||||||
|
ipcMain.removeAllListeners("client-message");
|
||||||
|
ipcMain.on("client-message", onClientMessage);
|
||||||
|
|
||||||
|
// Attack browser window init listener.
|
||||||
|
ipcMain.removeAllListeners("app-mounted");
|
||||||
|
ipcMain.on("app-mounted", onAppMounted);
|
||||||
|
|
||||||
|
ipcMain.removeAllListeners("init-session");
|
||||||
|
ipcMain.on("init-session", onSessionInit);
|
||||||
|
|
||||||
|
}
|
||||||
119
src/background/session.ts
Normal file
119
src/background/session.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* 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 } from './helpers';
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
|
import useWebSockets from "./websockets";
|
||||||
|
|
||||||
|
import { play } from "./audio";
|
||||||
|
import { renderMessage } from "@/modules/message";
|
||||||
|
import { SessionState } from "@/types";
|
||||||
|
|
||||||
|
let win = true;
|
||||||
|
|
||||||
|
// Info saved to json on quit (key, newMessages).
|
||||||
|
let state: SessionState;
|
||||||
|
|
||||||
|
let socket: WebSocket | null = null;
|
||||||
|
|
||||||
|
|
||||||
|
// Calls appropriate endpoint for a server message.
|
||||||
|
const onMessage = (data: string): void => {
|
||||||
|
let message = JSON.parse(data);
|
||||||
|
|
||||||
|
if (message === "CLOSE_AUTH_FAIL") {
|
||||||
|
ipcEmit("session-auth-fail", null)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard message.
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Websockets module.
|
||||||
|
const { createSocket, send } = useWebSockets(onMessage);
|
||||||
|
|
||||||
|
|
||||||
|
export const emitNewMessages = (): void => {
|
||||||
|
if (state) {
|
||||||
|
ipcEmit("update-state", {
|
||||||
|
newMessages: state.newMessages,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const sendMessage = (payload: Record<string, any>): void => {
|
||||||
|
try {
|
||||||
|
send(payload)
|
||||||
|
} catch(e) {
|
||||||
|
console.log("Unable to send message: ", payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const endSession = (): void => {
|
||||||
|
if (socket) {
|
||||||
|
socket.close();
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call this to initialize session with Crimata servers.
|
||||||
|
export const initSession = (): void => {
|
||||||
|
console.log("SESS:Creating new session.")
|
||||||
|
|
||||||
|
// Load Json or createState.
|
||||||
|
state = loadState("session.json");
|
||||||
|
|
||||||
|
// Open socket connection.
|
||||||
|
if (!socket)
|
||||||
|
socket = createSocket();
|
||||||
|
|
||||||
|
// Keep win up-to-date.
|
||||||
|
backgroundMitt.on('window-active', (state: boolean) => {
|
||||||
|
win = state;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
122
src/background/websockets.ts
Normal file
122
src/background/websockets.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
import { getAuthPayload } from "./authPayload";
|
||||||
|
import { ipcEmit } from './helpers';
|
||||||
|
|
||||||
|
let socket: WebSocket;
|
||||||
|
|
||||||
|
const socketUrl = "ws://127.0.0.1:8760"
|
||||||
|
|
||||||
|
const _connectionCheckTimeout = 4000;
|
||||||
|
const _reconnectTimeout = 1000;
|
||||||
|
let _connectionCheckInterval: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
|
||||||
|
// Run every time we want to connect to backend.
|
||||||
|
export default function useWebSockets(
|
||||||
|
receiveCallback: (s: string) => void,
|
||||||
|
openCallback?: () => void
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Returns bool (sucess or fail).
|
||||||
|
const sendMessage = (data: any) => {
|
||||||
|
console.log("WS:Sending message: ", data)
|
||||||
|
|
||||||
|
if (socket.readyState !== 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
socket.send(JSON.stringify(data))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const send = async (data: Record<string, any>): Promise<boolean> => (
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
if (socket.readyState !== 1) {
|
||||||
|
reject(false);
|
||||||
|
}
|
||||||
|
socket.send(JSON.stringify(data))
|
||||||
|
resolve(true);
|
||||||
|
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
const onOpen = (_event: WebSocket.OpenEvent) => {
|
||||||
|
|
||||||
|
console.log("WS:Connected to WS Server!");
|
||||||
|
const jwt = getAuthPayload();
|
||||||
|
socket.send(JSON.stringify(jwt));
|
||||||
|
|
||||||
|
// ping server
|
||||||
|
_connectionCheckInterval = setInterval(() => {
|
||||||
|
|
||||||
|
if (socket) socket.ping(null, true, (e: Error) => {
|
||||||
|
if (e) {
|
||||||
|
ipcEmit('connection-alive', false);
|
||||||
|
socket.close();
|
||||||
|
setTimeout(createSocket, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}, _connectionCheckTimeout);
|
||||||
|
|
||||||
|
if (openCallback) openCallback();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const onServerMessage = (event: WebSocket.MessageEvent) => {
|
||||||
|
|
||||||
|
console.log("WS:Message received: ", event.data);
|
||||||
|
|
||||||
|
receiveCallback(event.data.toString())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClose = (event: WebSocket.CloseEvent) => {
|
||||||
|
console.log("WS:Socket closed normally.", event.wasClean)
|
||||||
|
|
||||||
|
clearInterval(_connectionCheckInterval);
|
||||||
|
|
||||||
|
if (!event.wasClean) {
|
||||||
|
ipcEmit('connection-alive', false);
|
||||||
|
setTimeout(createSocket, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconnect automatically on error.
|
||||||
|
const onError = (event: WebSocket.ErrorEvent) => {
|
||||||
|
console.log("WS:WebSocket error: ", event.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const createSocket = (): WebSocket => {
|
||||||
|
|
||||||
|
if (_connectionCheckInterval) clearInterval(_connectionCheckInterval);
|
||||||
|
|
||||||
|
socket = new WebSocket(socketUrl);
|
||||||
|
|
||||||
|
// Add listeners.
|
||||||
|
socket.addEventListener("open", onOpen);
|
||||||
|
socket.addEventListener("message", onServerMessage);
|
||||||
|
socket.addEventListener("close", onClose);
|
||||||
|
socket.addEventListener("error", onError);
|
||||||
|
socket.addEventListener("pong", () => {
|
||||||
|
ipcEmit('connection-alive', true);
|
||||||
|
});
|
||||||
|
|
||||||
|
return socket;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
createSocket,
|
||||||
|
sendMessage,
|
||||||
|
send
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
23
src/ipcRend/session.ts
Normal file
23
src/ipcRend/session.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
import { useIpc } from "@/modules/ipc";
|
||||||
|
|
||||||
|
import { ClientMessage } from "@/types";
|
||||||
|
|
||||||
|
const { post } = useIpc();
|
||||||
|
|
||||||
|
|
||||||
|
export const postMount = (): void => (
|
||||||
|
post("app-mounted", null)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export const postInitSession = (): void => (
|
||||||
|
post("init-session", null)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export const postMessage = (payload: ClientMessage): void => (
|
||||||
|
post('client-message', payload)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in a new issue