import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
import * as path from "path";
-export function createWindow(options: {
+interface WindowSettings {
width: number;
height: number;
resizable: boolean;
-}): BrowserWindow {
+}
- const win: BrowserWindow = new BrowserWindow({
- width: options.width,
- height: options.height,
- resizable: options.resizable,
- webPreferences: {
- // Use pluginOptions.nodeIntegration, leave this alone
- // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
- nodeIntegration: (process.env
- .ELECTRON_NODE_INTEGRATION as unknown) as boolean,
- preload: path.join(__dirname, "preload.js")
- }
- });
+export const createWindow = async (options: WindowSettings): Promise<BrowserWindow> => {
+ return new Promise((resolve, reject) => {
+ const win: BrowserWindow = new BrowserWindow({
+ width: options.width,
+ height: options.height,
+ resizable: options.resizable,
+ webPreferences: {
+ // Use pluginOptions.nodeIntegration, leave this alone
+ // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
+ nodeIntegration: (process.env
+ .ELECTRON_NODE_INTEGRATION as unknown) as boolean,
+ preload: path.join(__dirname, "preload.js")
+ }
+ });
- if (process.env.WEBPACK_DEV_SERVER_URL) {
- // Load the url of the dev server if in development mode
- win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string);
- } else {
- createProtocol("app");
- // Load the index.html when not in development
- win.loadURL("app://./index.html");
- }
+ if (process.env.WEBPACK_DEV_SERVER_URL) {
+ // Load the url of the dev server if in development mode
+ win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string);
+ } else {
+ createProtocol("app");
+ // Load the index.html when not in development
+ win.loadURL("app://./index.html");
+ }
- return win;
+ win.webContents.on('did-finish-load', () => {
+ resolve(win);
+ });
+ })
}
-
import { createWindow } from './createWindow';
import { ipcMain } from "electron";
-import { initSession, sendMessage, authUser, authLogin} from './session';
+import { initSession, sendMessage } from './session';
import { windowEmitter } from './windowEmitter';
const portAudio = require('naudiodon');
message: any;
}
+let activeSession = false;
+
/*
* The main function will be run after electron app is ready.
*/
-export function main(): void {
+export async function main() {
// create main window.
- const win = createWindow({ width: 350, height: 525, resizable: false });
+ const win = await createWindow({ width: 350, height: 525, resizable: false });
windowEmitter.on('ipc-renderer', (payload: ipcRendererPayload) => {
win.webContents.send(payload.endpoint, {
});
});
+ // Instantiate socket session with crimata-platorm.
+ if (!activeSession) {
+ initSession();
+ }
+ activeSession = true;
+
const handleMessage = (event: any, arg: any) => {
sendMessage(arg);
}
const windowMount = (): void => {
- // Instantiate socket session with crimata-platorm.
- initSession();
windowEmitter.emit('window-active', true);
ipcMain.on('send-message', handleMessage);
- ipcMain.on('auth-login', authLogin);
}
const windowDismount = (): void => {
windowEmitter.emit('window-active', false);
ipcMain.removeAllListeners('send-message');
- ipcMain.removeAllListeners('auth-login');
}
// Handle window mount and dismount.
import { windowEmitter } from './windowEmitter';
import { ipcMain } from "electron";
-type Message = {
- type: string;
- id: string;
-}
-
-interface RenderMessage extends Message {
+interface RenderMessage {
+ type: 'render';
content: string;
context: string;
subContext: string;
modifiers: string;
time: string;
+ id: string;
}
-interface AuthUser extends Message {
+interface UserCreds {
email: string;
- firstName: string;
- lastName: string;
- access_token: string;
+ password: string;
}
const ip = 'ws://localhost';
-const port = 8080;
+const port = 8081;
const reconnectTimeout = 3000; //ms
let socket: WebSocket;
let success = false;
+let auth = false;
const receiveMessage = (message: string): void => {
- // NOTE assuming message is JSON string
- if (message === 'locked') {
- windowEmitter.emit('auth-resp', message);
- return;
- }
- const parsed: RenderMessage | AuthUser = JSON.parse(message);
- if (parsed.type === "render") {
- windowEmitter.emit('ipc-renderer', {
- endpoint: 'render-message',
- message: parsed
- });
- }
+
+ while(!auth) {
+ windowEmitter.emit('auth-res', message);
+ return;
+ }
+
+ const parsed: RenderMessage = JSON.parse(message);
+ if (parsed.type === "render") {
+ windowEmitter.emit('ipc-renderer', {
+ endpoint: 'render-message',
+ message: parsed
+ });
+ }
}
-const authToken = async (event: any, token: string): Promise<string | AuthUser > => {
+const authUser = async (event: any, payload: string | UserCreds | null): Promise<string> => {
return new Promise((resolve, reject) => {
console.log('authenticating...');
- windowEmitter.on('auth-resp', (arg: string | AuthUser) => {
- if (arg === 'locked') {
- reject(arg);
+ windowEmitter.on('auth-res', (res: string) => {
+ if (res === 'locked') {
+ reject(res);
+ } else {
+ auth = true;
+ resolve(res);
}
- resolve(arg);
});
- if (token) {
- socket.send(token);
- } else {
+ if (!payload) {
socket.send('no-token');
+ } else if (typeof payload === 'string' || payload instanceof String) {
+ socket.send(payload);
+ } else {
+ socket.send(JSON.stringify(payload));
}
});
};
-// Connect and authenticate
-export function initSession() {
+export const initSession = () => {
+ if (socket) {
+ socket.removeAllListeners();
+ socket.terminate();
+ socket.close();
+ success = false;
+ }
+
+ console.log('Connecting to Crimata Servers...');
socket = new WebSocket(`${ip}:${port}`);
socket.binaryType = 'arraybuffer';
socket.on('open', () => {
- console.log('Connected to crimata-platform');
- success = true;
+ console.log('Success! Connected to Crimata.');
// handle renderer auth-token event
- ipcMain.removeHandler('auth-token'); // avoid setting duplicate handlers
- ipcMain.handle('auth-token', authToken);
+ ipcMain.removeHandler('auth-user'); // avoid setting duplicate handlers
+ ipcMain.handle('auth-user', authUser);
// fetch token from renderer
windowEmitter.emit('ipc-renderer', {
message: null
});
- })
+ success = true;
+ });
- socket.on("message", receiveMessage);
+ socket.on('error', (e) => {
+ console.log('ERROR: Failed to connect.');
+ socket.removeAllListeners();
+ socket.close();
+ setTimeout(()=> {
+ if (!success) {
+ console.log('Attempting reconnect.');
+ initSession();
+ }
+ }, reconnectTimeout);
- setTimeout(()=> {
- if (!success) {
- // initSession();
- throw new Error('Unable to connect to crimata-platform');
- }
- }, reconnectTimeout);
-}
+ })
-export const authLogin = (event: any, arg: any) => {
- try {
- sendMessage(arg)
- windowEmitter.on('auth-resp', (payload: AuthUser) => {
- event.reply('auth-login-reply', payload);
- })
- } catch(e) {
- console.log('Error loging in' + e);
- event.reply('auth-login-reply', e);
- }
+ socket.on('close', () => {
+ console.log('Connection droped. Restarting.')
+ initSession();
+ })
+
+ socket.on("message", receiveMessage);
}
export const sendMessage = (content: string | Buffer) => {
class WindowEmitter extends EventEmitter {}
export const windowEmitter = new WindowEmitter();
-
-const ipcRend = (endpoint: string, message: any) => {
- win.webContents.send(endpoint, {
- message: message
- })
-}
import { reactive, watch, toRefs } from 'vue';
import { useIpc } from './ipc';
-interface User {
- id: string;
- email: string;
- firstName: string;
- lastName: string;
- access_token: string;
-}
-
interface AuthState {
- authenticating: boolean;
- user?: User;
+ access_token?: string | null;
error?: Error;
}
const state = reactive<AuthState>({
- authenticating: false,
- user: undefined,
+ access_token: undefined,
error: undefined,
});
const token = window.localStorage.getItem(AUTH_KEY);
// authenticate on socket connect
-window.ipcRenderer.on("fetch-token", async (event, payload) => {
- const { data, invoke } = useIpc('auth-token');
+window.ipcRenderer.on("fetch-token", async (event, payload: null) => {
+ const { data, invoke } = useIpc('auth-user');
try {
await invoke(token);
- state.user = data.value;
+ state.access_token = data.value;
}
catch(e) {
state.error = e;
}
});
-if (token) {
- const { loading, error, data, send, invoke } = useIpc('auth-user');
-
- state.authenticating = true;
-
- // authenticate token against crimata-platform
- console.log('sending token to main')
- send({
- token: token
- });
-
- watch(loading, () => {
- if (error.value) {
- console.log('ERROR: failed authentication')
- window.localStorage.removeItem(AUTH_KEY);
- }
- else if (data.value) {
- state.user = data.value;
- }
-
- state.authenticating = false;
- })
-} else {
- console.log('no token to send')
-}
-
export const useAuth = () => {
- const setUser = (payload: User, remember: boolean) => {
+ const setToken = (token: string, remember: boolean) => {
if (remember) {
// Save
- window.localStorage.setItem(AUTH_KEY, payload.access_token);
+ window.localStorage.setItem(AUTH_KEY, token);
}
- state.user = payload;
+ state.access_token = token;
state.error = undefined;
}
const logout = (): Promise<void> => {
window.localStorage.removeItem(AUTH_KEY);
- return Promise.resolve(state.user = undefined);
+ return Promise.resolve(state.access_token = undefined);
}
return {
- setUser,
+ setToken,
logout,
- ...toRefs(state), // authenticating, user, error
+ ...toRefs(state), // access_token, error
}
}
});
router.beforeEach((to, from, next) => {
- const { user } = useAuth();
+ const { access_token } = useAuth();
// Not logged into a guarded route?
- if (to.meta.requiresAuth && !user?.value) next({ name: 'login' });
+ if (to.meta.requiresAuth && !access_token?.value) next({ name: 'login' });
// Logged in for an auth route
- else if ((to.name == 'login' || to.name == 'register') && user!.value) next({ name: 'home' });
+ else if ((to.name == 'login' || to.name == 'register') && access_token!.value) next({ name: 'home' });
// Carry On...
else next();
<input class="input" type="password" v-model="password" placeholder="Password" />
</div>
+ <input type="checkbox" id="checkbox" v-model="rememberMe" />
+ <label for="checkbox">Remember Me</label>
+
<!-- submit button -->
<button class="button" type="submit">Login</button>
</form>
</template>
<script lang="ts">
-import { defineComponent, toRefs, reactive, watch } from "vue";
+import { defineComponent, toRefs, reactive, watch, ref } from "vue";
import { useAuth } from "@/modules/auth";
import { useIpc } from "@/modules/ipc";
import { useRouter } from "vue-router";
export default defineComponent({
name: "Login",
setup() {
- const { setUser, user } = useAuth();
+ const { setToken, access_token } = useAuth();
const router = useRouter();
- const payload = reactive<LoginPayload>({
- email: "",
- password: "",
- rememberMe: true,
- });
+ const email = ref("");
+ const password = ref("");
+ const rememberMe = ref(false);
- //const { loading, data, send, errorMessage } = useIpc("auth-login");
+ const { loading, error, data, invoke, errorMessage } = useIpc('auth-user');
- const { loading, error, data, invoke, errorMessage } = useIpc('test');
const submit = async () => {
- // console.log(toRefs(payload));
- await invoke({
- request: "register",
- email: payload.email,
- password: payload.password,
- })
- console.log('testing incoke', data.value.test)
- // setUser(data.value, payload.rememberMe);
+ const payload = {
+ email: email.value,
+ password: password.value
+ };
+ await invoke(payload);
+ console.log('testing incoke', data.value)
+ setToken(data.value, rememberMe.value);
router.push({ name: "home" });
};
loading,
submit,
errorMessage,
- ...toRefs(payload),
+ email,
+ password,
+ rememberMe
};
},
});
lastName: undefined,
});
- const { error, loading, send, data, errorMessage } = useIpc(
+ const { error, loading, invoke, data, errorMessage } = useIpc(
"auth-register"
);
- const { setUser } = useAuth();
+ const { setToken } = useAuth();
const router = useRouter();
const submit = async () => {
- send(payload);
- setUser(data.value, true);
+ await invoke(payload);
+ setToken(data.value, true);
router.push({ name: "home" });
};
time: 'test'
}
const wss = new WebSocket.Server({
- port: 8080
+ port: 8081
});
wss.on("connection", function connection(ws, req) {