refactor frontend ipc

This commit is contained in:
riqo 2021-06-19 15:22:17 -05:00
commit 56196bcbcf
13 changed files with 177 additions and 52 deletions

View file

@ -1,8 +1,9 @@
import { postAuth, postLogin, postLogout } from "@/api/account"; import { postAuth, postLogin, postLogout } from "@/api/account";
import { endSession, launchSession } from "@/session"; import { endSession, launchSession } from "@/session";
import { getToken, clearToken, setToken } from "./store"; import { getToken, setToken, setProfile, getProfile, clearStore } from "./store";
import { parseAuthRes } from "./auth"; import { parseAuthRes } from "./auth";
import { ipcEmit } from "@/composables/useEmitter";
export const accountAuth = async (): Promise<Error | AuthState> => { export const accountAuth = async (): Promise<Error | AuthState> => {
@ -18,6 +19,7 @@ export const accountAuth = async (): Promise<Error | AuthState> => {
const parsed = parseAuthRes(res); const parsed = parseAuthRes(res);
setToken(parsed.token) setToken(parsed.token)
setProfile(parsed.profile);
return { return {
profile: parsed.profile, profile: parsed.profile,
@ -26,7 +28,7 @@ export const accountAuth = async (): Promise<Error | AuthState> => {
} catch(e) { } catch(e) {
console.log('[ACCOUNT]', e); console.log('[ACCOUNT]', e);
clearToken(); clearStore();
throw(new Error('Failed to authenticate.')); throw(new Error('Failed to authenticate.'));
} }
@ -45,6 +47,7 @@ export const accountLogin: IpcHandlerCallback<AccountCredentials, Profile> = asy
// save jwt token and profile // save jwt token and profile
setToken(parsed.token); setToken(parsed.token);
setProfile(parsed.profile);
// launch session // launch session
launchSession(parsed.token); launchSession(parsed.token);
@ -53,6 +56,7 @@ export const accountLogin: IpcHandlerCallback<AccountCredentials, Profile> = asy
return parsed.profile; return parsed.profile;
} catch(e) { } catch(e) {
clearStore();
throw e; throw e;
} }
} }
@ -65,7 +69,7 @@ export const accountLogout = async (): Promise<Error | void> => {
await postLogout(); await postLogout();
// remove key and crimataId // remove key and crimataId
clearToken(); clearStore();
// kill crimata platform session // kill crimata platform session
endSession(); endSession();
@ -79,4 +83,13 @@ export const accountLogout = async (): Promise<Error | void> => {
} }
export const updateAppState = (): void => {
const profile = getProfile();
ipcEmit("set-profile", profile);
// ipcEmit('messages') etc
}

View file

@ -1,22 +1,21 @@
import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron";
export class IpcHandler<InputType, ReturnType> implements IIpcHandler<InputType, ReturnType> { export class IpcHandler<InputParam, ReturnType> implements IIpcHandler<InputParam, ReturnType> {
readonly channel: string; readonly channel: string;
readonly _handlerCallback: IpcHandlerCallback<InputType, ReturnType>; readonly _handlerCallback: IpcHandlerCallback<InputParam, ReturnType>;
constructor(options: { constructor(options: {
channel: string; channel: string;
handlerCallback: IpcHandlerCallback<InputType, ReturnType>; handlerCallback: IpcHandlerCallback<InputParam, ReturnType>;
}) { }) {
this.channel = options.channel; this.channel = options.channel;
this._handlerCallback = options.handlerCallback; this._handlerCallback = options.handlerCallback;
} }
handle() { handle() {
console.log(`[IPC] INIT: ${this.channel}`);
this.remove(); this.remove();
ipcMain.handle(this.channel, this._onInvoke); ipcMain.handle(this.channel, this._onInvoke);
} }
@ -49,22 +48,21 @@ export class IpcHandler<InputType, ReturnType> implements IIpcHandler<InputType,
} }
export class IpcListener<InputType> implements IIpcListener<InputType> { export class IpcListener<InputParam> implements IIpcListener<InputParam> {
readonly channel: string; readonly channel: string;
readonly _listenerCallback: IpcListenerCallback<InputType>; readonly _listenerCallback: IpcListenerCallback<InputParam>;
constructor(options: { constructor(options: {
channel: string; channel: string;
listenerCallback: IpcListenerCallback<InputType>; listenerCallback: IpcListenerCallback<InputParam>;
}) { }) {
this.channel = options.channel; this.channel = options.channel;
this._listenerCallback = options.listenerCallback; this._listenerCallback = options.listenerCallback;
} }
listen() { listen() {
console.log(`[IPC] Init: ${this.channel}`);
this.remove(); this.remove();
ipcMain.on(this.channel, this._onPost); ipcMain.on(this.channel, this._onPost);
} }
@ -82,7 +80,3 @@ export class IpcListener<InputType> implements IIpcListener<InputType> {
} }
} }

View file

@ -1,10 +1,11 @@
"use strict"; "use strict";
import { accountLogin, accountLogout } from "@/account"; import { accountLogin, accountLogout, accountProfile } from "@/account";
import { IpcHandler } from "@/composables/useIpcMain"; import { IpcHandler } from "@/composables/useIpcMain";
import { flush } from "@/audio"; import { flush } from "@/audio";
const LOGIN_CHANNEL = "invoke-account-login"; const LOGIN_CHANNEL = "invoke-account-login";
const LOGOUT_CHANNEL = "invoke-account-logout"; const LOGOUT_CHANNEL = "invoke-account-logout";
const GET_AUDIO_CHANNEL = "invoke-audio-flush"; const GET_AUDIO_CHANNEL = "invoke-audio-flush";

View file

@ -2,9 +2,11 @@
import { IpcListener } from "@/composables/useIpcMain" import { IpcListener } from "@/composables/useIpcMain"
import { sendMessage } from '@/session'; import { sendMessage } from '@/session';
import { collect } from "@/audio"; import { collect } from "@/audio";
import { updateAppState } from "@/account";
const CLIENT_MESSAGE_CHANNEL = "post-session-send" const CLIENT_MESSAGE_CHANNEL = "post-session-send"
const GET_AUDIO_CHANNEL = "post-audio-collect"; const GET_AUDIO_CHANNEL = "post-audio-collect";
const APP_MOUNT_CHANNEL = "post-app-mount";
export const messageListener = new IpcListener<Message>({ export const messageListener = new IpcListener<Message>({
channel: CLIENT_MESSAGE_CHANNEL, channel: CLIENT_MESSAGE_CHANNEL,
@ -15,3 +17,8 @@ export const audioChunkListener = new IpcListener<ArrayBuffer>({
channel: GET_AUDIO_CHANNEL, channel: GET_AUDIO_CHANNEL,
listenerCallback: collect listenerCallback: collect
}); });
export const appMountListener = new IpcListener<null>({
channel: APP_MOUNT_CHANNEL,
listenerCallback: updateAppState
});

View file

@ -10,9 +10,8 @@
*/ */
import initIpcMain from "@/ipc/index"; import initIpcMain from "@/ipc/index";
import { accountAuth } from "./account"; import { accountAuth, updateAppState } from "./account";
import { launchSession } from "./session"; import { launchSession } from "./session";
import { ipcEmit } from "./composables/useEmitter";
import createWindow from "./window"; import createWindow from "./window";
let authState: AuthState | null; let authState: AuthState | null;
@ -31,12 +30,10 @@ export default async function main() {
console.log('AUTH:', e); console.log('AUTH:', e);
authState = null; authState = null;
} finally { } finally {
let profile = null;
if (authState) { if (authState) {
launchSession(authState.token as string); launchSession(authState.token as string);
profile = authState.profile;
} }
ipcEmit("set-profile", profile); updateAppState();
} }
} }

View file

@ -23,14 +23,16 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, onUnmounted, Ref, ref } from "vue"; import { defineComponent, onMounted } from "vue";
import { IpcRendererEvent } from "electron"; import { IpcRendererEvent } from "electron";
import Splash from "@/render/components/splash.vue"; import Splash from "@/render/components/splash.vue";
import Messenger from "@/render/components/messenger.vue"; import Messenger from "@/render/components/messenger.vue";
import Login from "@/render/components/login.vue"; import Login from "@/render/components/login.vue";
import Header from "@/render/components/header.vue"; import Header from "@/render/components/header.vue";
import useProfile from "@/render/composables/useProfile"; import useProfile from "@/render/composables/useProfile";
import { postAppMount } from "@/render/ipc";
export default defineComponent({ export default defineComponent({
@ -43,25 +45,9 @@ export default defineComponent({
setup() { setup() {
const authComplete = ref(false); const { profile, authComplete } = useProfile();
const { setProfile, clearProfile, profile } = useProfile(); onMounted(() => postAppMount());
onMounted(async () => {
console.log("[APP]:mounted.");
/* listen for auth related messages */
window.ipcRenderer.on("set-profile", (_event: IpcRendererEvent, payload: any) => {
console.log('progfile', payload.message)
payload.message ? setProfile(payload.message) : clearProfile();
authComplete.value = true;
});
});
onUnmounted(() => {
window.ipcRenderer.removeAllListeners("set-profile");
});
return { return {
authComplete, authComplete,

View file

@ -1,6 +1,39 @@
export default function useIpc () { import { IpcRendererEvent } from "electron";
export class IpcRendererListener<InputParam> implements IIpcListener<InputParam> {
readonly channel: string;
readonly _listenerCallback: IpcListenerCallback<InputParam>;
constructor(options: {
channel: string;
listenerCallback: IpcListenerCallback<InputParam>;
}) {
this.channel = options.channel;
this._listenerCallback = options.listenerCallback;
}
listen() {
this.remove();
window.ipcRenderer.on(this.channel, this._onPost);
}
remove() {
window.ipcRenderer.removeAllListeners(this.channel);
}
private _onPost = (_e: IpcRendererEvent, payload: IpcEmitPayload<InputParam>): void => {
console.log(`[IPC] Post: ${this.channel}`);
this._listenerCallback(payload.message);
}
}
export default function useIpcRenderer () {
const invoke = async (endpoint: string, payload: any) => { const invoke = async (endpoint: string, payload: any) => {
try { try {
const res = await window.ipcRenderer.invoke(endpoint, payload); const res = await window.ipcRenderer.invoke(endpoint, payload);
@ -16,6 +49,6 @@ export default function useIpc () {
return { return {
invoke, invoke,
post post,
} }
} }

View file

@ -2,20 +2,30 @@ import { ref } from "vue";
const profile = ref(); const profile = ref();
const authComplete = ref(false);
const useProfile = () => { const useProfile = () => {
const setProfile = (payload: Profile) => { const setProfile: IpcListenerCallback<Profile | null> = (payload) => {
profile.value = payload; payload ? profile.value = payload : clearProfile();
showRender();
} }
const clearProfile = () => { const clearProfile = () => {
profile.value = null; profile.value = null;
} }
const showRender = () => {
authComplete.value = true;
}
return { return {
setProfile, setProfile,
clearProfile, clearProfile,
profile profile,
showRender,
authComplete,
} }
} }

View file

@ -1,5 +1,6 @@
import useIpc from "@/render/composables/useIpcRend"; import useIpc from "@/render/composables/useIpcRend";
import * as rendererListeners from "./listeners";
const { post, invoke } = useIpc(); const { post, invoke } = useIpc();
@ -47,3 +48,33 @@ export const invokeSession = async (cid: string): Promise<Profile | Error> => (
export const postMessage = (payload: Message): void => ( export const postMessage = (payload: Message): void => (
post('post-session-send', payload) post('post-session-send', payload)
); );
export const postAppMount = (): void => (
post('post-app-mount', null)
);
/**
*
* Ipc Renderer Listeners
*
*/
let ipcListeners: IPCListeners = {};
export const initIpcRendererListeners = () => {
for (const [key, listener] of Object.entries(rendererListeners)) {
if (!(key in ipcListeners)) {
ipcListeners[key] = listener;
listener.listen();
}
}
};
export const removeListeners = () => {
for (const [key, listener] of Object.entries(rendererListeners)) {
listener.remove();
}
ipcListeners = {};
};

32
src/render/listeners.ts Normal file
View file

@ -0,0 +1,32 @@
import { IpcRendererListener } from "./composables/useIpcRend"
import useProfile from "./composables/useProfile";
const { setProfile } = useProfile();
const SET_PROFILE_CHANNEL = "set-profile";
const INIT_MESSAGES_CHANNEL = "init-messages";
const ADD_MESSAGE_CHANNEL = "add-message";
const UPDATE_MESSAGE_CHANNEL = "update-message";
export const setProfileListener = new IpcRendererListener({
channel: SET_PROFILE_CHANNEL,
listenerCallback: setProfile
});
export const initMessagesListener = new IpcRendererListener({
channel: INIT_MESSAGES_CHANNEL,
listenerCallback: () => {}
});
export const addMessagesListener = new IpcRendererListener({
channel: ADD_MESSAGE_CHANNEL,
listenerCallback: () => {}
});
export const updateMessagesListener = new IpcRendererListener({
channel: UPDATE_MESSAGE_CHANNEL,
listenerCallback: () => {}
});

View file

@ -6,11 +6,16 @@ import App from "./App.vue";
import mitt from "mitt"; import mitt from "mitt";
import { createApp } from "vue"; import { createApp } from "vue";
import { initIpcRendererListeners } from "./ipc"
// Handle ipcMain events.
initIpcRendererListeners();
// Handle events. // Handle events.
const emitter = mitt(); const emitter = mitt();
const app = createApp(App) const app = createApp(App);
app.provide("mitt", emitter) app.provide("mitt", emitter);
app.mount("#app"); app.mount("#app");

View file

@ -1,9 +1,10 @@
const Store = require('electron-store'); const Store = require('electron-store');
const schema = { const schema = {
key: { token: {
type: 'string', type: 'string',
}, },
profile: {}
}; };
const store = new Store({ const store = new Store({
@ -17,3 +18,14 @@ export const clearToken = (): void => (store.delete("token"));
export const setToken = (token: string): void => (store.set('token', token)); export const setToken = (token: string): void => (store.set('token', token));
export const setProfile = (profile: Profile): Profile => (store.set('profile', profile));
export const getProfile = (): Profile => (store.get('profile'));
export const clearProfile = (): void => (store.delete('profile'));
export const clearStore = (): void => {
clearToken();
clearProfile();
}

View file

@ -46,8 +46,8 @@ interface IpcHandlerCallback<I, O> {
(payload: I | null): Promise<Error | O>; (payload: I | null): Promise<Error | O>;
} }
interface IpcListenerCallback<I> { interface IpcListenerCallback<T> {
(payload: I | null): void; (payload: T | null): void;
} }
interface IIpcHandler<I, O> { interface IIpcHandler<I, O> {
@ -67,6 +67,10 @@ interface IPCHandlers {
} }
interface IPCListeners { interface IPCListeners {
[listener: string]: IIpcListener<any>; [listener: string]: IIpcListener<any> | null;
}
interface IpcEmitPayload<T> {
message: T | null;
} }