/>
</span>
- <!-- Windows -->
- <router-view/>
+ <!-- Main Pages -->
+ <Messenger v-if="auth"/>
+ <Login v-else />
</div>
</template>
<script lang="ts">
-import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
+import { defineComponent, onMounted, onUnmounted, ref } from "vue";
import { useIpc } from "@/modules/ipc";
import Splash from "@/components/splash.vue"
components: { Splash },
setup() {
-
- // Show spash screen til true.
const ready = ref(false);
- const { invoke } = useIpc();
+ // Whether user is logged in.
+ let auth = ref(false);
+
+ // Attempt token login
+ const key = window.localStorage.getItem(AUTH_KEY);
+
+ if (key) {
+ post("client-message", key)
+ }
+
+ // onAuthResponse
+ const onAuthResponse = (_event: IpcMainEvent, payload: Auth) => {
+ if (payload.token) {
+ auth.value = true;
+ }
+ }
// Post navbar action to backend.
const callNavbar = (action: string) => {
- invoke('nav-bar', action);
+ post('nav-bar', action);
}
- const onWindowReady = (_event: any, _payload: any) => {
- ready.value = true;
- }
onMounted(() => {
- window.ipcRenderer.on("window-ready", onWindowReady);
+ window.ipcRenderer.on("auth-response", onAuthResponse)
+
+
+ window.ipcRenderer.on("window-ready", () => ready.value = true);
});
onUnmounted(() => {
window.ipcRenderer.removeAllListeners("window-ready")
+ window.ipcRenderer.removeAllListeners("auth-response")
})
return {
callNavbar,
- ready
+ ready,
+ auth,
}
}
})
"use strict";
-import { sendAudio } from './session'
import { ipcMain } from "electron";
import { backgroundMitt } from './emitter';
const portAudio = require('naudiodon');
+// Audio in and out stream objects.
let ai: typeof portAudio.AudioIO | null = null;
let ao: typeof portAudio.AudioIO | null = null;
+
+// Whether activly recording.
let record = false;
+
const audioContainer = {
input: '',
}
+
const encoding = "hex";
+
const audioOptions = {
channelCount: 1,
sampleFormat: 16,
}
// callback run on space bar key up and down.
-const updateRecorder = (_event, payload: {
- isRecording: boolean;
- uid: string | null;
+const updateRecorder = (_event, payload: { isRecording: boolean; uid: string | null;
+
}): void => {
+
record = payload.isRecording;
if (!record) {
if (payload.uid) sendAudio(audioContainer.input, payload.uid);
}
+
};
// listen for space key up/down event.
return chunks;
}
-// main audio function run by run.ts module.
+// Main audio function run by run.ts module.
export function initAudioIO(): void {
if (!ai) {
}
}
-// play audio buffers.
+// Audio playback.
export function play(input: Buffer): void {
let i = 0;
}
}
+// Get's called on window close.
export function stopStream() {
if(ai != null) {
ai.quit();
-import { backgroundMitt } from './emitter';
+import { backgroundMitt } from "./emitter";
+import { renderMessage } from "@/modules/message";
+import { Profile, StandardMessage, Annotation } from "@/types/message/index";
+import { play } from "./audio";
-// Attempt an authenticaion, either with Token or with Creds.
-const onAuthRequest = async (e: any, payload: string | Creds) => {
-
- 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 (typeof payload !== "string") {
- payload = JSON.stringify(payload)
- }
-
- // Send token to backend
- socket.send(payload);
+export const handleAuthMessage = (message: string) => {
+ backgroundMitt.emit('ipc-renderer', {
+ endpoint: 'auth-response',
+ message: message
});
-};
-
-
-const handleAuthMessage = (message: string) => {
- backgroundMitt.emit('auth-res', message);
}
-const handleProfileMessage = (message: Profile) => {
+export const handleProfileMessage = (message: Profile) => {
backgroundMitt.emit('ipc-renderer', {
endpoint: 'update-profile',
message: message
});
}
-const handleStandardMessage = (m: StandardMessage) => {
+export const handleStandardMessage = (m: StandardMessage) => {
// Create a render message object.
const message = renderMessage(
});
}
-const handleAnnotationMessage = (message: Annotation) => {
+export const handleAnnotation = (message: Annotation) => {
backgroundMitt.emit('ipc-renderer', {
endpoint: 'render-message',
message: message
"use strict";
import { createWindow } from './window';
-import useWebSockets from './session';
+import agentInterface from './session';
import { initAudioIO } from './audio';
-let socket = false;
-
/*
* The main function will be run after electron app is ready.
*/
export async function main() {
- const { initSession } = useWebSockets()
+ const { initSession } = agentInterface()
// create main window.
await createWindow();
// Instantiate socket session with crimata-platorm.
- if (!socket) {
- initSocketSession();
- }
-
- socket = true;
+ initSession();
// Begin audio stream.
initAudioIO();
import { backgroundMitt } from './emitter';
+import { ipcMain, IpcMainEvent } from "electron";
+
+import useWebSockets from "@/modules/ws";
import { handleAuthMessage, handleStandardMessage, handleProfileMessage, handleAnnotation } from "./handlers";
-// Handle messages from server.
+// Calls appropriate endpoint for a server message.
const onServerMessage = (data: string): void => {
const message = JSON.parse(data)
if (message.key) {
- handleAuthMessage(message)
+ backgroundMitt.emit('auth-response', message);
}
else if (message.content) {
}
else {
- handleAnnotationMessage(message)
+ handleAnnotation(message)
}
};
+const { createSocket, sendMessage } = useWebSockets(onServerMessage);
+
// Handle messages from client.
const onClientMessage = (_event: IpcMainEvent, payload: any) {
sendMessage(JSON.stringify(payload))
}
+// Routes messages to and from Crimata Servers.
export default function agentInterface() {
-
- const { createSocket, sendMessage } = useWebSockets(onServerMessage)
const initSession = () => {
ipcMain.removeAllListeners()
- ipcMain.removeHandler('auth-session');
- ipcMain.handle('auth-request', onAuthRequest);
- ipcMain.on('client-message', onClientMessage);
+ ipcMain.on("client-message", onClientMessage);
createSocket()
}
initSession
}
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// Attempt an authenticaion, either with Token or with Creds.
-const onAuthRequest = async (e: any, payload: string | Creds) => {
-
- 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 (typeof payload !== "string") {
- payload = JSON.stringify(payload)
- }
-
- // Send token to backend
- socket.send(payload);
-
- });
-};
-
-
-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: 'render-message',
- message: message
- });
-}
-
-const onMessage = (messageStr: string): void => {
-
- // Auth messages are strings.
- if (!auth) {
- handleAuthMessage(messageStr)
- return
- }
-
- const message = JSON.parse(messageStr)
- console.log("New message:")
- console.log(message)
-
- 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));
}
\ No newline at end of file
const message = renderMessage("", "", "", "sf")
emitter.emit("self-message", message);
- post('update-recorder', {
+ const audio = invoke('update-recorder', {
isRecording: false,
uid: message.uid
});
window.addEventListener("keydown", onEscape);
}
- // When user clicks logout button in settings.
+ // We ask server to log us out.
const onLogout = () => {
- logout();
- router.push({ name: "login" });
- post("logout", "")
- }
+ post("auth-request", "logout")
+ }
return {
onActive,
toggleSettings,
onLogout
}
- }
+ }
})
</script>
// src/main.ts
import App from "./App.vue";
-import router from "./router";
import mitt from "mitt";
import { createApp } from "vue";
const app = createApp(App)
-app.use(router)
app.provide("mitt", emitter)
app.mount("#app");
window.localStorage.setItem(AUTH_KEY, token);
}
-// Load key and invoke onAuthSession to try key-login.
+// Token authentication.
const authToken = async () => {
console.log("Calling auth token!!")
const { invoke } = useIpc();
// Run every time we want to connect to backend.
-export default function useWebSockets(receiveCallback: (s: Buffer) => any) {
+export default function useWebSockets(receiveCallback: (s: string) => any) {
const sendMessage = (data: string) => {
console.log('Message received: ', event);
- receiveCallback(event.data)
+ receiveCallback(event.data.toString())
}
const onClose = (event: WebSocket.CloseEvent) => {
- console.log("socket closed normally.")
+ console.log("Socket closed normally.")
}
+ // Reconnect automatically on error.
const onError = (event: WebSocket.ErrorEvent) => {
console.log('WebSocket error: ', event);
}
return {
- createSocket
+ createSocket,
+ sendMessage
}
-}
-
-
-
-
-
-
-
-
- // Close existing sockets.
- if (socket) {
- socket.removeAllListeners();
- socket.terminate();
- socket.close();
- success = false;
- }
-
- // Init new socket.
- socket = new WebSocket(`ws://127.0.0.1:8760`);
- socket.binaryType = 'arraybuffer';
-
- // Handle requests for authentication (promise).
- 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.');
-
- // Try to authenticate token right away.
- backgroundMitt.emit('ipc-renderer', {
- endpoint: 'auth',
- message: null
- });
-
- success = true;
-
- });
-
- // Error handling.
- socket.on('error', (_e) => {
-
- console.log('ERROR: Failed to connect.');
- socket.removeAllListeners();
- socket.close();
-
- setTimeout(() => {
- if (!success) {
- console.log('Reconnecting...');
- initSession();
- }
- }, 3000); // reconnect timeout
-
- });
-
- socket.on('close', () => {
- console.log('Connection droped! Restarting...');
- restart();
- });
-
- socket.on("message", onMessage);
}
\ No newline at end of file
+++ /dev/null
-import {
- createRouter,
- createWebHistory,
- createWebHashHistory,
- RouteRecordRaw
-} from "vue-router";
-import Home from "@/views/messenger.vue";
-import { useAuth } from '@/modules/auth';
-
-// Define the routes (/*) for the app here.
-const routes: Array<RouteRecordRaw> = [
- {
- path: "/",
- name: "home",
- component: Home,
- meta: { requiresAuth: true },
- },
- {
- path: "/login",
- name: "login",
- component: () => import("@/views/login.vue"),
- meta: { requiresAuth: false },
- },
- {
- path: "/register",
- name: "register",
- component: () => import("@/views/register.vue"),
- meta: { requiresAuth: false },
- },
-];
-
-const router = createRouter({
- history: process.env.IS_ELECTRON ? createWebHashHistory() : createWebHistory(process.env.BASE_URL),
- routes
-});
-
-// route auth check
-router.beforeEach((to, from, next) => {
- const { accessToken } = useAuth();
-
- // Not logged into a guarded route?
- if (to.meta.requiresAuth && !accessToken.value) {
- next({ name: 'login' })
- }
-
- // Logged in for an auth route
- else if ((to.name == 'login' || to.name == 'register') && accessToken.value){
- next({ name: 'home' });
- }
-
- // Carry On...
- else next();
-})
-
-export default router;
</div>
<!-- submit button; position: fixed -->
- <button class="submitButton button" type="submit">Submit</button>
+ <button class="submitButton button" type="submitForm">Submit</button>
<div class="invalid" v-if="invalid">
Incorrect Credentials
setup() {
+ const { post } = useIpc();
const { setToken } = useAuth();
const { resetMessages } = useMessages();
- const router = useRouter();
-
- const email = ref("");
- const password = ref("");
- const invalid = ref(false);
-
- const { invoke } = useIpc();
-
- const submit = async () => {
-
- const payload = {
- request: "login",
- email: email.value,
- password: password.value
- };
-
- try {
- const response = await invoke('auth-session', payload);
- // On login without token, we clear localStorage and messages.
- window.localStorage.clear();
- resetMessages();
-
- setToken(response);
- invalid.value = false;
- router.push({ name: "home" });
- }
-
- catch(e) {
- invalid.value = true;
- console.log('Error loging in.');
- }
+ const router = useRouter();
- };
+ const form = ref({
+ email: "",
+ password: "",
+ })
- const switchView = () => {
- router.push({ name: "register" });
- };
+ // Submit login credentials to the backend.
+ const submitForm = () => {
+ post("auth-message", form)
+ }
return {
- submit,
- email,
- password,
- switchView,
- invalid
+ form,
+ submitForm
}
},
+
});
+
</script>
<style lang="scss" scoped>