]> Repos - mime-chat/commitdiff
messenger v69
authorriqo <hernandeze2@xavier.edu>
Mon, 8 Mar 2021 22:49:14 +0000 (16:49 -0600)
committerriqo <hernandeze2@xavier.edu>
Mon, 8 Mar 2021 22:49:14 +0000 (16:49 -0600)
package.json
src/background/audio.ts
src/background/session.ts
src/components/inputItem/inputController.ts
src/modules/message.ts [new file with mode: 0644]
src/preload.ts
src/router.ts
src/types/message/index.ts
src/views/messenger.vue
yarn.lock

index 183baf8f5be7266596801e84c84e5910c8948091..5bb457125a1299083b00b69a5e5bd1ef513c7822 100644 (file)
@@ -32,6 +32,7 @@
     "mitt": "^2.1.0",
     "naudiodon": "^2.3.2",
     "node-record-lpcm16": "^1.0.1",
+    "uuid": "^8.3.2",
     "vue": "^3.0.0-0",
     "vue-router": "^4.0.0-0",
     "vuex": "^4.0.0-0",
index 98e290948fa3e687710f89ca5bb9a33246604674..de1c6888d6810bd16b63dce96b3626fa88ac2067 100644 (file)
@@ -12,7 +12,7 @@ let record = false;
 const audioContainer = {
     input: '',
 }
-const encoding = "base64";
+const encoding = "hex";
 const audioOptions = {
     channelCount: 1,
     sampleFormat: 16,
@@ -22,10 +22,13 @@ const audioOptions = {
 }
 
 // callback run on space bar key up and down.
-const updateRecorder = (_event, payload: boolean): void => {
-    record = payload;
+const updateRecorder = (_event, payload: {
+    isRecording: boolean;
+    uid: string | null;
+}): void => {
+    record = payload.isRecording;
     if (!record) {
-        sendAudio(Buffer.from(audioContainer.input, 'base64'));
+        if (payload.uid) sendAudio(audioContainer.input, payload.uid);
     }
 };
 
index 75f9433141eee842c6e356ee67a53366fd9a7a35..217935762c9830d3c71d8dba929767fa4f74c9c6 100644 (file)
@@ -4,26 +4,9 @@ import WebSocket from 'ws';
 import { backgroundMitt } from './emitter';
 import { ipcMain } from "electron";
 import { play } from './audio';
-
-interface RenderMessage {
-    content: {
-        text: string;
-        audio: string;
-    };
-    context: string;
-    modifier: string;
-    id: string;
-}
-
-interface UserCreds {
-    email: string;
-    password: string;
-}
-
-interface TextMessage {
-    audio: 0;
-    content: string;
-}
+import { UserCreds, ClientMessage } from "@/types/message/index";
+import { clientMessage } from '@/modules/message';
+import { v4 as uuidv4 } from 'uuid';
 
 const ip = 'ws://127.0.0.1';
 const port = 8760;
@@ -32,8 +15,7 @@ let socket: WebSocket;
 let success = false;
 let auth = false;
 
-
-const authSession = async (_event, payload: string | UserCreds | null): Promise<string> => {
+const onAuthSession = async (_event, payload: string | UserCreds | null): Promise<string> => {
     return new Promise((resolve, reject) => {
 
         console.log('authenticating...');
@@ -61,18 +43,7 @@ const authSession = async (_event, payload: string | UserCreds | null): Promise<
     });
 };
 
-// function parseHexString(str: string) { 
-//     var result = [];
-//     while (str.length >= 8) { 
-//         result.push(parseInt(str.substring(0, 8), 16));
-
-//         str = str.substring(8, str.length);
-//     }
-
-//     return result;
-// }
-
-const receiveMessage = (message: string): void => {
+const onMessage = (message: string): void => {
 
     while (!auth) {
         backgroundMitt.emit('auth-res', message);
@@ -80,34 +51,34 @@ const receiveMessage = (message: string): void => {
     }
 
     // Parse the message.
-    const parsed: RenderMessage = JSON.parse(message);
-    console.log('message received', parsed.content.text);
+    const m = JSON.parse(message);
+
+    // check to see if this is a Render Message.
+    if (m.content) {
+        // If there is audio, play it.
+        if (m.content.audio) {
+            const audioBytes = Buffer.from(m.content.audio as string, 'hex');
+            play(audioBytes);
+        }
 
-    // If there is audio, play it.
-    if (parsed.content.audio) {
-        const audioBytes = Buffer.from(parsed.content.audio, 'hex');
-        play(audioBytes);
+        // if there is no unique id, add it.
+        if(!m.uid) m.uid = uuidv4();   
     }
 
     backgroundMitt.emit('ipc-renderer', {
         endpoint: 'render-message',
-        message: parsed
+        message: m
     });
 
 };
 
-const sendMessage = (_event, payload: TextMessage): void => {
-    console.log('sending message')
+const onClientMessage = (_event, payload: ClientMessage): void => {
+    console.log('sending message');
     socket.send(JSON.stringify(payload));
 }
 
-export const sendAudio = (content: Buffer) => {
-    console.log('sending audio')
-    socket.send(content);
-}
-
 // Run every time we want to connect to backend.
-export const initSession = () => {
+export function initSession(): void {
 
     // Close existing sockets.
     if (socket) {
@@ -123,11 +94,11 @@ export const initSession = () => {
 
     // handle renderer auth-token event
     ipcMain.removeHandler('auth-session'); // avoid setting duplicate handlers
-    ipcMain.handle('auth-session', authSession);
+    ipcMain.handle('auth-session', onAuthSession);
 
     // handle user message event
-    ipcMain.removeAllListeners('message');
-    ipcMain.on('message', sendMessage);
+    ipcMain.removeAllListeners('client-message');
+    ipcMain.on('client-message', onClientMessage);
 
     // Connect to the backend.
     socket.on('open', () => {
@@ -162,6 +133,10 @@ export const initSession = () => {
         initSession();
     });
 
-    socket.on("message", receiveMessage);
-};
+    socket.on("message", onMessage);
+}
 
+export function sendAudio(content: string, uid: string): void {
+    const m = clientMessage("", content, uid);
+    socket.send(JSON.stringify(m));
+}
index dd9f62d5ea269a14e451841737ad7f82499df1cd..6c9570dd97aa3c3c2aa72c0913fa0f2c2b6cbef1 100644 (file)
@@ -1,8 +1,8 @@
 /*
-* Controls which input to visualize
-* Will visualize text input by default as user types or
-* if user holds space bar down, input audio stream
-* will be visualized & recorded
+* Main logic used by inputItem component.
+* Will visualize text input by default as user types.
+* If user holds space bar down, input audio stream will
+* be recorded and sent to the backend for analysis.
 */
 
 import { ref, watch, onUnmounted, onMounted } from "vue";
@@ -10,8 +10,13 @@ import useMitt from "@/modules/mitt";
 import { useIpc } from '@/modules/ipc';
 import keyboardNameMap from "./keyBoardMaps/keyboardNameMap";
 import keyboardCharMap from "./keyBoardMaps/keyboardCharMap";
+import { RenderMessage, ClientMessage } from "@/types/message/index";
+import { v4 as uuidv4 } from 'uuid';
+import {clientMessage, renderMessage} from '@/modules/message';
 
 let textInput: HTMLInputElement | null;
+let m: RenderMessage | ClientMessage;
+let uid: string;
 
 export default function useInputController() {
 
@@ -21,19 +26,28 @@ export default function useInputController() {
     const isTyping = ref(false);
     const input = ref("");
 
-    // send message on ENTER
+    // send message on ENTER.
     const onEnter = () => {
+        if (input.value) {
+            // remove first character of input.
+            const text = input.value.substring(1);
 
-        const message = {
-            audio: 0,
-            text: input.value
-        };
+            uid = uuidv4();
 
-        // trigger send animation
-        emitter.emit("animate-send");
+            m = renderMessage(text, false, "sf", uid);
 
-        // send message to backend
-        if (input.value) post('message', message);
+            // render user message.
+            emitter.emit("self-message", m);
+
+            m = clientMessage(m.content.text, m.content.audio, uid);
+
+            // send message to backend.
+            post('client-message', m);
+
+            // reset text input.
+            if (textInput) textInput.value = ''; 
+            input.value = " ";
+        }
     }
 
     // update input on keydown event & listen for special commands.
@@ -59,8 +73,6 @@ export default function useInputController() {
         switch (cmd) {
           case "ENTER":
             onEnter();
-            if (textInput) textInput.value = ''
-            input.value = " ";
             break;
           case "BACK_SPACE":
             input.value = input.value.slice(0, -1);
@@ -74,12 +86,24 @@ export default function useInputController() {
         }
     }
 
-    // stops stream recording on space key up event.
+    // stop stream recording and render audio message on space key up event.
     const onKeyUp = (e: KeyboardEvent) => {
         if (e.key === " " && isRecording.value) {
 
             isRecording.value = false;
-            post('update-recorder', isRecording.value);
+
+            uid = uuidv4();
+
+            // render audio message.
+            m = renderMessage("", false, "sf", uid);
+            emitter.emit("self-message", m);
+
+            // stop stream recording.
+            post('update-recorder', {
+                isRecording: isRecording.value,
+                uid
+            }); 
+
             input.value = ''
         }
     }
@@ -107,7 +131,10 @@ export default function useInputController() {
         if (input === " " && isRecording.value === false) {
             isTyping.value = false;
             isRecording.value = true;
-            post('update-recorder', isRecording.value);
+            post('update-recorder', {
+                isRecording: isRecording.value,
+                uid: null
+            });
             return;
         }
         isTyping.value = true;
diff --git a/src/modules/message.ts b/src/modules/message.ts
new file mode 100644 (file)
index 0000000..37c6ba9
--- /dev/null
@@ -0,0 +1,21 @@
+import { RenderMessage, ClientMessage } from "@/types/message/index";
+
+export const renderMessage = (text: string, audio: string | boolean, modifier: string, uid: string): RenderMessage => (
+  {
+    content: {
+        audio,
+        text
+    },
+    context: "",
+    modifier,
+    uid
+  }
+)
+
+export const clientMessage = (text: string, audio: string | boolean, uid: string): ClientMessage => (
+  {
+    audio,
+    text,
+    uid
+  }
+)
\ No newline at end of file
index bbc0c9a09efec6c9d61aaadde3d109cc0945c68d..8ba296b9398fd96359e5ec0a338d230bec08d8c0 100644 (file)
@@ -25,8 +25,8 @@ process.once("loaded", () => {
       ipcRenderer.send("update-recorder", message.content);
     }
 
-    if (message.endpoint === "message") {
-      ipcRenderer.send("message", message.content);
+    if (message.endpoint === "client-message") {
+      ipcRenderer.send("client-message", message.content);
     }
 
   });
index 6f689bf52b4193ada35932a3b6a494979730d341..ee94a6137aa14f719970623442705afa1e146141 100644 (file)
@@ -35,21 +35,21 @@ const router = createRouter({
 });
 
 // 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();
-// })
+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;
index 5163d684213c03aa2ba71e2723ffb75fa44ef2cb..80e3a979d586dba74d4b8e48aedd3abdfcb4fb9d 100644 (file)
@@ -1,18 +1,26 @@
-export interface Message {
+export interface UserCreds {
+    email: string;
+    password: string;
+}
+
+export interface RenderMessage {
     content: {
         text: string;
-        audio: boolean | Buffer;
+        audio: boolean | string;
     };
     context: string;
     modifier: string;
-    id: string;
+    uid: string;
 }
 
-interface MessageTransform {
-    initialTranslate: string;
-    finalTranslate: string;
+export interface ClientMessage {
+    text: string;
+    audio: boolean | string;
+    uid: string;
 }
 
-export interface MessageAnimeFunc {
-    (message: SVGElement, transform: MessageTransform, scrollHeight?: number | undefined, targetList?: NodeList | undefined): void;
-}
\ No newline at end of file
+export interface Annotation {
+    text: string;
+    context: string;
+    uid: string;
+}
index e0769da10b4eacb517c09b2ddccf453ac83facfc..fea42d7f0aee1c7e149bbe757fbddd0136f871a1 100644 (file)
@@ -3,15 +3,16 @@
 
   <!-- List of message bubbles. -->
   <div id="messenger">
-    <MessageItem v-for="message in messages" :message="message" :key="message.id" />
+    <MessageItem v-for="message in messages" :message="message[1]" :key="message[0]" />
   </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, reactive, onMounted, onUnmounted } from "vue";
-import { Message } from "@/types/message/index";
+import { RenderMessage , Annotation } from "@/types/message/index";
 import MessageItem from "@/components/messageItem.vue";
 import InputItem from "@/components/inputItem/inputItem.vue";
+import useMitt from "@/modules/mitt";
 
 export default defineComponent({
   name: "Messenger",
@@ -22,32 +23,42 @@ export default defineComponent({
   },
 
   setup() {
+    const { emitter } = useMitt();
     // List of messages in the view.
     // Oldest message first.
-    const messages: Message[] = reactive([]);
-    const messages_ref: any = {};
-
-    // Render a message.
-    // Called on "enter" instead of on "recv message"
-    const render = (message: Message) => {
-      messages.push(message);
-      messages_ref[message.id] = message;
-    };
+    const messages = reactive(new Map());
 
-    // Annotate/update an existing message.
-    const annotate = (message: Message) => {
-      1 + 1;
-    };
+    let m: RenderMessage | Annotation;
+
+    const onRenderMessage = (event: any, payload: any) => { 
+
+      // render message if there is content.
+      if (payload.message.content) {
+        m = payload.message as RenderMessage;
+
+        messages.set(m.uid, m);
+
+      } else {
+        // must be an annotation, update messages.
+        m = payload.message as Annotation;
+
+        if (messages.has(m.uid)) {
+          messages.get(m.uid).context = m.context;
+          messages.get(m.uid).content.text = m.text;
+        }
+
+      }
+    }
 
     onMounted(() => {
+      emitter.on('self-message', (message) => messages.set(message.uid, message));
       // Listen for new messages to render.
-      window.ipcRenderer.on("render-message", (event, payload) => {
-        if (payload.message.content) render(payload.message);
-      });
+      window.ipcRenderer.on("render-message", onRenderMessage);
     });
 
     onUnmounted(() => {
       window.ipcRenderer.removeAllListeners("render-message");
+      emitter.all.clear();
     });
 
     return {
index 79f5a454ab312007aa996d14e5d8c754dc6c0195..619e71a066149ab132a35d408dd1a797ca418429 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -12838,6 +12838,11 @@ uuid@^8.0.0:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31"
   integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==
 
+uuid@^8.3.2:
+  version "8.3.2"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+  integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
 v8-compile-cache@^2.0.3:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"