Merge remote-tracking branch 'origin/main' into main
This commit is contained in:
commit
69a9dacb90
34 changed files with 874 additions and 799 deletions
|
|
@ -1,5 +1,9 @@
|
|||
"use strict";
|
||||
/* eslint @typescript-eslint/no-var-requires: "off" */
|
||||
import { sendAudio } from './session'
|
||||
const portAudio = require('naudiodon');
|
||||
|
||||
let ia: typeof portAudio.AudioIO;
|
||||
let audioInput: string[] = [];
|
||||
|
||||
function processAudio(audioInput: Array<string>): Buffer {
|
||||
|
|
@ -8,42 +12,39 @@ function processAudio(audioInput: Array<string>): Buffer {
|
|||
return Buffer.from(audio, "base64");
|
||||
}
|
||||
|
||||
|
||||
const updateRecorder = async (Event: any, record: boolean): void => {
|
||||
export const updateRecorder = (_event, record: boolean): void => {
|
||||
if (record) {
|
||||
ia.resume();
|
||||
} else {
|
||||
ia.pause();
|
||||
const audio = processAudio(audioInput);
|
||||
// emmit ws event with audio
|
||||
// sendAudio(audio);
|
||||
sendAudio(audio);
|
||||
audioInput = [];
|
||||
}
|
||||
}
|
||||
|
||||
export const initRecorder = () => {
|
||||
|
||||
const ia = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
sampleFormat: 16,
|
||||
sampleRate: 16000,
|
||||
deviceId: -1,
|
||||
closeOnError: false,
|
||||
}
|
||||
});
|
||||
ia.setEncoding('base64');
|
||||
ia.start();
|
||||
ia.pause();
|
||||
ia.on('error', (e: Error) => {
|
||||
console.log('Error recording audio', + e);
|
||||
});
|
||||
ia.on('data', (chunk: string) => {
|
||||
audioInput.push(chunk);
|
||||
});
|
||||
|
||||
export function useIA() {
|
||||
return {
|
||||
ia,
|
||||
processAudio
|
||||
if (!ia) {
|
||||
ia = new portAudio.AudioIO({
|
||||
inOptions: {
|
||||
channelCount: 1,
|
||||
sampleFormat: 16,
|
||||
sampleRate: 16000,
|
||||
deviceId: -1,
|
||||
closeOnError: false,
|
||||
}
|
||||
});
|
||||
ia.setEncoding('base64');
|
||||
ia.start();
|
||||
ia.pause();
|
||||
ia.on('error', (e: Error) => {
|
||||
console.log('Error recording audio', + e);
|
||||
});
|
||||
ia.on('data', (chunk: string) => {
|
||||
audioInput.push(chunk);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,40 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
import { createWindow } from './window';
|
||||
import { ipcMain, BrowserWindow } from "electron";
|
||||
import { initSession } from './session';
|
||||
import { backgroundMitt } from './emitter';
|
||||
// const portAudio = require('naudiodon');
|
||||
import { initRecorder } from './audio';
|
||||
|
||||
interface RenderMessage {
|
||||
content: string;
|
||||
context: string;
|
||||
subContext: string;
|
||||
modifiers: string;
|
||||
time: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface IpcRendererPayload {
|
||||
endpoint: string;
|
||||
message: RenderMessage | null;
|
||||
}
|
||||
|
||||
let win: BrowserWindow | null;
|
||||
let activeSession = false;
|
||||
|
||||
backgroundMitt.on('ipc-renderer', (payload: IpcRendererPayload) => {
|
||||
if (win)
|
||||
win.webContents.send(payload.endpoint, {
|
||||
message: payload.message
|
||||
});
|
||||
});
|
||||
|
||||
const windowDismount = (): void => {
|
||||
win = null;
|
||||
backgroundMitt.emit('window-active', false);
|
||||
ipcMain.removeAllListeners('send-message');
|
||||
}
|
||||
let socket = false;
|
||||
|
||||
/*
|
||||
* The main function will be run after electron app is ready.
|
||||
|
|
@ -42,55 +12,17 @@ const windowDismount = (): void => {
|
|||
export async function main() {
|
||||
|
||||
// create main window.
|
||||
if (!win) win = await createWindow({
|
||||
await createWindow({
|
||||
width: 350,
|
||||
height: 525,
|
||||
resizable: true
|
||||
});
|
||||
|
||||
// Instantiate socket session with crimata-platorm.
|
||||
if (!activeSession) initSession();
|
||||
if (!socket) initSession();
|
||||
socket = true;
|
||||
|
||||
activeSession = true;
|
||||
// Begin audio stream.
|
||||
initRecorder();
|
||||
|
||||
// Handle window close.
|
||||
win.on("closed", windowDismount);
|
||||
|
||||
// TODO: FIX recorder restart bug
|
||||
// let audioInput: string[] = [];
|
||||
// const updateRecorder = async (Event: any, record: boolean): void => {
|
||||
// if (record) {
|
||||
// ia.resume();
|
||||
// } else {
|
||||
// ia.pause();
|
||||
// const audio = processAudio(audioInput);
|
||||
// sendAudio(audio);
|
||||
// audioInput = [];
|
||||
// }
|
||||
// }
|
||||
|
||||
// function processAudio(audioInput: Array<string>): Buffer {
|
||||
// let audio = '';
|
||||
// audioInput.forEach(chunk => audio += chunk);
|
||||
// return Buffer.from(audio, "base64");
|
||||
// }
|
||||
|
||||
// const ia = new portAudio.AudioIO({
|
||||
// inOptions: {
|
||||
// channelCount: 1,
|
||||
// sampleFormat: 16,
|
||||
// sampleRate: 16000,
|
||||
// deviceId: -1,
|
||||
// closeOnError: false,
|
||||
// }
|
||||
// });
|
||||
// ia.setEncoding('base64');
|
||||
// ia.start();
|
||||
// ia.pause();
|
||||
// ia.on('error', (e: Error) => {
|
||||
// console.log('Error recording audio', + e);
|
||||
// });
|
||||
// ia.on('data', (chunk: string) => {
|
||||
// audioInput.push(chunk);
|
||||
// });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ interface RenderMessage {
|
|||
content: string;
|
||||
context: string;
|
||||
subContext: string;
|
||||
modifiers: string;
|
||||
modifier: string;
|
||||
time: string;
|
||||
id: string;
|
||||
}
|
||||
|
|
@ -32,22 +32,29 @@ let auth = false;
|
|||
|
||||
const authSession = async (_event, payload: string | UserCreds | null): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
console.log('authenticating...');
|
||||
backgroundMitt.on('auth-res', (res: string) => {
|
||||
|
||||
backgroundMitt.once('auth-res', (res: string) => {
|
||||
|
||||
if (res === 'locked') {
|
||||
reject(res);
|
||||
} else {
|
||||
console.log('Success!');
|
||||
auth = true;
|
||||
resolve(res);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (!payload) {
|
||||
socket.send('no-token');
|
||||
} else if (typeof payload === 'string' || payload instanceof String) {
|
||||
} else if (payload instanceof String || typeof payload === 'string') {
|
||||
socket.send(payload);
|
||||
} else {
|
||||
socket.send(JSON.stringify(payload));
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -59,22 +66,52 @@ const receiveMessage = (message: string): void => {
|
|||
}
|
||||
|
||||
const parsed: RenderMessage = JSON.parse(message);
|
||||
if (parsed.modifier === "sf") {
|
||||
backgroundMitt.emit('message-res', parsed);
|
||||
} else if (parsed.modifier === "ai") {
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'render-message',
|
||||
message: parsed
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const asyncSend = (_event?, payload: TextMessage | Buffer): Promise<RenderMessage> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
backgroundMitt.once('message-res', (res: RenderMessage) => {
|
||||
if (res.content) {
|
||||
resolve(res);
|
||||
} else {
|
||||
reject('ERROR: NO MESSAGE');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (payload instanceof Buffer) {
|
||||
socket.send(payload);
|
||||
} else if (payload) {
|
||||
socket.send(JSON.stringify(payload));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const sendAudio = async (content: Buffer) => {
|
||||
|
||||
const res = await asyncSend(null, content);
|
||||
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'render-message',
|
||||
message: parsed
|
||||
message: res
|
||||
});
|
||||
};
|
||||
|
||||
export const sendMessage = (content: TextMessage | Buffer) => {
|
||||
if (content instanceof Buffer) {
|
||||
socket.send(content);
|
||||
} else if (content) {
|
||||
socket.send(JSON.stringify(content));
|
||||
}
|
||||
}
|
||||
|
||||
// Run every time we want to connect to backend.
|
||||
export const initSession = () => {
|
||||
|
||||
// Close existing sockets.
|
||||
if (socket) {
|
||||
socket.removeAllListeners();
|
||||
socket.terminate();
|
||||
|
|
@ -82,25 +119,33 @@ export const initSession = () => {
|
|||
success = false;
|
||||
}
|
||||
|
||||
// Init new socket.
|
||||
socket = new WebSocket(`${ip}:${port}`);
|
||||
socket.binaryType = 'arraybuffer';
|
||||
|
||||
// handle renderer auth-token event
|
||||
ipcMain.removeHandler('auth-user'); // avoid setting duplicate handlers
|
||||
ipcMain.handle('auth-user', authSession);
|
||||
ipcMain.removeHandler('auth-session'); // avoid setting duplicate handlers
|
||||
ipcMain.handle('auth-session', authSession);
|
||||
|
||||
// handle renderer send-message event
|
||||
ipcMain.removeHandler('message'); // avoid setting duplicate handlers
|
||||
ipcMain.handle('message', asyncSend);
|
||||
|
||||
// Connect to the backend.
|
||||
socket.on('open', () => {
|
||||
console.log('Success! Connected to Crimata Servers.');
|
||||
console.log('Connected to Crimata Servers.');
|
||||
|
||||
// fetch token from renderer
|
||||
// call auth renderer event on connection
|
||||
backgroundMitt.emit('ipc-renderer', {
|
||||
endpoint: 'fetch-token',
|
||||
endpoint: 'auth',
|
||||
message: null
|
||||
});
|
||||
|
||||
success = true;
|
||||
|
||||
});
|
||||
|
||||
// Handle for failed connect, try again.
|
||||
socket.on('error', (_e) => {
|
||||
console.log('ERROR: Failed to connect.');
|
||||
socket.removeAllListeners();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { BrowserWindow, ipcMain } from "electron";
|
||||
import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
|
||||
import { backgroundMitt } from './emitter';
|
||||
import { sendMessage } from './session';
|
||||
import { updateRecorder } from './audio';
|
||||
import * as path from "path";
|
||||
|
||||
interface WindowSettings {
|
||||
|
|
@ -12,23 +12,46 @@ interface WindowSettings {
|
|||
resizable: boolean;
|
||||
}
|
||||
|
||||
interface TextMessage {
|
||||
audio: 0;
|
||||
content: string;
|
||||
interface RenderMessage {
|
||||
content: string;
|
||||
context: string;
|
||||
subContext: string;
|
||||
modifiers: string;
|
||||
time: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const handleMessage = (_event, arg: TextMessage | Buffer ) => {
|
||||
sendMessage(arg);
|
||||
interface IpcRendererPayload {
|
||||
endpoint: string;
|
||||
message: RenderMessage | null;
|
||||
}
|
||||
|
||||
let win: BrowserWindow | null;
|
||||
|
||||
const windowMount = (): void => {
|
||||
backgroundMitt.emit('window-active', true);
|
||||
ipcMain.on('send-message', handleMessage);
|
||||
ipcMain.on('update-recorder', updateRecorder);
|
||||
}
|
||||
|
||||
export const createWindow = async (options: WindowSettings): Promise<BrowserWindow> => {
|
||||
const windowDismount = (): void => {
|
||||
win = null;
|
||||
backgroundMitt.emit('window-active', false);
|
||||
ipcMain.removeAllListeners('update-recorder');
|
||||
}
|
||||
|
||||
backgroundMitt.on('ipc-renderer', (payload: IpcRendererPayload) => {
|
||||
if (win)
|
||||
win.webContents.send(payload.endpoint, {
|
||||
message: payload.message
|
||||
});
|
||||
});
|
||||
|
||||
export const createWindow = async (options: WindowSettings): Promise<void> => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
const win: BrowserWindow = new BrowserWindow({
|
||||
|
||||
if (win) resolve();
|
||||
|
||||
win = new BrowserWindow({
|
||||
width: options.width,
|
||||
height: options.height,
|
||||
resizable: options.resizable,
|
||||
|
|
@ -50,9 +73,12 @@ export const createWindow = async (options: WindowSettings): Promise<BrowserWind
|
|||
win.loadURL("app://./index.html");
|
||||
}
|
||||
|
||||
// Handle window close.
|
||||
win.on("closed", windowDismount);
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
windowMount();
|
||||
resolve(win);
|
||||
resolve();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
<template>
|
||||
<svg
|
||||
id="messenger"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
@click="emittMessage"
|
||||
>
|
||||
<MessageVisualizer />
|
||||
<TextAudioInput />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
// child components
|
||||
import MessageVisualizer from "./messageVisualizer/index.vue";
|
||||
import TextAudioInput from "@/components/taInput/index.vue";
|
||||
|
||||
// event emitter
|
||||
import { Mitt } from "@/types/mitt/index";
|
||||
|
||||
import { defineComponent, ref, inject } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
name: "Messenger",
|
||||
components: { MessageVisualizer, TextAudioInput },
|
||||
|
||||
setup() {
|
||||
const count = ref(0);
|
||||
|
||||
// imports mitt Emitter safely
|
||||
let emitter: Mitt;
|
||||
const emitterInject: Mitt | undefined = inject("mitt");
|
||||
|
||||
if (emitterInject) {
|
||||
emitter = emitterInject;
|
||||
}
|
||||
|
||||
// Render message when render-message event called.
|
||||
window.ipcRenderer.on("render-message", (event, payload) => {
|
||||
console.log(payload.message);
|
||||
emitter.emit("renderMessage", payload.message);
|
||||
});
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#messenger {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
background-color: #e6e6e6;
|
||||
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
// border-radius: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
:viewBox="scrollView"
|
||||
>
|
||||
<g id="messageVisualizer" transform="translate(0, 5)">
|
||||
<g
|
||||
v-for="(item, index) in renderArr"
|
||||
:key="index"
|
||||
class="messageList"
|
||||
transform="translate(0, 25)"
|
||||
preserverAspectRatio="none"
|
||||
>
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="beforeEnter"
|
||||
v-on:appear="enter"
|
||||
v-on:after-enter="afterEnter"
|
||||
>
|
||||
<MessageItem :item="item" :key="index" />
|
||||
</transition>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import useMessageVisualizer from "./viewDetails/visualizer";
|
||||
import useScrollView from "@/modules/scrollView";
|
||||
import MessageItem from "../messageBubble/index.vue";
|
||||
import { Message } from "@/types/message/index";
|
||||
import { Mitt } from "@/types/mitt/index";
|
||||
import { defineComponent, reactive, inject } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MessageVisualizer",
|
||||
components: { MessageItem },
|
||||
setup() {
|
||||
const renderArr: Message[] = reactive([]);
|
||||
|
||||
// imports mitt Emitter safely
|
||||
let emitter: Mitt;
|
||||
const emitterInject: Mitt | undefined = inject("mitt");
|
||||
if (emitterInject) {
|
||||
emitter = emitterInject;
|
||||
emitter.on("renderMessage", (payload: Message | undefined) => {
|
||||
if (payload) renderArr.push(payload);
|
||||
});
|
||||
}
|
||||
|
||||
const { beforeEnter, enter, afterEnter } = useMessageVisualizer();
|
||||
const { scrollView } = useScrollView({
|
||||
targetId: "messageVisualizer",
|
||||
});
|
||||
|
||||
return {
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
scrollView,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
svg {
|
||||
height: 1%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#messageRenderer {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
import { inject } from "vue";
|
||||
import AnimeFunc from "@/types/animejs/index";
|
||||
import { MessageAnimeFunc } from '@/types/message/index';
|
||||
|
||||
/**
|
||||
* anime js animations used by message renderer
|
||||
*/
|
||||
export default function useMessageViewAnims(): {
|
||||
shiftAnimate: MessageAnimeFunc;
|
||||
stackAnimate: MessageAnimeFunc;
|
||||
} {
|
||||
// imports animejs safely
|
||||
let anime: AnimeFunc;
|
||||
const animeInject: AnimeFunc | undefined = inject("animejs");
|
||||
if (animeInject) anime = animeInject;
|
||||
|
||||
// shifts message list by a given value
|
||||
function shiftList({ targetList, sv }: { targetList: NodeList | undefined; sv: number | undefined }) {
|
||||
if (targetList) {
|
||||
for (const element of targetList) {
|
||||
const el = element.parentNode as HTMLElement;
|
||||
anime({
|
||||
targets: el,
|
||||
transform: `translate(0 ${sv})`,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adds new message at the bottom of the list and shifts existing message list
|
||||
const shiftAnimate: MessageAnimeFunc = (el, transform, shiftValue, targetList) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.initialTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
begin: function() {
|
||||
shiftList({
|
||||
targetList,
|
||||
sv: shiftValue
|
||||
});
|
||||
},
|
||||
complete: function() {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.finalTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
offset: 1000
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// stacks message from top to bottom
|
||||
const stackAnimate: MessageAnimeFunc = (el, transform) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.initialTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 1000,
|
||||
complete: function() {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform.finalTranslate,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
offset: 1000
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
shiftAnimate,
|
||||
stackAnimate
|
||||
};
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index';
|
||||
import useMessageViewAnims from "./anime";
|
||||
import useOffsetCalculator from './offsetCalculator';
|
||||
|
||||
/**
|
||||
* handles visualization of view messages through
|
||||
* vue transition callbacks and anime-js animations
|
||||
*/
|
||||
export default function useMessageVisualizer(): {
|
||||
beforeEnter: VueTransitionCallback;
|
||||
enter: VueTransitionCallback;
|
||||
afterEnter: VueTransitionCallback;
|
||||
} {
|
||||
// uses offsetCalculator logic and renderer animations
|
||||
const { calculateMessageOffsets } = useOffsetCalculator();
|
||||
const { shiftAnimate, stackAnimate } = useMessageViewAnims();
|
||||
|
||||
const messagePadding = 15;
|
||||
let messageList: NodeList;
|
||||
let message: HTMLElement | null;
|
||||
let messageOffset = { x: 0, y: 0 };
|
||||
let shift = false;
|
||||
let shiftOffset = 0;
|
||||
|
||||
// animates message item to 'enter' renderView
|
||||
const animateMessage = (el: SVGGElement): void => {
|
||||
|
||||
const transform = {
|
||||
initialTranslate: `translate(${messageOffset.x} ${messageOffset.y})`,
|
||||
finalTranslate: `translate(${messageOffset.x} ${messageOffset.y})`
|
||||
}
|
||||
shift ? shiftAnimate(el, transform, shiftOffset, messageList) : stackAnimate(el, transform);
|
||||
}
|
||||
|
||||
const beforeEnter: VueTransitionCallback = () => {
|
||||
const queryResult = document.querySelectorAll(".messageList");
|
||||
if (queryResult.length) messageList = queryResult;
|
||||
}
|
||||
|
||||
const enter: VueTransitionCallback = (el) => {
|
||||
// query DOM for latest message as soon as it enters
|
||||
if (el) {
|
||||
message = document.getElementById(el.id);
|
||||
}
|
||||
}
|
||||
|
||||
const afterEnter: VueTransitionCallback = (el) => {
|
||||
// get message positioning & shift state before animating
|
||||
if (message) {
|
||||
messageOffset = calculateMessageOffsets(message);
|
||||
shift = messageOffset.y > 400 ? true : false;
|
||||
}
|
||||
if (el) {
|
||||
if (shift) {
|
||||
|
||||
console.log(messageOffset.y)
|
||||
if (messageOffset.y < 445) {
|
||||
shiftOffset -= 15;
|
||||
} else {
|
||||
shiftOffset -= el.getBBox().height + messagePadding;
|
||||
}
|
||||
}
|
||||
animateMessage(el);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter
|
||||
};
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
<template>
|
||||
<div id="login">
|
||||
|
||||
<!-- login title -->
|
||||
<div id="loginTitle">Login</div>
|
||||
|
||||
<!-- username and password forms -->
|
||||
<div id="loginBox">
|
||||
|
||||
<!-- username -->
|
||||
<input
|
||||
class="input"
|
||||
type="text"
|
||||
v-model="login.username"
|
||||
placeholder="username"
|
||||
/>
|
||||
|
||||
<!-- password -->
|
||||
<input
|
||||
class="input"
|
||||
type="password"
|
||||
v-model="login.password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- submit button -->
|
||||
<button class="button" v-on:click="submitCreds">Submit</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
name: "Login",
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
login: {
|
||||
username: "",
|
||||
password: ""
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
#login {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
#loginBox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
background-color: #B9B9B9;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 16px;
|
||||
text-decoration: none;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: #58C4FD;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
</style>
|
||||
92
src/components/messageView/index.vue
Normal file
92
src/components/messageView/index.vue
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
:viewBox="scrollView"
|
||||
>
|
||||
<g id="messageView" transform="translate(0, 20)">
|
||||
<g v-for="(item, index) in renderArr" :key="index" preserverAspectRatio="none">
|
||||
<transition
|
||||
appear
|
||||
v-on:before-appear="beforeEnter"
|
||||
v-on:appear="enter"
|
||||
v-on:after-enter="afterEnter"
|
||||
>
|
||||
<TextBubble :item="item" :key="index" />
|
||||
</transition>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import TextBubble from "@/components/textBubble/index.vue";
|
||||
import { Message } from "@/types/message/index";
|
||||
import useTransitions from "./viewDetails/transitions";
|
||||
import useScrollView from "@/modules/scrollView";
|
||||
import useMitt from "@/modules/mitt";
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import { Queue } from '@/modules/queue';
|
||||
import { defineComponent, reactive, onMounted, onUnmounted, watch } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MessageView",
|
||||
components: { TextBubble },
|
||||
setup() {
|
||||
const { emitter } = useMitt();
|
||||
const renderArr: Message[] = reactive([]);
|
||||
const renderQ = new Queue();
|
||||
|
||||
const { invoke } = useIpc("message");
|
||||
const { beforeEnter, enter, afterEnter, rendering } = useTransitions();
|
||||
const { scrollView } = useScrollView({
|
||||
targetId: "messageView",
|
||||
});
|
||||
|
||||
const render = (m: Message) => {
|
||||
if (rendering.value) {
|
||||
renderQ.enqueue(m);
|
||||
} else {
|
||||
renderArr.push(m);
|
||||
}
|
||||
}
|
||||
|
||||
watch(rendering, (rendering, _prevRendering) => {
|
||||
if (!rendering) {
|
||||
const m = renderQ.dequeue() as Message | null;
|
||||
if (m) renderArr.push(m);
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
window.ipcRenderer.on("render-message", (event, payload) => {
|
||||
const m = payload.message;
|
||||
if (m.content) render(m);
|
||||
});
|
||||
|
||||
emitter.on("user-message", async (message) => {
|
||||
try {
|
||||
const res = await invoke(message);
|
||||
render(res)
|
||||
} catch (e) {
|
||||
console.log("No response. Do not render.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.ipcRenderer.removeAllListeners("render-message");
|
||||
emitter.all.clear();
|
||||
});
|
||||
|
||||
return {
|
||||
renderArr,
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
scrollView,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
60
src/components/messageView/viewDetails/anime.ts
Normal file
60
src/components/messageView/viewDetails/anime.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import { inject } from "vue";
|
||||
import AnimeFunc from "@/types/animejs/index";
|
||||
|
||||
/**
|
||||
* anime js animations used by message view transitions
|
||||
*/
|
||||
export default function useMessageViewAnims() {
|
||||
// imports animejs safely
|
||||
let anime: AnimeFunc;
|
||||
const animeInject: AnimeFunc | undefined = inject("animejs");
|
||||
if (animeInject) anime = animeInject;
|
||||
|
||||
// update message View bottom bound
|
||||
const shiftView = (el: SVGGElement, transform: string) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 500,
|
||||
});
|
||||
}
|
||||
|
||||
// stacks message from top to bottom
|
||||
const stackAnimate = (el: Element, transform: string) => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 1000,
|
||||
complete: function() {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// adds new message at the bottom of the list and shifts existing message list
|
||||
const shiftAnimate = (el: Element, transform: string, view: SVGGElement, viewTransform: string) => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
anime({
|
||||
targets: el,
|
||||
transform: transform,
|
||||
easing: "easeInOutQuad",
|
||||
duration: 800,
|
||||
begin: function() {
|
||||
shiftView(view, viewTransform);
|
||||
},
|
||||
complete: function() {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
shiftAnimate,
|
||||
stackAnimate,
|
||||
};
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ export default function useOffsetCalculator() {
|
|||
let previousMessageHeight = 0;
|
||||
const messagePadding = 15;
|
||||
|
||||
function calculateX(message: HTMLElement): void {
|
||||
function calculateX(message: HTMLElement| SVGGElement): void {
|
||||
const computedQuery = window.getComputedStyle(message);
|
||||
const matrix = new WebKitCSSMatrix(computedQuery.webkitTransform);
|
||||
xOffset.value = matrix.m41;
|
||||
85
src/components/messageView/viewDetails/transitions.ts
Normal file
85
src/components/messageView/viewDetails/transitions.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/**
|
||||
* Do stuff before, on, and after message enters the view.
|
||||
* Rendering Process consists of the execution of the above
|
||||
* mentioned callbacks followed by the shift or stack animation.
|
||||
* The animation called depends on the height of the message view
|
||||
* relative to the window height. Additionally, the animation will
|
||||
* always be called on the after enter callback, after all the neccesary
|
||||
* calculations have been completed. While all of this is hapenning,
|
||||
* the rendering state is updated throughout the process.
|
||||
*/
|
||||
|
||||
import { VueTransitionCallback } from '@/types/vue3/vueTransitionCallback/index';
|
||||
import useMessageViewAnims from "./anime";
|
||||
import useOffsetCalculator from './offsetCalculator';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const wH = 500; // window Height
|
||||
const vP = 10; // view padding
|
||||
const mP = 15; // message padding
|
||||
let mH: number; // message Height
|
||||
let vH: number; // view Height
|
||||
let vB: number; // view Bottom Bound
|
||||
let message: HTMLElement | null;
|
||||
let messageOffset = { x: 0, y: 0 };
|
||||
let shift = false;
|
||||
let beforeEnterVH: number;
|
||||
let messageView: SVGGElement;
|
||||
|
||||
export default function useTransitions() {
|
||||
const { calculateMessageOffsets } = useOffsetCalculator();
|
||||
const { shiftAnimate, stackAnimate } = useMessageViewAnims();
|
||||
const rendering = ref(false);
|
||||
|
||||
const animateMessage = async (el: SVGGElement) => {
|
||||
|
||||
const elTransform = `translate(${messageOffset.x} ${messageOffset.y})`;
|
||||
const viewTransform = `translate(0 ${-vB})`;
|
||||
|
||||
if (shift) {
|
||||
await shiftAnimate(el, elTransform, messageView, viewTransform);
|
||||
} else {
|
||||
await stackAnimate(el, elTransform)
|
||||
}
|
||||
rendering.value = false;
|
||||
}
|
||||
|
||||
const beforeEnter: VueTransitionCallback = () => {
|
||||
rendering.value = true;
|
||||
// query DOM for messageView element
|
||||
const messageViewQuery = document.querySelectorAll("#messageView");
|
||||
messageView = messageViewQuery[0] as SVGGElement;
|
||||
if (messageViewQuery) {
|
||||
beforeEnterVH = messageView.getBBox().height;
|
||||
}
|
||||
}
|
||||
|
||||
const enter: VueTransitionCallback = (el) => {
|
||||
// query DOM for latest message
|
||||
if (el) {
|
||||
message = document.getElementById(el.id);
|
||||
}
|
||||
}
|
||||
|
||||
const afterEnter: VueTransitionCallback = (el) => {
|
||||
|
||||
if (message) messageOffset = calculateMessageOffsets(message);
|
||||
|
||||
if (el) {
|
||||
// calculate message & view heights, as well as view bottom bound
|
||||
mH = el.getBoundingClientRect().height;
|
||||
vH = mH + beforeEnterVH + mP;
|
||||
vB = Math.abs(vH - wH) + vP;
|
||||
|
||||
shift = vH > wH ? true : false;
|
||||
animateMessage(el);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
beforeEnter,
|
||||
enter,
|
||||
afterEnter,
|
||||
rendering
|
||||
};
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<template>
|
||||
<div id="splash">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="57.046"
|
||||
height="52.759"
|
||||
viewBox="0 0 57.046 52.759"
|
||||
>
|
||||
<g transform="translate(-4127 -507)">
|
||||
<g transform="translate(3949 332.206)">
|
||||
<g transform="translate(178 174.794)">
|
||||
<g transform="translate(0 27.405)">
|
||||
<circle
|
||||
cx="12.677"
|
||||
cy="12.677"
|
||||
r="12.677"
|
||||
transform="translate(0 0)"
|
||||
fill="#383838"
|
||||
/>
|
||||
<circle
|
||||
cx="12.677"
|
||||
cy="12.677"
|
||||
r="12.677"
|
||||
transform="translate(31.692 0)"
|
||||
fill="#383838"
|
||||
/>
|
||||
</g>
|
||||
<circle
|
||||
cx="12.677"
|
||||
cy="12.677"
|
||||
r="12.677"
|
||||
transform="translate(15.822 0)"
|
||||
fill="#383838"
|
||||
/>
|
||||
<path
|
||||
d="M36.27,83.67"
|
||||
transform="translate(-23.569 -43.588)"
|
||||
fill="#ff0"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
name: "Splash",
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
#splash {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #EBEBEB;
|
||||
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
// border-radius: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
|
@ -1,37 +1,46 @@
|
|||
import { ref, watch, onUnmounted, onMounted } from "vue";
|
||||
import useKeyDownHandler from "@/modules/keyDownHandler/useKeyDownHandler";
|
||||
import useMediaStream from "@/modules/mediaStream";
|
||||
import useAudioVisualizer from './audioDetails/audioVisualizer';
|
||||
import useTextVisualizer from './textDetails/textVisualizer';
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
// NOTE: input params should probably be input and MediaStream
|
||||
// TODO: visualize audio stream from nodeJS background process
|
||||
|
||||
import { ref, watch, onUnmounted, onMounted } from "vue";
|
||||
import useKeyDownHandler from "@/modules/keyDownHandler/useKeyDownHandler";
|
||||
import useMediaStream from "@/modules/mediaStream";
|
||||
import useAudioVisualizer from './audioDetails/audioVisualizer';
|
||||
import useTextVisualizer from './textDetails/textVisualizer';
|
||||
import useMitt from "@/modules/mitt";
|
||||
import { useIpc } from '@/modules/ipc';
|
||||
|
||||
let stream: MediaStream;
|
||||
|
||||
export default function useInputController() {
|
||||
const visualizeStream = ref(false);
|
||||
const paths = ref([]);
|
||||
const audioBubbleWidth = ref(10);
|
||||
let stream: MediaStream;
|
||||
const { emitter } = useMitt();
|
||||
const { post } = useIpc('update-recorder');
|
||||
|
||||
// send message on ENTER
|
||||
const enterCallback = (input: string) => {
|
||||
|
||||
const message = {
|
||||
audio: 0,
|
||||
text: input
|
||||
};
|
||||
emitter.emit("user-message", message);
|
||||
}
|
||||
|
||||
const { keyDownHandler, input } = useKeyDownHandler();
|
||||
const { textInputXoffset, renderTextInput } = useTextVisualizer(input);
|
||||
const { visualizeStreamAsPaths, expandBubble } = useAudioVisualizer(visualizeStream);
|
||||
const { keyDownHandler, input } = useKeyDownHandler(enterCallback);
|
||||
const { textInputXoffset, renderTextInput } = useTextVisualizer(input);
|
||||
|
||||
// stops stream recording on space key up
|
||||
function keyupHandler(e: any) {
|
||||
if (e.key === " " && visualizeStream.value) {
|
||||
console.log("stop recording");
|
||||
|
||||
window.postMessage({
|
||||
myTypeField: 'update-recorder',
|
||||
record: false
|
||||
}, '*')
|
||||
|
||||
post(false);
|
||||
visualizeStream.value = false;
|
||||
paths.value = []
|
||||
audioBubbleWidth.value = 10;
|
||||
|
|
@ -39,15 +48,18 @@ export default function useInputController() {
|
|||
}
|
||||
}
|
||||
|
||||
// add window event keyboard listeners
|
||||
window.addEventListener("keydown", keyDownHandler);
|
||||
window.addEventListener('keyup', keyupHandler);
|
||||
|
||||
// get stream & initialize recorder object on mount
|
||||
onMounted(async () => {
|
||||
stream = await useMediaStream({ audio: true });
|
||||
// add window event keyboard listeners
|
||||
window.addEventListener("keydown", keyDownHandler);
|
||||
window.addEventListener('keyup', keyupHandler);
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("keydown", keyDownHandler);
|
||||
window.removeEventListener("keyup", keyupHandler);
|
||||
});
|
||||
|
||||
// determine whether to render text or audio based one the keyboard input
|
||||
watch(input, (input, prevInput) => {
|
||||
if (prevInput !== "" || prevInput.length > 0) {
|
||||
|
|
@ -57,14 +69,8 @@ export default function useInputController() {
|
|||
return;
|
||||
}
|
||||
if (input === " " && visualizeStream.value === false) {
|
||||
console.log("record MediaStream");
|
||||
visualizeStream.value = true;
|
||||
|
||||
window.postMessage({
|
||||
myTypeField: 'update-recorder',
|
||||
record: true
|
||||
}, '*')
|
||||
|
||||
post(true);
|
||||
expandBubble(audioBubbleWidth);
|
||||
visualizeStreamAsPaths(stream, paths, audioBubbleWidth);
|
||||
return;
|
||||
|
|
@ -72,11 +78,6 @@ export default function useInputController() {
|
|||
renderTextInput();
|
||||
});
|
||||
|
||||
// remove Event Listeners on component unMount
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("keydown", keyDownHandler);
|
||||
window.removeEventListener("keyup", keyupHandler);
|
||||
});
|
||||
|
||||
return {
|
||||
input,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
import { ref, computed, inject } from 'vue';
|
||||
import useTextInputAnims from "./textAnime";
|
||||
import { Ref } from "@/types/vueRef/index";
|
||||
/*
|
||||
* text rendering logic used by inputController
|
||||
*/
|
||||
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||
import useTextInputAnims from "./textAnime";
|
||||
import { Ref } from "@/types/vueRef/index";
|
||||
import useMitt from "@/modules/mitt";
|
||||
|
||||
export default function useTextVisualizer(input: Ref<string>) {
|
||||
const inputHeight = ref(42);
|
||||
const inputWidth = ref(0);
|
||||
|
||||
const emitter: any = inject("mitt");
|
||||
const { emitter } = useMitt();
|
||||
const { animateSend, verticalShiftInput, inputAppear } = useTextInputAnims();
|
||||
|
||||
async function renderTextInput() {
|
||||
|
|
@ -32,10 +34,16 @@ export default function useTextVisualizer(input: Ref<string>) {
|
|||
}
|
||||
}
|
||||
|
||||
emitter.on("newSelfMessage", async (payload: any) => {
|
||||
const inputEl = document.getElementsByClassName("inputContainer");
|
||||
const foreignEl = inputEl[0] as HTMLElement;
|
||||
animateSend(foreignEl, inputHeight.value, input);
|
||||
onMounted(() => {
|
||||
emitter.on("user-message", () => {
|
||||
const inputEl = document.getElementsByClassName("inputContainer");
|
||||
const foreignEl = inputEl[0] as HTMLElement;
|
||||
animateSend(foreignEl, inputHeight.value, input);
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.all.clear();
|
||||
});
|
||||
|
||||
const textInputXoffset = computed(() => {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export default function useComputedBubble(m: string, id: string) {
|
|||
}
|
||||
|
||||
const startingOffset = computed(() => {
|
||||
const parentView = document.getElementById('messageVisualizer');
|
||||
const parentView = document.getElementById('messageView');
|
||||
if (parentView) {
|
||||
const rect = parentView.getBoundingClientRect();
|
||||
let Y = 600;
|
||||
|
|
@ -29,13 +29,11 @@
|
|||
<script lang="ts">
|
||||
import useComputedBubble from "./bubbleDetails/computed";
|
||||
import useBubbleDrawer from "./bubbleDetails/drawer";
|
||||
|
||||
// text wrap composition
|
||||
import useTextWrap from "@/modules/textWrap";
|
||||
|
||||
import { defineComponent, onMounted, ref, reactive } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MessageItem",
|
||||
name: "TextBubble",
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
|
|
@ -2,12 +2,12 @@ import { reactive, toRefs } from 'vue';
|
|||
import { useIpc } from './ipc';
|
||||
|
||||
interface AuthState {
|
||||
accessToken?: string | null;
|
||||
accessToken: string | null;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
const state = reactive<AuthState>({
|
||||
accessToken: undefined,
|
||||
accessToken: null,
|
||||
error: undefined,
|
||||
});
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ const AUTH_KEY = 'crimata_token';
|
|||
const token = window.localStorage.getItem(AUTH_KEY);
|
||||
|
||||
const authToken = async () => {
|
||||
const { data, invoke } = useIpc('auth-user');
|
||||
const { data, invoke } = useIpc('auth-session');
|
||||
try {
|
||||
await invoke(token);
|
||||
state.accessToken = data.value;
|
||||
|
|
@ -28,29 +28,26 @@ const authToken = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// authenticate on socket connect
|
||||
window.ipcRenderer.on("fetch-token", async (_event, _arg) => {
|
||||
authToken();
|
||||
// authenticate on auth event
|
||||
window.ipcRenderer.on("auth", async (_event, _arg) => {
|
||||
await authToken();
|
||||
});
|
||||
|
||||
if (token) {
|
||||
authToken();
|
||||
state.accessToken = token;
|
||||
}
|
||||
|
||||
export const useAuth = () => {
|
||||
const setToken = (token: string, remember: boolean) => {
|
||||
if (remember) {
|
||||
// Save
|
||||
window.localStorage.setItem(AUTH_KEY, token);
|
||||
}
|
||||
|
||||
const setToken = (token: string) => {
|
||||
window.localStorage.setItem(AUTH_KEY, token);
|
||||
state.accessToken = token;
|
||||
state.error = undefined;
|
||||
}
|
||||
|
||||
const logout = (): Promise<void> => {
|
||||
const logout = (): Promise<null> => {
|
||||
window.localStorage.removeItem(AUTH_KEY);
|
||||
return Promise.resolve(state.accessToken = undefined);
|
||||
return Promise.resolve(state.accessToken = null);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ import { ref, computed } from 'vue'
|
|||
|
||||
export const useIpc = (endpoint: string) => {
|
||||
const data = ref();
|
||||
const loading = ref(false);
|
||||
const error = ref();
|
||||
const listener = ref(false);
|
||||
|
||||
const errorMessage = computed(() => {
|
||||
console.log('ERROR', error.value);
|
||||
|
|
@ -13,54 +11,29 @@ export const useIpc = (endpoint: string) => {
|
|||
}
|
||||
})
|
||||
|
||||
const invoke = (payload: any) => {
|
||||
loading.value = true;
|
||||
const invoke = async (payload: any) => {
|
||||
error.value = undefined;
|
||||
|
||||
return window.ipcRenderer.invoke(endpoint, payload).then(res => {
|
||||
data.value = res;
|
||||
}).catch(e => {
|
||||
try {
|
||||
const res = await window.ipcRenderer.invoke(endpoint, payload);
|
||||
return data.value = res;
|
||||
} catch (e) {
|
||||
error.value = e;
|
||||
throw e;
|
||||
}).finally(() => {
|
||||
loading.value = false;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const send = (payload?: Record<string, any>, callback?: (arg: any) => void) => {
|
||||
loading.value = true;
|
||||
error.value = undefined;
|
||||
|
||||
window.ipcRenderer.on(endpoint + '-reply', (event: any, arg: any | Error) => {
|
||||
if (arg instanceof Error) {
|
||||
error.value = arg;
|
||||
throw arg;
|
||||
} else {
|
||||
data.value = arg;
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
window.ipcRenderer.send(endpoint, payload);
|
||||
};
|
||||
|
||||
const onEvent = (callback: (event: any, arg: any) => void) => {
|
||||
listener.value = true;
|
||||
window.ipcRenderer.on(endpoint, callback);
|
||||
};
|
||||
|
||||
const post = (payload?: Record<string, any>) => {
|
||||
const post = (payload: any) => {
|
||||
window.postMessage({
|
||||
myTypeField: endpoint,
|
||||
message: payload
|
||||
endpoint: endpoint,
|
||||
content: payload
|
||||
}, '*')
|
||||
};
|
||||
|
||||
return {
|
||||
loading,
|
||||
data,
|
||||
error,
|
||||
errorMessage,
|
||||
send,
|
||||
invoke
|
||||
invoke,
|
||||
post
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,18 @@
|
|||
import { ref, inject } from "vue";
|
||||
import { ref } from "vue";
|
||||
import keyboardNameMap from "./keyBoardMaps/keyboardNameMap";
|
||||
import keyboardCharMap from "./keyBoardMaps/keyboardCharMap";
|
||||
// This catches keys from a physical keyboard, a soft keyboard on a tablet, or a
|
||||
// scanner attached via USB
|
||||
export default function useKeyDownHandler() {
|
||||
interface KeyDownEvent {
|
||||
|
||||
interface KeyDownEvent {
|
||||
keyCode: number;
|
||||
shiftKey: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// This catches keys from a physical keyboard, a soft keyboard on a tablet, or a
|
||||
// scanner attached via USB
|
||||
export default function useKeyDownHandler(enterCallback: (input: string) => void | null) {
|
||||
|
||||
const emitter: any = inject("mitt");
|
||||
const input = ref("");
|
||||
|
||||
// submits newSelfMessage event
|
||||
function handleEnterKey() {
|
||||
// does nothing if input value is empty
|
||||
if (input.value === "") {
|
||||
return;
|
||||
}
|
||||
const message = {
|
||||
text: input.value,
|
||||
audio: 0
|
||||
};
|
||||
// fire event with message payload
|
||||
emitter.emit("newSelfMessage", message);
|
||||
|
||||
window.postMessage({
|
||||
myTypeField: 'send-message',
|
||||
message: message
|
||||
}, '*')
|
||||
}
|
||||
|
||||
function keyDownHandler(e: KeyDownEvent) {
|
||||
// keyboardCharMap is an array of arrays, with each inner
|
||||
// array having 2 columns - un-shifted, and shifted values.
|
||||
|
|
@ -49,7 +31,7 @@ export default function useKeyDownHandler() {
|
|||
const cmd = keyboardNameMap[e.keyCode];
|
||||
switch (cmd) {
|
||||
case "ENTER":
|
||||
handleEnterKey();
|
||||
enterCallback(input.value);
|
||||
break;
|
||||
case "BACK_SPACE":
|
||||
input.value = input.value.slice(0, -1);
|
||||
|
|
@ -66,4 +48,4 @@ export default function useKeyDownHandler() {
|
|||
keyDownHandler,
|
||||
input
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
src/modules/mitt.ts
Normal file
17
src/modules/mitt.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { inject } from "vue";
|
||||
import { Mitt } from "@/types/mitt/index";
|
||||
|
||||
let emitter: Mitt;
|
||||
|
||||
export default function useMitt() {
|
||||
|
||||
const emitterInject: Mitt | undefined = inject("mitt");
|
||||
if (emitterInject) {
|
||||
emitter = emitterInject;
|
||||
}
|
||||
return {
|
||||
emitter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
78
src/modules/queue.ts
Normal file
78
src/modules/queue.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
export interface DataNode<T> {
|
||||
data: T;
|
||||
next: DataNode<T> | null;
|
||||
}
|
||||
|
||||
export interface QueueI<T> {
|
||||
enqueue(data: T): void;
|
||||
dequeue(): T | null;
|
||||
peek(): T | null;
|
||||
size(): number;
|
||||
}
|
||||
|
||||
export class Queue<T> implements QueueI<T> {
|
||||
private _size: number;
|
||||
private head: DataNode<T> | null;
|
||||
private tail: DataNode<T> | null;
|
||||
constructor() {
|
||||
this._size = 0;
|
||||
this.head = this.tail = null;
|
||||
}
|
||||
|
||||
enqueue(data: T) {
|
||||
|
||||
const node: DataNode<T> = {
|
||||
data,
|
||||
next: null
|
||||
}
|
||||
if (this.head === null) {
|
||||
this.head = this.tail = node;
|
||||
} else {
|
||||
if (this.tail) {
|
||||
this.tail.next = node;
|
||||
this.tail = this.tail.next;
|
||||
}
|
||||
|
||||
}
|
||||
++this._size;
|
||||
}
|
||||
|
||||
dequeue(): T | null {
|
||||
|
||||
let item: T | null = null;
|
||||
|
||||
if (this._size === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.head) {
|
||||
item = this.head.data;
|
||||
this.head = this.head.next;
|
||||
--this._size;
|
||||
|
||||
if (!this._size) {
|
||||
this.tail = null;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
peek(): T | null {
|
||||
|
||||
let item: T | null = null;
|
||||
|
||||
if (this._size === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.head) {
|
||||
item = this.head.data;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
size(): number {
|
||||
return this._size;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { ref, computed, onMounted, onUnmounted } from "vue";
|
||||
|
||||
/**
|
||||
* handles visualization of view messages through
|
||||
* handles visualization of view messages through
|
||||
* vue transition callbacks and anime-js animations
|
||||
*/
|
||||
export default function useScrollView({ targetId }: { targetId: string }) {
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
interface SocketState {
|
||||
connection: WebSocket | null;
|
||||
auth: boolean;
|
||||
}
|
||||
|
||||
// Create WebSocket connection.
|
||||
const socket = new WebSocket('ws://localhost:8080');
|
||||
|
||||
// Connection opened
|
||||
socket.onopen = function (event) {
|
||||
socket.send('Hello Server!');
|
||||
}
|
||||
|
||||
socket.onmessage = function(event) {
|
||||
console.debug("WebSocket message received:", event);
|
||||
}
|
||||
|
||||
|
|
@ -17,22 +17,14 @@ process.once("loaded", () => {
|
|||
// do something with custom event
|
||||
const message = event.data;
|
||||
|
||||
if (message.myTypeField === "send-message") {
|
||||
ipcRenderer.send("send-message", message.message);
|
||||
if (message.endpoint === "update-menu-bar") {
|
||||
ipcRenderer.send("update-menu-bar", message.content);
|
||||
}
|
||||
|
||||
if (message.myTypeField === "update-menu-bar") {
|
||||
ipcRenderer.send("update-menu-bar", message);
|
||||
}
|
||||
|
||||
if (message.myTypeField === "update-recorder") {
|
||||
ipcRenderer.send("update-recorder", message.record);
|
||||
}
|
||||
|
||||
if (message.myTypeField === "submit-creds") {
|
||||
ipcRenderer.send("submit-creds", message)
|
||||
if (message.endpoint === "update-recorder") {
|
||||
ipcRenderer.send("update-recorder", message.content);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
RouteRecordRaw
|
||||
} from "vue-router";
|
||||
import Home from "@/views/home.vue";
|
||||
import Splash from "@/views/splash.vue";
|
||||
import { useAuth } from '@/modules/auth';
|
||||
|
||||
// Define the routes (/*) for the app here.
|
||||
|
|
@ -15,6 +16,14 @@ const routes: Array<RouteRecordRaw> = [
|
|||
component: Home,
|
||||
meta: { requiresAuth: true },
|
||||
},
|
||||
{
|
||||
path: "/splash",
|
||||
name: "splash",
|
||||
component: Splash,
|
||||
meta: {
|
||||
requiresAuth: false
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
|
|
@ -34,14 +43,19 @@ const router = createRouter({
|
|||
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' });
|
||||
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' });
|
||||
else if ((to.name == 'login' || to.name == 'register') && accessToken.value){
|
||||
next({ name: 'home' });
|
||||
}
|
||||
|
||||
// Carry On...
|
||||
else next();
|
||||
|
|
|
|||
|
|
@ -1,17 +1,32 @@
|
|||
<template>
|
||||
<HomeComponent />
|
||||
<svg
|
||||
id="messenger"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<MessageView />
|
||||
<TextAudioInput />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import MessageView from "@/components/messageView/index.vue";
|
||||
import TextAudioInput from "@/components/taInput/index.vue";
|
||||
import { defineComponent } from "vue";
|
||||
import HomeComponent from "@/components/home/index.vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
name: "Home",
|
||||
components: { HomeComponent },
|
||||
|
||||
name: "Messenger",
|
||||
components: { MessageView, TextAudioInput },
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
#messenger {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
background-color: #e6e6e6;
|
||||
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
// border-radius: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@
|
|||
<label for="checkbox">Remember Me</label>
|
||||
|
||||
<!-- submit button; position: fixed -->
|
||||
<button class="button" @click="submit">Submit</button>
|
||||
<button class="button" @click.prevent="submit">Submit</button>
|
||||
|
||||
<!-- back to login button: position: fixed -->
|
||||
<button class="button2" @click="switchView">Create an account</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
|
|
@ -45,9 +44,9 @@ export default defineComponent({
|
|||
|
||||
const email = ref("");
|
||||
const password = ref("");
|
||||
const rememberMe = ref(false);
|
||||
const rememberMe = ref(true);
|
||||
|
||||
const { data, invoke } = useIpc('auth-user');
|
||||
const { data, invoke } = useIpc('auth-session');
|
||||
|
||||
const submit = async () => {
|
||||
const payload = {
|
||||
|
|
@ -57,8 +56,7 @@ export default defineComponent({
|
|||
};
|
||||
try {
|
||||
await invoke(payload);
|
||||
console.log('testing incoke', data.value)
|
||||
setToken(data.value, rememberMe.value);
|
||||
setToken(data.value);
|
||||
router.push({ name: "home" });
|
||||
} catch(e){
|
||||
console.log('Error loging in.')
|
||||
|
|
|
|||
|
|
@ -6,42 +6,40 @@
|
|||
</div>
|
||||
|
||||
<!-- username and password forms -->
|
||||
<div id="registerBox">
|
||||
<form id="registerBox" @submit.prevent="submit">
|
||||
<!-- username -->
|
||||
<input class="input" type="text" v-model="email" placeholder="email" />
|
||||
<input class="input" type="text" v-model="email" placeholder="email" required/>
|
||||
|
||||
<!-- password -->
|
||||
<input class="input" type="password" v-model="password" placeholder="Password" />
|
||||
<input class="input" type="password" v-model="password" placeholder="Password" required/>
|
||||
|
||||
<!-- firstName -->
|
||||
<input class="input" type="text" v-model="password2" placeholder="Re-enter password" />
|
||||
</div>
|
||||
<!-- re-enter passoword -->
|
||||
<input class="input" type="password" v-model="password2" placeholder="Re-enter password" required/>
|
||||
|
||||
<!-- submit button; position: fixed -->
|
||||
<button class="button" @click="submit">Submit</button>
|
||||
<!-- submit button; position: fixed -->
|
||||
<button class="button" type="submit">Submit</button>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- back to login button: position: fixed -->
|
||||
<button class="button2" @click="switchView">Back to login</button>
|
||||
<button class="button2" @click.prevent="switchView">Back to login</button>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
onErrorCaptured,
|
||||
reactive,
|
||||
ref,
|
||||
toRefs,
|
||||
} from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useIpc } from "@/modules/ipc";
|
||||
import { useAuth } from "@/modules/auth";
|
||||
|
||||
interface RegisterPayload {
|
||||
request?: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
request: string;
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -49,25 +47,46 @@ export default defineComponent({
|
|||
setup() {
|
||||
const email = ref("");
|
||||
const password = ref("");
|
||||
const rememberMe = ref("");
|
||||
const password2 = ref("");
|
||||
|
||||
const { invoke, data,} = useIpc("auth-user");
|
||||
const { invoke, data,} = useIpc("auth-session");
|
||||
const { setToken } = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
const payload: RegisterPayload = {
|
||||
request: "register",
|
||||
email: email.value,
|
||||
password: password.value,
|
||||
};
|
||||
const re = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
||||
|
||||
const passwordMatch = () => {
|
||||
let match = false;
|
||||
if (password.value == password2.value) {
|
||||
match = true;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
let valid = false;
|
||||
if (re.test(email.value) && passwordMatch()) {
|
||||
valid = true;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
try {
|
||||
await invoke(payload);
|
||||
setToken(data.value, true);
|
||||
router.push({ name: "home" });
|
||||
} catch(e) {
|
||||
console.log('Failed to register.')
|
||||
|
||||
const payload: RegisterPayload = {
|
||||
request: "register",
|
||||
email: email.value,
|
||||
password: password.value,
|
||||
};
|
||||
|
||||
if (validate()) {
|
||||
try {
|
||||
await invoke(payload);
|
||||
setToken(data.value);
|
||||
router.push({ name: "home" });
|
||||
} catch(e) {
|
||||
console.log('Failed to register.')
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -78,6 +97,7 @@ export default defineComponent({
|
|||
return {
|
||||
email,
|
||||
password,
|
||||
password2,
|
||||
switchView,
|
||||
submit,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,17 +1,72 @@
|
|||
<template>
|
||||
<SplashComponent />
|
||||
<div id="splash">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="57.046"
|
||||
height="52.759"
|
||||
viewBox="0 0 57.046 52.759"
|
||||
>
|
||||
<g transform="translate(-4127 -507)">
|
||||
<g transform="translate(3949 332.206)">
|
||||
<g transform="translate(178 174.794)">
|
||||
<g transform="translate(0 27.405)">
|
||||
<circle
|
||||
cx="12.677"
|
||||
cy="12.677"
|
||||
r="12.677"
|
||||
transform="translate(0 0)"
|
||||
fill="#383838"
|
||||
/>
|
||||
<circle
|
||||
cx="12.677"
|
||||
cy="12.677"
|
||||
r="12.677"
|
||||
transform="translate(31.692 0)"
|
||||
fill="#383838"
|
||||
/>
|
||||
</g>
|
||||
<circle
|
||||
cx="12.677"
|
||||
cy="12.677"
|
||||
r="12.677"
|
||||
transform="translate(15.822 0)"
|
||||
fill="#383838"
|
||||
/>
|
||||
<path
|
||||
d="M36.27,83.67"
|
||||
transform="translate(-23.569 -43.588)"
|
||||
fill="#ff0"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
import { defineComponent } from "vue";
|
||||
import SplashComponent from "@/components/splash/index.vue"
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
name: "Splash",
|
||||
components: { SplashComponent },
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
#splash {
|
||||
width: 350px;
|
||||
height: 500px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #EBEBEB;
|
||||
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
// border-radius: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
160
tests/mockMessages.ts
Normal file
160
tests/mockMessages.ts
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import { Message } from "@/types/message/index";
|
||||
|
||||
export const Messages: Message[] = [
|
||||
{
|
||||
content: "Good morning Dave",
|
||||
context: "launch",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "2",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content:
|
||||
"add contact",
|
||||
context: "addcontact",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "1",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "I'm looking for name, crimata_idto addcontact. Feel free toenter only a subset of thisinformation, but then let meknow when you are done",
|
||||
context: "addcontact",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "5",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "andrew gundersen",
|
||||
context: "addcontact",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "6",
|
||||
time: ""
|
||||
},
|
||||
|
||||
{
|
||||
content: "gundersena@xavier.edu",
|
||||
context: "addcontact",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "3",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "I already have a contact forandrew gundersen. Are you sureyou want this?",
|
||||
context: "addcontact",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "7",
|
||||
time: ""
|
||||
},
|
||||
|
||||
{
|
||||
content: "Yes posting it online soon.",
|
||||
context: "You to Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "4",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Hey do you know Enrique Hernandez?",
|
||||
context: "Message from Crimata",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "8",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Hey Anna, did you get the paper done?",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "9",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Hey Anna, did you get the paper done?",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "10",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Yes posting it online soon.",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "11",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content:
|
||||
"I can be there at 5 pm tomorrow to greet you at a Chick file with my almond and chive salad.",
|
||||
context: "You to Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "12",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Hey Anna, did you get the paper done?",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "13",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Hey Anna, did you get the paper done?",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "14",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Yes posting it online soon.",
|
||||
context: "You to Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "15",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Sweet, thanks!",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "16",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Hey do you know Enrique Hernandez?",
|
||||
context: "Message from Crimata AI",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "17",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Yes posting it online soon.",
|
||||
context: "You to Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "sf",
|
||||
id: "18",
|
||||
time: ""
|
||||
},
|
||||
{
|
||||
content: "Sweet, thanks!",
|
||||
context: "Message from Tommy McConville",
|
||||
subContext: "",
|
||||
modifier: "ai",
|
||||
id: "19",
|
||||
time: ""
|
||||
},
|
||||
];
|
||||
|
|
@ -8,10 +8,10 @@ wss.on("connection", function connection(ws, req) {
|
|||
ws.on("message", function incoming(message) {
|
||||
|
||||
console.log(message)
|
||||
if (message === 'no-token' || message === 'undefined') {
|
||||
console.log('no token to authenticate');
|
||||
ws.send('locked');
|
||||
}
|
||||
if (message === 'no-token' || message === 'undefined') {
|
||||
console.log('no token to authenticate');
|
||||
ws.send('success');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue