From ee203d93ba58f7737d54540d5dea627d82b2930b Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 08:44:06 -0500 Subject: [PATCH 01/66] enhancements --- package.json | 6 +----- src/background.ts | 11 ++++++++-- tests/audio.js | 2 +- yarn.lock | 53 ++++++++++++++++++++++++++++++----------------- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 852a3e9..5a395f7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "Crimata", "productName": "Crimata Messenger", "description": "Cross-platform messenger application built with electron, vue3, and TS.", - "version": "0.9.0", + "version": "0.9.2", "private": true, "author": { "name": "Enrique Hernandez" @@ -12,10 +12,6 @@ "dev": "vue-cli-service electron:serve", "build": "vue-cli-service electron:build" }, - "repository": { - "type" : "git", - "url" : "https://gitlab.com/crimata/electron-app.git" - }, "dependencies": { "@google-cloud/speech": "^4.2.0", "@types/animejs": "^3.1.2", diff --git a/src/background.ts b/src/background.ts index 1613f63..654c673 100644 --- a/src/background.ts +++ b/src/background.ts @@ -24,14 +24,21 @@ const isDev = require('electron-is-dev'); })(); -// Auto app updates. +// Code for auto app updates. if (!isDev) { + + autoUpdater.setFeedURL({ + url: "https://gitlab.com/api/v4/projects/25637892/releases", + headers: {"PRIVATE-TOKEN": "fSCN8xr4EgccV7z1UNaw"}, + serverType: "default" + }) + autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => { const dialogOpts = { type: 'info', buttons: ['Restart', 'Later'], title: 'Application Update', - message: releaseName, + message: process.platform === 'win32' ? releaseNotes : releaseName, detail: 'A new version has been downloaded. Restart the application to apply the updates.' } diff --git a/tests/audio.js b/tests/audio.js index d0f3595..b8ab22f 100644 --- a/tests/audio.js +++ b/tests/audio.js @@ -86,7 +86,7 @@ function testCallback() { } function splitArrayIntoChunksOfLen(buf, len) { - let chunks = []; + const chunks = []; let i = 0; let L = len; console.log(buf.byteLength) diff --git a/yarn.lock b/yarn.lock index 8d5a2cf..fa7ce8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1391,6 +1391,11 @@ dependencies: "@types/node" "*" +"@types/electron-devtools-installer@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/electron-devtools-installer/-/electron-devtools-installer-2.2.0.tgz#32ee4ebbe99b3daf9847a6d2097dc00b5de94f10" + integrity sha512-HJNxpaOXuykCK4rQ6FOMxAA0NLFYsf7FiPFGmab0iQmtVBHSAfxzy3MRFpLTTDDWbV0yD2YsHOQvdu8yCqtCfw== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -4317,7 +4322,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -5597,19 +5602,19 @@ execa@^3.3.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== +execa@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" + integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" is-stream "^2.0.0" merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" strip-final-newline "^2.0.0" exit@^0.1.2: @@ -6304,6 +6309,11 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" + integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -6938,6 +6948,11 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -9425,7 +9440,7 @@ npm-run-path@^3.0.0: dependencies: path-key "^3.0.0" -npm-run-path@^4.0.0: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -9579,7 +9594,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -11521,7 +11536,7 @@ sigmund@^1.0.1: resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= -signal-exit@^3.0.0, signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== @@ -12979,15 +12994,15 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -vue-cli-plugin-electron-builder@~2.0.0-rc.4: - version "2.0.0-rc.5" - resolved "https://registry.yarnpkg.com/vue-cli-plugin-electron-builder/-/vue-cli-plugin-electron-builder-2.0.0-rc.5.tgz#87cd8d09877f5f3ae339abc0bedc47d7d2b733ac" - integrity sha512-l1/BkwxMDgDSz3fW+KPM3mdVu6ItR6jGhqR6xGhTHxre3dH9XCEfpT+esZp6wxex9trUJzlL+wMmzm79dYKl0A== +vue-cli-plugin-electron-builder@~2.0.0-rc.6: + version "2.0.0-rc.6" + resolved "https://registry.yarnpkg.com/vue-cli-plugin-electron-builder/-/vue-cli-plugin-electron-builder-2.0.0-rc.6.tgz#2c0df46167ef50c71923cf47836bb7e4f6685c29" + integrity sha512-VDpPwdGZ5qoEZe5DuPmyvDB8Ip/CyarpA9cWnEWNJcZ/2NajnglirMCa6cbLrwt9vsv6HFa28IsmVtaVu4dFqw== dependencies: "@vue/cli-shared-utils" "^4.5.6" chokidar "^3.0.2" electron-builder "^22.2.0" - execa "^4.0.0" + execa "^5.0.0" friendly-errors-webpack-plugin "^1.7.0" fs-extra "^9.0.1" lodash.merge "^4.6.1" From 809ec5e05a78394ccc37893da72688e4eebe7acd Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 09:57:32 -0500 Subject: [PATCH 02/66] enhancements --- package.json | 2 +- src/background.ts | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b6bdecf..de60418 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "Crimata", "productName": "Crimata Messenger", "description": "Cross-platform messenger application built with electron, vue3, and TS.", - "version": "0.9.2", + "version": "0.9.1", "private": true, "author": { "name": "Enrique Hernandez" diff --git a/src/background.ts b/src/background.ts index be71771..95db12b 100644 --- a/src/background.ts +++ b/src/background.ts @@ -21,15 +21,14 @@ const isDev = require('electron-is-dev'); // NOTE Program Begins Here (async () => { + autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'seMF_apn237iUw8puG9a' } autoUpdater.logger = log; - // Check for an update 10sec after Program Starts - setTimeout(function () { - autoUpdater.checkForUpdatesAndNotify() - }, 10000) + // Check for updates right away. + autoUpdater.checkForUpdatesAndNotify() - // Check for an update every 2min. + // Then, every two minuntes... setInterval(() => { autoUpdater.checkForUpdatesAndNotify() }, 120000) From a17c552b66c0bd4b797d0c6dabe56aa3ad8afe06 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 10:47:35 -0500 Subject: [PATCH 03/66] cicd --- .gitlab-ci.yml | 8 ++++---- src/background.ts | 10 ++++++---- yarn.lock | 7 +------ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fe8056b..2adb652 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,7 @@ stages: build: stage: Build - image: electronuserland/builder:wine + image: electronuserland/builder before_script: - yarn script: @@ -25,7 +25,7 @@ build: - main variables: - WIN_BINARY: '${APPNAME}-${VERSION}.exe' + BINARY: '${APPNAME}-${VERSION}.exe' PACKAGE_REGISTRY_URL: '${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${APPNAME}/${VERSION}' upload: @@ -38,7 +38,7 @@ upload: when: never # Do not run this job when a tag is created manually - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: - - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist/${WIN_BINARY}" "${PACKAGE_REGISTRY_URL}/${WIN_BINARY}"' + - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist/${BINARY}" "${PACKAGE_REGISTRY_URL}/${BINARY}"' auto-release-master: image: registry.gitlab.com/gitlab-org/release-cli @@ -57,4 +57,4 @@ auto-release-master: - | release-cli create --name "Release $VERSION" --tag-name v$VERSION \ --description 'Created using the release-cli. $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ - --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${WIN_BINARY}\"}" + --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${BINARY}\"}" diff --git a/src/background.ts b/src/background.ts index 95db12b..77e704c 100644 --- a/src/background.ts +++ b/src/background.ts @@ -21,16 +21,18 @@ const isDev = require('electron-is-dev'); // NOTE Program Begins Here (async () => { - + autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'seMF_apn237iUw8puG9a' } autoUpdater.logger = log; - // Check for updates right away. + autoUpdater.on('update-downloaded', () => { + autoUpdater.quitAndInstall() + }) + autoUpdater.checkForUpdatesAndNotify() - // Then, every two minuntes... setInterval(() => { - autoUpdater.checkForUpdatesAndNotify() + autoUpdater.checkForUpdatesAndNotify() }, 120000) console.log('Starting Crimata electron app.'); diff --git a/yarn.lock b/yarn.lock index 76ed0cc..e89e34a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1391,11 +1391,6 @@ dependencies: "@types/node" "*" -"@types/electron-devtools-installer@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@types/electron-devtools-installer/-/electron-devtools-installer-2.2.0.tgz#32ee4ebbe99b3daf9847a6d2097dc00b5de94f10" - integrity sha512-HJNxpaOXuykCK4rQ6FOMxAA0NLFYsf7FiPFGmab0iQmtVBHSAfxzy3MRFpLTTDDWbV0yD2YsHOQvdu8yCqtCfw== - "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -12999,7 +12994,7 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -vue-cli-plugin-electron-builder@~2.0.0-rc.6: +vue-cli-plugin-electron-builder@~2.0.0-rc.4: version "2.0.0-rc.6" resolved "https://registry.yarnpkg.com/vue-cli-plugin-electron-builder/-/vue-cli-plugin-electron-builder-2.0.0-rc.6.tgz#2c0df46167ef50c71923cf47836bb7e4f6685c29" integrity sha512-VDpPwdGZ5qoEZe5DuPmyvDB8Ip/CyarpA9cWnEWNJcZ/2NajnglirMCa6cbLrwt9vsv6HFa28IsmVtaVu4dFqw== From 9283c0511535c5c07b04801b1d4baf5b19972ff5 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 11:19:21 -0500 Subject: [PATCH 04/66] cicd --- electron.builder.yml | 51 -------------------------------------------- package.json | 13 +---------- 2 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 electron.builder.yml diff --git a/electron.builder.yml b/electron.builder.yml deleted file mode 100644 index 2590695..0000000 --- a/electron.builder.yml +++ /dev/null @@ -1,51 +0,0 @@ -electronVersion: 9.0.0 -compression: normal -npmRebuild: false -# TODO: enable this in the future once we sign all the linux builds. -#forceCodeSigning: true -directories: - output: dist - buildResources: build - app: . - -mac: - category: Reference - icon: ./icons/icon.icns - target: - - target: dmg - - target: zip - - # steps for notarizing the MacOS builds: - # https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/ - - hardenedRuntime: true - gatekeeperAssess: false - entitlements: build/macos/entitlements.mac.plist - entitlementsInherit: build/macos/entitlements.mac.plist - -dmg: - # The inner app inside the .dmg is signed and there is some broken logic - # which requires that the DMG itself is not signed. - sign: false - - -nsis: - artifactName: ${name}-${version}-${arch}.${ext} - -appx: - artifactName: ${name}-${version}-${arch}.${ext} - applicationId: polar - identityName: 25130KevinBurton.PolarBookshelf - publisher: CN=D3591277-F57D-4C75-B342-D158E6C4AAF5 - publisherDisplayName: Kevin Burton - - -# https://www.electron.build/configuration/publish -# https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/ -publish: - provider: github - publishAutoUpdate: true - -asar: true -afterPack: "./electron-builder-afterpack.js" -afterSign: "./build/macos/notarize.js" diff --git a/package.json b/package.json index de60418..f92ddea 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "scripts": { "dev": "vue-cli-service electron:serve", "serve": "vue-cli-service serve", - "build": "electron-builder --win", + "build": "electron-builder --mac", "test:unit": "vue-cli-service test:unit", "lint": "vue-cli-service lint", "electron:build": "vue-cli-service electron:build", @@ -30,17 +30,6 @@ "publish": { "provider": "generic", "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" - }, - "win": { - "target": [ - "nsis" - ], - "verifyUpdateCodeSignature": false - }, - "linux": { - "target": [ - "AppImage" - ] } }, "dependencies": { From c1285893a4b8f5527f0550ee577911da496f1e52 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 11:38:17 -0500 Subject: [PATCH 05/66] cicd --- package.json | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/package.json b/package.json index f92ddea..498d9ee 100644 --- a/package.json +++ b/package.json @@ -10,15 +10,7 @@ "main": "./src/background.ts", "scripts": { "dev": "vue-cli-service electron:serve", - "serve": "vue-cli-service serve", - "build": "electron-builder --mac", - "test:unit": "vue-cli-service test:unit", - "lint": "vue-cli-service lint", - "electron:build": "vue-cli-service electron:build", - "electron:serve": "vue-cli-service electron:serve", - "postinstall": "electron-builder install-app-deps", - "postuninstal": "electron-builder install-app-deps", - "dist": "electron-builder --publish always" + "build": "vue-cli-service electron:build", }, "repository": { "type": "git", From 97a6514966eca67ade3a3e323eede207b879cced Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 11:40:50 -0500 Subject: [PATCH 06/66] cicd --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 498d9ee..dfd278b 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "main": "./src/background.ts", "scripts": { "dev": "vue-cli-service electron:serve", - "build": "vue-cli-service electron:build", + "build": "vue-cli-service electron:build" }, "repository": { "type": "git", From bb437e1b5f5f50a94dbe29016408e725c0842bb0 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 12:27:03 -0500 Subject: [PATCH 07/66] cicd --- .browserslistrc | 3 --- package.json | 22 +++++++++++++++++----- vue.config.js | 30 ------------------------------ 3 files changed, 17 insertions(+), 38 deletions(-) delete mode 100644 .browserslistrc delete mode 100644 vue.config.js diff --git a/.browserslistrc b/.browserslistrc deleted file mode 100644 index 214388f..0000000 --- a/.browserslistrc +++ /dev/null @@ -1,3 +0,0 @@ -> 1% -last 2 versions -not dead diff --git a/package.json b/package.json index dfd278b..93b0b2e 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,23 @@ "url": "https://gitlab.com/crimata/electron-app.git", "release": "latest" }, - "build": { - "artifactName": "${productName}-${version}.${ext}", - "publish": { - "provider": "generic", - "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" + "vue": { + "plugin-options": { + + // Electron builder options. + "electronBuilder": { + "builderOptions": { + "appId": "com.crimata.App", + "productName": "Crimata Messenger", + "artifactName": "${productName}-${version}.${ext}", + "publish": { + "provider": "generic", + "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" + } + }, + "preload": "src/preload.ts" + } + } }, "dependencies": { diff --git a/vue.config.js b/vue.config.js deleted file mode 100644 index f2ae6a0..0000000 --- a/vue.config.js +++ /dev/null @@ -1,30 +0,0 @@ -// NOTE needed imports for rust wasm -// const path = require("path"); -// const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); -// const OptimizeWasmPlugin = require("optimize-wasm-webpack-plugin"); - -module.exports = { - lintOnSave: false, - configureWebpack: { - // NOTE uncomment to use rust wasm - // optimization: { - // minimizer: [new OptimizeWasmPlugin()] - // }, - // plugins: [ - // new WasmPackPlugin({ - // crateDirectory: path.resolve(__dirname, "crate") - // }) - // ] - }, - pluginOptions: { - electronBuilder: { - builderOptions: { - // TODO electron-builder config https://www.electron.build/configuration/configuration - appId: "com.crimata.messenger", - productName: "Crimata Messenger", - - }, - preload: "src/preload.ts" - } - } -}; From d9582a8f3aa4c983c134dbd3feb55c96a762c1b9 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 12:28:15 -0500 Subject: [PATCH 08/66] cicd --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 93b0b2e..0d1bc8b 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,8 @@ "release": "latest" }, "vue": { - "plugin-options": { + "pluginOptions": { - // Electron builder options. "electronBuilder": { "builderOptions": { "appId": "com.crimata.App", From b5669238960fb86ff2568f7ff8ea58fafaf4fc3e Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 12:39:42 -0500 Subject: [PATCH 09/66] cicd --- package.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0d1bc8b..de29c96 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "author": { "name": "Enrique Hernandez" }, - "main": "./src/background.ts", + "main": "background.js", "scripts": { "dev": "vue-cli-service electron:serve", "build": "vue-cli-service electron:build" @@ -18,9 +18,10 @@ "release": "latest" }, "vue": { + "lintOnSave": false, "pluginOptions": { - "electronBuilder": { + "preload": "src/preload.ts", "builderOptions": { "appId": "com.crimata.App", "productName": "Crimata Messenger", @@ -29,10 +30,8 @@ "provider": "generic", "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" } - }, - "preload": "src/preload.ts" + } } - } }, "dependencies": { From 8597d4899ab72231e11dbafbdf44076397e5835f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 12:55:10 -0500 Subject: [PATCH 10/66] cicd --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2adb652..ab014d9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,7 +25,7 @@ build: - main variables: - BINARY: '${APPNAME}-${VERSION}.exe' + PACKAGE: '${APPNAME}-${VERSION}.dmg' PACKAGE_REGISTRY_URL: '${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${APPNAME}/${VERSION}' upload: @@ -38,7 +38,7 @@ upload: when: never # Do not run this job when a tag is created manually - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: - - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist/${BINARY}" "${PACKAGE_REGISTRY_URL}/${BINARY}"' + - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist_electron/${PACKAGE}" "${PACKAGE_REGISTRY_URL}/${PACKAGE}"' auto-release-master: image: registry.gitlab.com/gitlab-org/release-cli @@ -57,4 +57,4 @@ auto-release-master: - | release-cli create --name "Release $VERSION" --tag-name v$VERSION \ --description 'Created using the release-cli. $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ - --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${BINARY}\"}" + --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE}\"}" From 5fe6e4f047b31a0174d2a795da65331b848ff8d1 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 12:59:15 -0500 Subject: [PATCH 11/66] cicd --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ab014d9..a221de4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,7 @@ build: dotenv: variables.env name: $CI_COMMIT_REF_SLUG paths: - - $CI_PROJECT_DIR/dist/*.* + - $CI_PROJECT_DIR/dist_electron/*.dmg when: on_success only: - main From f7e70f02fa8204d97ed330958cdebce8e537a0ae Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 13:13:23 -0500 Subject: [PATCH 12/66] cicd --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 46762a2..0a10082 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,7 @@ pnpm-debug.log* *.sw? #Electron-builder output -/dist_electron +/dist_electron/* #Electron-builder config electron-builder.yml From a01507b2bd021fd41d56ac69aeb50d0796409e84 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 13:17:54 -0500 Subject: [PATCH 13/66] cicd --- .gitignore | 2 +- .gitlab-ci.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0a10082..46762a2 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,7 @@ pnpm-debug.log* *.sw? #Electron-builder output -/dist_electron/* +/dist_electron #Electron-builder config electron-builder.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a221de4..ba17b77 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,7 @@ build: dotenv: variables.env name: $CI_COMMIT_REF_SLUG paths: - - $CI_PROJECT_DIR/dist_electron/*.dmg + - $CI_PROJECT_DIR/dist_electron/*.* when: on_success only: - main From 687762bca455c043ee686db569ea2adbfd53e35f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 13:56:28 -0500 Subject: [PATCH 14/66] cicd --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index de29c96..712f332 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,10 @@ "electronBuilder": { "preload": "src/preload.ts", "builderOptions": { - "appId": "com.crimata.App", + "mac": { + "target": "dmg" + }, + "appId": "com.crimata.${name}", "productName": "Crimata Messenger", "artifactName": "${productName}-${version}.${ext}", "publish": { From 2c891190924e3701de532b9d0b3506b3a372d1ca Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 14:24:02 -0500 Subject: [PATCH 15/66] cicd --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 712f332..8d21426 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "main": "background.js", "scripts": { "dev": "vue-cli-service electron:serve", - "build": "vue-cli-service electron:build" + "build": "vue-cli-service electron:build --mac" }, "repository": { "type": "git", From 5f3e14f557884ce33567dcc3a468ae1acb0a8dec Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 14:43:25 -0500 Subject: [PATCH 16/66] cicd --- .gitlab-ci.yml | 2 +- package.json | 67 +-- tests/unit/electron.spec.js | 2 +- yarn.lock | 828 ++++++++++++------------------------ 4 files changed, 317 insertions(+), 582 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ba17b77..4d77815 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ build: - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env - - yarn build + - yarn electron:build --macos dmg artifacts: reports: dotenv: variables.env diff --git a/package.json b/package.json index 8d21426..a0f7a5e 100644 --- a/package.json +++ b/package.json @@ -1,42 +1,18 @@ { "name": "Crimata", - "productName": "Crimata Messenger", - "description": "Cross-platform messenger application built with electron, vue3, and TS.", "version": "0.9.1", "private": true, + "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { "name": "Enrique Hernandez" }, - "main": "background.js", "scripts": { - "dev": "vue-cli-service electron:serve", - "build": "vue-cli-service electron:build --mac" - }, - "repository": { - "type": "git", - "url": "https://gitlab.com/crimata/electron-app.git", - "release": "latest" - }, - "vue": { - "lintOnSave": false, - "pluginOptions": { - "electronBuilder": { - "preload": "src/preload.ts", - "builderOptions": { - "mac": { - "target": "dmg" - }, - "appId": "com.crimata.${name}", - "productName": "Crimata Messenger", - "artifactName": "${productName}-${version}.${ext}", - "publish": { - "provider": "generic", - "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" - } - } - } - } + "electron:build": "vue-cli-service electron:build", + "electron:serve": "vue-cli-service electron:serve", + "postinstall": "electron-builder install-app-deps", + "postuninstall": "electron-builder install-app-deps" }, + "main": "background.js", "dependencies": { "@google-cloud/speech": "^4.2.0", "@types/animejs": "^3.1.2", @@ -60,6 +36,7 @@ "ws": "^7.3.1" }, "devDependencies": { + "@types/electron-devtools-installer": "^2.2.0", "@types/jest": "^24.0.19", "@typescript-eslint/eslint-plugin": "^2.33.0", "@typescript-eslint/parser": "^2.33.0", @@ -83,11 +60,31 @@ "node-sass": "^4.12.0", "optimize-wasm-webpack-plugin": "^1.0.12", "sass-loader": "^8.0.2", - "spectron": "^11.0.0", + "spectron": "11.0.0", "typescript": "~3.9.3", - "vue-cli-plugin-electron-builder": "~2.0.0-rc.4", + "vue-cli-plugin-electron-builder": "~2.0.0-rc.6", "vue-jest": "^5.0.0-0" }, + "vue": { + "lintOnSave": false, + "pluginOptions": { + "electronBuilder": { + "preload": "src/preload.ts", + "builderOptions": { + "mac": { + "target": "dmg" + }, + "appId": "com.crimata.${name}", + "productName": "Crimata Messenger", + "artifactName": "${productName}-${version}.${ext}", + "publish": { + "provider": "generic", + "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" + } + } + } + } + }, "gitHooks": { "pre-commit": "lint-staged" }, @@ -96,5 +93,11 @@ "vue-cli-service lint", "git add" ] + }, + "productName": "Crimata Messenger", + "repository": { + "type": "git", + "url": "https://gitlab.com/crimata/electron-app.git", + "release": "latest" } } diff --git a/tests/unit/electron.spec.js b/tests/unit/electron.spec.js index 049759d..ddd262c 100644 --- a/tests/unit/electron.spec.js +++ b/tests/unit/electron.spec.js @@ -24,7 +24,7 @@ test('Window Loads Properly', async () => { // App is loaded properly expect( /Welcome to Your Vue\.js (\+ TypeScript )?App/.test( - await client.getHTML('#app') + await (await app.client.$('#app')).getHTML() ) ).toBe(true) diff --git a/yarn.lock b/yarn.lock index e89e34a..8dc3fba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1243,11 +1243,6 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4" - integrity sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ== - "@soda/friendly-errors-webpack-plugin@^1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.7.1.tgz#706f64bcb4a8b9642b48ae3ace444c70334d615d" @@ -1269,13 +1264,6 @@ dependencies: defer-to-connect "^1.0.1" -"@szmarczak/http-timer@^4.0.5": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152" - integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ== - dependencies: - defer-to-connect "^2.0.0" - "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -1291,18 +1279,6 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== -"@types/archiver@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-3.1.1.tgz#10cc1be44af8911e57484342c7b3b32a5f178a1a" - integrity sha512-TzVZ9204sH1TuFylfr1cw/AA/3/VldAAXswEwKLXUOzA9mDg+m6gHF9EaqKNlozcjc6knX5m1KAqJzksPLSEfw== - dependencies: - "@types/glob" "*" - -"@types/atob@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@types/atob/-/atob-2.1.2.tgz#157eb0cc46264a8c55f2273a836c7a1a644fb820" - integrity sha512-8GAYQ1jDRUQkSpHzJUqXwAkYFOxuWAOGLhIR4aPd/Y/yL12Q/9m7LsKpHKlfKdNE/362Hc9wPI1Yh6opDfxVJg== - "@types/babel__core@^7.1.0": version "7.1.12" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" @@ -1349,16 +1325,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/cacheable-request@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976" - integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "*" - "@types/node" "*" - "@types/responselike" "*" - "@types/connect-history-api-fallback@*": version "1.3.3" resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.3.tgz#4772b79b8b53185f0f4c9deab09236baf76ee3b4" @@ -1391,6 +1357,11 @@ dependencies: "@types/node" "*" +"@types/electron-devtools-installer@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/electron-devtools-installer/-/electron-devtools-installer-2.2.0.tgz#32ee4ebbe99b3daf9847a6d2097dc00b5de94f10" + integrity sha512-HJNxpaOXuykCK4rQ6FOMxAA0NLFYsf7FiPFGmab0iQmtVBHSAfxzy3MRFpLTTDDWbV0yD2YsHOQvdu8yCqtCfw== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -1415,14 +1386,14 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/fs-extra@^9.0.1", "@types/fs-extra@^9.0.2": +"@types/fs-extra@^9.0.1": version "9.0.3" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.3.tgz#9996e5cce993508c32325380b429f04a1327523e" integrity sha512-NKdGoXLTFTRED3ENcfCsH8+ekV4gbsysanx2OPbstXVV6fZMgUCqTxubs6I9r7pbOJbFgVq1rpFtLURjKCZWUw== dependencies: "@types/node" "*" -"@types/glob@*", "@types/glob@^7.1.1": +"@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== @@ -1430,11 +1401,6 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/http-cache-semantics@*": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a" - integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A== - "@types/http-proxy-middleware@*": version "0.19.3" resolved "https://registry.yarnpkg.com/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz#b2eb96fbc0f9ac7250b5d9c4c53aade049497d03" @@ -1483,39 +1449,6 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== -"@types/keyv@*": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7" - integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw== - dependencies: - "@types/node" "*" - -"@types/lodash.clonedeep@^4.5.6": - version "4.5.6" - resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.6.tgz#3b6c40a0affe0799a2ce823b440a6cf33571d32b" - integrity sha512-cE1jYr2dEg1wBImvXlNtp0xDoS79rfEdGozQVgliDZj1uERH4k+rmEMTudP9b4VQ8O6nRb5gPqft0QzEQGMQgA== - dependencies: - "@types/lodash" "*" - -"@types/lodash.isplainobject@^4.0.6": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#757d2dcdecbb32f4452018b285a586776092efd1" - integrity sha512-8G41YFhmOl8Ck6NrwLK5hhnbz6ADfuDJP+zusDnX3PoYhfC60+H/rQE6zmdO4yFzPCPJPY4oGZK2spbXm6gYEA== - dependencies: - "@types/lodash" "*" - -"@types/lodash.merge@^4.6.6": - version "4.6.6" - resolved "https://registry.yarnpkg.com/@types/lodash.merge/-/lodash.merge-4.6.6.tgz#b84b403c1d31bc42d51772d1cd5557fa008cd3d6" - integrity sha512-IB90krzMf7YpfgP3u/EvZEdXVvm4e3gJbUvh5ieuI+o+XqiNEt6fCzqNRaiLlPVScLI59RxIGZMQ3+Ko/DJ8vQ== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.165" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f" - integrity sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg== - "@types/long@^4.0.0", "@types/long@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" @@ -1579,20 +1512,6 @@ "@types/duplexify" "*" "@types/node" "*" -"@types/puppeteer-core@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/puppeteer-core/-/puppeteer-core-2.0.0.tgz#3b7fbbac53d56b566f5ef096116e1d60d504aa45" - integrity sha512-JvoEb7KgEkUet009ZDrtpUER3hheXoHgQByuYpJZ5WWT7LWwMH+0NTqGQXGgoOKzs+G5NA1T4DZwXK79Bhnejw== - dependencies: - "@types/puppeteer" "*" - -"@types/puppeteer@*": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-5.4.0.tgz#1ef860bd7a9dcf0c4633aac8c0ec21f75b431868" - integrity sha512-zTYDLjnHjgzokrwKt7N0rgn7oZPYo1J0m8Ghu+gXqzLCEn8RWbELa2uprE2UFJ0jU/Sk0x9jXXdOH/5QQLFHhQ== - dependencies: - "@types/node" "*" - "@types/q@^1.5.1": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" @@ -1608,13 +1527,6 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/responselike@*", "@types/responselike@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" - integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== - dependencies: - "@types/node" "*" - "@types/semver@^7.3.4": version "7.3.4" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" @@ -1665,6 +1577,13 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== +"@types/webdriverio@^4.8.0": + version "4.13.3" + resolved "https://registry.yarnpkg.com/@types/webdriverio/-/webdriverio-4.13.3.tgz#c1571c4e62724135c0b11e7d7e36b07af5168856" + integrity sha512-AfSQM1xTO9Ax+u9uSQPDuw69DQ0qA2RMoKHn86jCgWNcwKVUjGMSP4sfSl3JOfcZN8X/gWvn7znVPp2/g9zcJA== + dependencies: + "@types/node" "*" + "@types/webpack-dev-server@^3.11.0": version "3.11.1" resolved "https://registry.yarnpkg.com/@types/webpack-dev-server/-/webpack-dev-server-3.11.1.tgz#f8f4dac1da226d530bd15a1d5dc34b23ba766ccb" @@ -2186,44 +2105,6 @@ command-exists "^1.2.7" watchpack "^1.6.0" -"@wdio/config@6.6.3": - version "6.6.3" - resolved "https://registry.yarnpkg.com/@wdio/config/-/config-6.6.3.tgz#035012ea0d1d02eb72bd181e857e893713ad9ade" - integrity sha512-zJjPpjJu05els9A2ZzOVMAYccaHSXmmqQ2h+ftelXmFgO4mYDlKufx0HaCZDdn+O0SCG0ASqv+u1KNuqmNhjDw== - dependencies: - "@wdio/logger" "6.6.0" - deepmerge "^4.0.0" - glob "^7.1.2" - -"@wdio/logger@6.6.0": - version "6.6.0" - resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-6.6.0.tgz#69375d6cf373ee8e7db7cd05085e6a325fccfdf7" - integrity sha512-BAvXcnlWdQC93MLWObetpcjHUEGR8niW2mH2KAwLPQhXwJkKxXjhlMKH/DmUn5uQ4/S7iySLlMq9EEEg9KuCwA== - dependencies: - chalk "^4.0.0" - loglevel "^1.6.0" - loglevel-plugin-prefix "^0.8.4" - strip-ansi "^6.0.0" - -"@wdio/protocols@6.6.0": - version "6.6.0" - resolved "https://registry.yarnpkg.com/@wdio/protocols/-/protocols-6.6.0.tgz#3a5fcc7bc15b8138e6e523836984f0746530e6e1" - integrity sha512-0wWSZTB4sBzr9HG3hT9a0jaO+xPhz+eFdE/qMLvM8b1yPOOgHieGPSoTXPjkBaks0CZpqeimbT4myYoim2JK1w== - -"@wdio/repl@6.7.1": - version "6.7.1" - resolved "https://registry.yarnpkg.com/@wdio/repl/-/repl-6.7.1.tgz#8e8df570b9b1ba00e02197122b4bc08b0392af40" - integrity sha512-Ty69x6HTU/dl+xO2cLiHnYqxnf9ydylgKXiqktEvnGgft47+UEcXmnz18qWwPcqX10bu6lhr8J33hEk1A4kjIQ== - dependencies: - "@wdio/utils" "6.7.0" - -"@wdio/utils@6.7.0": - version "6.7.0" - resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-6.7.0.tgz#2106584ea075d2625ebc32a37f77839fceeac861" - integrity sha512-YhbExE89Ya5d1XIh4QIOuU1UjG30fB7iiFGgldu9ZfdUusIgjTwL4vMHhK30e+5+jdqzV6jMkTAf5a6OvH+02g== - dependencies: - "@wdio/logger" "6.6.0" - "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2447,11 +2328,6 @@ address@^1.1.2: resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== -agent-base@5: - version "5.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" - integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== - agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -2639,34 +2515,31 @@ arch@^2.1.1: resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== -archiver-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" - integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== +archiver-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174" + integrity sha1-5QtMCccL89aA4y/xt5lOn52JUXQ= dependencies: - glob "^7.1.4" - graceful-fs "^4.2.0" + glob "^7.0.0" + graceful-fs "^4.1.0" lazystream "^1.0.0" - lodash.defaults "^4.2.0" - lodash.difference "^4.5.0" - lodash.flatten "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.union "^4.6.0" - normalize-path "^3.0.0" + lodash "^4.8.0" + normalize-path "^2.0.0" readable-stream "^2.0.0" -archiver@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.0.2.tgz#b2c435823499b1f46eb07aa18e7bcb332f6ca3fc" - integrity sha512-Tq3yV/T4wxBsD2Wign8W9VQKhaUxzzRmjEiSoOK0SLqPgDP/N1TKdYyBeIEu56T4I9iO4fKTTR0mN9NWkBA0sg== +archiver@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc" + integrity sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw= dependencies: - archiver-utils "^2.1.0" - async "^3.2.0" + archiver-utils "^1.3.0" + async "^2.0.0" buffer-crc32 "^0.2.1" - readable-stream "^3.6.0" - readdir-glob "^1.0.0" - tar-stream "^2.1.4" - zip-stream "^4.0.0" + glob "^7.0.0" + lodash "^4.8.0" + readable-stream "^2.0.0" + tar-stream "^1.5.0" + zip-stream "^1.2.0" are-we-there-yet@~1.1.2: version "1.1.5" @@ -2815,18 +2688,13 @@ async@0.9.x: resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= -async@^2.6.2: +async@^2.0.0, async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== dependencies: lodash "^4.17.14" -async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -3096,14 +2964,13 @@ bindings@^1.2.1, bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.3.tgz#12d6287adc29080e22a705e5764b2a9522cdc489" - integrity sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== +bl@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" + readable-stream "^2.3.5" + safe-buffer "^5.1.1" block-stream@*: version "0.0.9" @@ -3319,7 +3186,20 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@^0.2.1, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= @@ -3329,6 +3209,11 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -3358,7 +3243,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.1.0, buffer@^5.2.1, buffer@^5.5.0: +buffer@^5.1.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -3517,11 +3402,6 @@ cache-loader@^4.1.0: neo-async "^2.6.1" schema-utils "^2.0.0" -cacheable-lookup@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3" - integrity sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w== - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -3535,19 +3415,6 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" - integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^2.0.0" - call-bind@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" @@ -3681,7 +3548,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== @@ -3689,6 +3556,11 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -3743,18 +3615,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -chrome-launcher@^0.13.1: - version "0.13.4" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.13.4.tgz#4c7d81333c98282899c4e38256da23e00ed32f73" - integrity sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A== - dependencies: - "@types/node" "*" - escape-string-regexp "^1.0.5" - is-wsl "^2.2.0" - lighthouse-logger "^1.0.0" - mkdirp "^0.5.3" - rimraf "^3.0.2" - chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" @@ -3851,6 +3711,11 @@ cli-truncate@^0.2.1: slice-ansi "0.0.4" string-width "^1.0.1" +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" @@ -4027,15 +3892,15 @@ component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -compress-commons@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.0.1.tgz#c5fa908a791a0c71329fba211d73cd2a32005ea8" - integrity sha512-xZm9o6iikekkI0GnXCmAl3LQGZj5TBDj0zLowsqi7tJtEa3FMGSEcHcqrSJIrOAk1UG/NBbDn/F1q+MG/p/EsA== +compress-commons@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" + integrity sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8= dependencies: - buffer-crc32 "^0.2.13" - crc32-stream "^4.0.0" - normalize-path "^3.0.0" - readable-stream "^3.6.0" + buffer-crc32 "^0.2.1" + crc32-stream "^2.0.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" compressible@~2.0.16: version "2.0.18" @@ -4243,13 +4108,13 @@ cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -crc32-stream@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.0.tgz#05b7ca047d831e98c215538666f372b756d91893" - integrity sha512-tyMw2IeUX6t9jhgXI6um0eKfWq4EIDpfv5m7GX4Jzp7eVelQ360xd8EPXJhp2mHwLQIkqlnMLjzqSZI3a+0wRw== +crc32-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" + integrity sha1-483TtN8xaN10494/u8t7KX/pCPQ= dependencies: crc "^3.4.4" - readable-stream "^3.4.0" + readable-stream "^2.0.0" crc@^3.4.4: version "3.8.0" @@ -4380,6 +4245,13 @@ css-loader@^3.5.3: schema-utils "^2.7.0" semver "^6.3.0" +css-parse@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" + integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= + dependencies: + css "^2.0.0" + css-select-base-adapter@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" @@ -4421,7 +4293,7 @@ css-tree@^1.0.0: mdn-data "2.0.12" source-map "^0.6.1" -css-value@^0.0.1: +css-value@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" integrity sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo= @@ -4436,7 +4308,7 @@ css-what@^3.2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== -css@^2.1.0: +css@^2.0.0, css@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== @@ -4648,13 +4520,6 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -decompress-response@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" - integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== - dependencies: - mimic-response "^3.1.0" - dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -4687,11 +4552,16 @@ deepmerge@^1.5.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753" integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ== -deepmerge@^4.0.0, deepmerge@^4.2.2: +deepmerge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +deepmerge@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312" + integrity sha512-VIPwiMJqJ13ZQfaCsIFnp5Me9tnjURiaIFxfz7EH0Ci0dTSQpZtSLrqOicXqEd/z2r+z+Klk9GzmnRsgpgbOsQ== + default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -4719,11 +4589,6 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== -defer-to-connect@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.0.tgz#83d6b199db041593ac84d781b5222308ccf4c2c1" - integrity sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg== - define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -4823,26 +4688,6 @@ dev-null@^0.1.1: resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818" integrity sha1-WiBc48Ky73e2I41roXnrdMag6Bg= -devtools-protocol@0.0.809251: - version "0.0.809251" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.809251.tgz#300b3366be107d5c46114ecb85274173e3999518" - integrity sha512-pf+2OY6ghMDPjKkzSWxHMq+McD+9Ojmq5XVRYpv/kPd9sTMQxzEt21592a31API8qRjro0iYYOc3ag46qF/1FA== - -devtools@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/devtools/-/devtools-6.7.0.tgz#e5b9ecd30eb731d33ff9bd49d78d67e22f1c53a5" - integrity sha512-RkmIy2tX+XS0HM/6XGDmBHCv92jSbNKBdRcmwxHHBqYuSuVxYhLlhNwNjjA+2LZHe92xnaxW5+oGH27wyPs8Ew== - dependencies: - "@wdio/config" "6.6.3" - "@wdio/logger" "6.6.0" - "@wdio/protocols" "6.6.0" - "@wdio/utils" "6.7.0" - chrome-launcher "^0.13.1" - edge-paths "^2.1.0" - puppeteer-core "^5.1.0" - ua-parser-js "^0.7.21" - uuid "^8.0.0" - diff-sequences@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" @@ -5042,11 +4887,6 @@ ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: dependencies: safe-buffer "^5.0.1" -edge-paths@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/edge-paths/-/edge-paths-2.1.0.tgz#f273f3a0fe022422048bb78f83eb61aca29977ef" - integrity sha512-ZpIN1Vm5hlo9dkkST/1s8QqPNne2uwk3Plf6HcVUhnpfal0WnDRLdNj/wdQo3xRc+wnN3C25wPpPlV2E6aOunQ== - editorconfig@^0.15.3: version "0.15.3" resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" @@ -5074,6 +4914,11 @@ ejs@^3.1.5: dependencies: jake "^10.6.1" +ejs@~2.5.6: + version "2.5.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" + integrity sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ== + electron-builder@^22.2.0: version "22.9.1" resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.9.1.tgz#a2962db6f2757bc01d02489f38fafe0809f68f60" @@ -5703,6 +5548,15 @@ extend@^3.0.2, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -5764,11 +5618,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6234,7 +6083,7 @@ gaxios@^4.0.0: is-stream "^2.0.0" node-fetch "^2.3.0" -gaze@^1.0.0: +gaze@^1.0.0, gaze@~1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== @@ -6280,11 +6129,6 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== -get-port@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -6518,23 +6362,6 @@ google-p12-pem@^3.0.3: dependencies: node-forge "^0.10.0" -got@^11.0.2: - version "11.8.0" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.0.tgz#be0920c3586b07fd94add3b5b27cb28f49e6545f" - integrity sha512-k9noyoIIY9EejuhaBNLyZ31D5328LeqnyPNXJQb2XlJZcKakLqN5m6O/ikhq/0lw56kUYS54fVm+D1x57YC9oQ== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.1" - decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" - got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -6552,6 +6379,11 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" +graceful-fs@^4.1.0: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" @@ -6609,6 +6441,11 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -6914,27 +6751,11 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.0-beta.5.2" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz#8b923deb90144aea65cf834b016a340fc98556f3" - integrity sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ== - dependencies: - quick-lru "^5.1.1" - resolve-alpn "^1.0.0" - https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" - integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== - dependencies: - agent-base "5" - debug "4" - https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -6953,7 +6774,7 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -7136,6 +6957,26 @@ inquirer@^7.0.0, inquirer@^7.1.0: strip-ansi "^6.0.0" through "^2.3.6" +inquirer@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -7531,7 +7372,7 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1, is-wsl@^2.2.0: +is-wsl@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -8187,11 +8028,6 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -8306,13 +8142,6 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -keyv@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254" - integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA== - dependencies: - json-buffer "3.0.1" - killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" @@ -8406,14 +8235,6 @@ lie@~3.3.0: dependencies: immediate "~3.0.5" -lighthouse-logger@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz#b76d56935e9c137e86a04741f6bb9b2776e886ca" - integrity sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw== - dependencies: - debug "^2.6.8" - marky "^1.2.0" - lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -8565,46 +8386,16 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - lodash.defaultsdeep@^4.6.1: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6" integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA== -lodash.difference@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" - integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= -lodash.isobject@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" - integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0= - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - lodash.kebabcase@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" @@ -8635,26 +8426,21 @@ lodash.transform@^4.6.0: resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0" integrity sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A= -lodash.union@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" - integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash.zip@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" - integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA= - lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3, lodash@^4.17.4, lodash@~4.17.10: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.3.0, lodash@^4.8.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + log-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" @@ -8685,12 +8471,7 @@ log-update@^2.3.0: cli-cursor "^2.0.0" wrap-ansi "^3.0.1" -loglevel-plugin-prefix@^0.8.4: - version "0.8.4" - resolved "https://registry.yarnpkg.com/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz#2fe0e05f1a820317d98d8c123e634c1bd84ff644" - integrity sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g== - -loglevel@^1.6.0, loglevel@^1.6.8: +loglevel@^1.6.8: version "1.7.0" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== @@ -8803,11 +8584,6 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -marky@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02" - integrity sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ== - matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -8987,11 +8763,6 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -mimic-response@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" - integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== - mini-css-extract-plugin@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" @@ -9024,6 +8795,11 @@ minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= + minipass-collect@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" @@ -9089,11 +8865,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -9146,6 +8917,11 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -9381,7 +9157,7 @@ normalize-path@^1.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= -normalize-path@^2.1.1: +normalize-path@^2.0.0, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= @@ -9426,6 +9202,11 @@ npm-conf@^1.1.3: config-chain "^1.1.11" pify "^3.0.0" +npm-install-package@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125" + integrity sha1-1+/jz816sAYUuJbqUxGdyaslkSU= + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -9620,6 +9401,14 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" +optimist@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + optimize-wasm-webpack-plugin@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/optimize-wasm-webpack-plugin/-/optimize-wasm-webpack-plugin-1.0.12.tgz#7252da00e356822aea9089f8ca73afcac36319a8" @@ -9687,11 +9476,6 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== -p-cancelable@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e" - integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg== - p-each-series@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" @@ -10031,7 +9815,7 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -pkg-dir@^4.1.0, pkg-dir@^4.2.0: +pkg-dir@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -10479,7 +10263,7 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -progress@^2.0.0, progress@^2.0.1, progress@^2.0.3: +progress@^2.0.0, progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -10529,11 +10313,6 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" -proxy-from-env@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -10617,25 +10396,7 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" -puppeteer-core@^5.1.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-5.4.1.tgz#68b85c1aae2dcde8e41df1d12aad8852768a88bd" - integrity sha512-JfPCQgLvyBlpwQTbdnEwCEvD2KiRB2Hv+J1YCwz9o0PxlTqVSuzSQ4XeLhPmy6fZpBFynyQ+r4FSn6RUywawqA== - dependencies: - debug "^4.1.0" - devtools-protocol "0.0.809251" - extract-zip "^2.0.0" - https-proxy-agent "^4.0.0" - node-fetch "^2.6.1" - pkg-dir "^4.2.0" - progress "^2.0.1" - proxy-from-env "^1.0.0" - rimraf "^3.0.2" - tar-fs "^2.0.0" - unbzip2-stream "^1.3.3" - ws "^7.2.3" - -q@^1.1.2: +q@^1.1.2, q@~1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= @@ -10673,11 +10434,6 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== -quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -10778,7 +10534,7 @@ read-pkg@^5.1.1: parse-json "^5.0.0" type-fest "^0.6.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -10791,7 +10547,7 @@ read-pkg@^5.1.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -10800,13 +10556,6 @@ readable-stream@^3.0.0, readable-stream@^3.0.6, readable-stream@^3.1.1, readable string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdir-glob@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" - integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA== - dependencies: - minimatch "^3.0.4" - readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -10985,7 +10734,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.7: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.87.0, request@^2.88.0, request@^2.88.2: +request@^2.83.0, request@^2.87.0, request@^2.88.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -11026,11 +10775,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= -resolve-alpn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.0.0.tgz#745ad60b3d6aff4b4a48e01b8c0bdc70959e0e8c" - integrity sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA== - resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -11073,20 +10817,6 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -responselike@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" - integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw== - dependencies: - lowercase-keys "^2.0.0" - -resq@^1.9.1: - version "1.9.2" - resolved "https://registry.yarnpkg.com/resq/-/resq-1.9.2.tgz#f674b061b22b415225edb4d0b20c33a85f949fc1" - integrity sha512-Y+fprJ9wQY64gh+vJRNatiG61G+9XD5jJe4kI/Rqw6gmOa5ihZvgrxZVydqyM96xj75jwaRCPVYPU3RwsEk6ug== - dependencies: - fast-deep-equal "^2.0.1" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -11130,10 +10860,10 @@ rgb-regex@^1.0.1: resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= -rgb2hex@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.2.0.tgz#801b4887127181d1e691f610df2cecdb77330265" - integrity sha512-cHdNTwmTMPu/TpP1bJfdApd6MbD+Kzi4GNnM6h35mdFChhQPSi9cAI8J7DMn5kQDKX8NuBaQXAyo360Oa7tOEA== +rgb2hex@^0.1.9: + version "0.1.10" + resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.10.tgz#4fdd432665273e2d5900434940ceba0a04c8a8a8" + integrity sha512-vKz+kzolWbL3rke/xeTE2+6vHmZnNxGyDnaVW4OckntAIcc7DcZzWkQSfxMDwqHS8vhgySnIFyBUH7lIk6PxvQ== rgba-regex@^1.0.0: version "1.0.0" @@ -11186,7 +10916,7 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.4.0: +run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== @@ -11203,6 +10933,18 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= + rxjs@^6.3.3, rxjs@^6.6.0: version "6.6.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" @@ -11405,7 +11147,7 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-error@^7.0.0, serialize-error@^7.0.1: +serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw== @@ -11745,16 +11487,17 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" -spectron@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/spectron/-/spectron-11.1.0.tgz#ee4f11c9057f6d79094f2d444eba555ccbe63965" - integrity sha512-gL5mQZrh2Afv5vfUX7Llf61NI9zzS139BP0vivNU9kbl92O1AoGk7KwOEg+Cf6Pb2/G/s/81wYWqo/WOhYi6jQ== +spectron@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/spectron/-/spectron-11.0.0.tgz#79d785e6b8898638e77b5186711e3910ed4ca09b" + integrity sha512-YRiB0TTpJa8ofNML/k1fJShe+m7U/E2HnFZsdZK57ekWIzlTHF+Lq7ZvuKGxMbpooU/OZkLObZfitemxhBVH4w== dependencies: + "@types/webdriverio" "^4.8.0" dev-null "^0.1.1" electron-chromedriver "^9.0.0" request "^2.87.0" split "^1.0.0" - webdriverio "^6.1.20" + webdriverio "^4.13.0" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -11948,7 +11691,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -12132,6 +11875,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@~5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.0.1.tgz#1c5331f22250c84202805b2f17adf16699f3a39a" + integrity sha512-7FQGOlSQ+AQxBNXJpVDj8efTA/FtyB5wcNE1omXXJ0cq6jm1jjDwuROlYDbnzHqdNPqliWFhcioCWSyav+xBnA== + dependencies: + has-flag "^2.0.0" + svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" @@ -12181,26 +11931,18 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar-fs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.0.tgz#d1cdd121ab465ee0eb9ccde2d35049d3f3daf0d5" - integrity sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg== +tar-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.0.0" - -tar-stream@^2.0.0, tar-stream@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa" - integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw== - dependencies: - bl "^4.0.3" - end-of-stream "^1.4.1" + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" fs-constants "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.1.1" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" tar@^2.0.0: version "2.2.2" @@ -12368,7 +12110,7 @@ through2@^2.0.0, through2@~2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through@2, through@^2.3.6, through@^2.3.8: +through@2, through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -12407,6 +12149,11 @@ to-arraybuffer@^1.0.0: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -12666,11 +12413,6 @@ typescript@~3.9.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== -ua-parser-js@^0.7.21: - version "0.7.22" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.22.tgz#960df60a5f911ea8f1c818f3747b99c6e177eae3" - integrity sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q== - uglify-js@3.4.x: version "3.4.10" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" @@ -12679,14 +12421,6 @@ uglify-js@3.4.x: commander "~2.19.0" source-map "~0.6.1" -unbzip2-stream@^1.3.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -12877,7 +12611,7 @@ url-parse@^1.4.3: querystringify "^2.1.1" requires-port "^1.0.0" -url@^0.11.0: +url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= @@ -12994,7 +12728,7 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -vue-cli-plugin-electron-builder@~2.0.0-rc.4: +vue-cli-plugin-electron-builder@~2.0.0-rc.6: version "2.0.0-rc.6" resolved "https://registry.yarnpkg.com/vue-cli-plugin-electron-builder/-/vue-cli-plugin-electron-builder-2.0.0-rc.6.tgz#2c0df46167ef50c71923cf47836bb7e4f6685c29" integrity sha512-VDpPwdGZ5qoEZe5DuPmyvDB8Ip/CyarpA9cWnEWNJcZ/2NajnglirMCa6cbLrwt9vsv6HFa28IsmVtaVu4dFqw== @@ -13172,51 +12906,38 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -webdriver@6.7.1: - version "6.7.1" - resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-6.7.1.tgz#5333eb4094c719b6ad16246012b30c51dfed5f30" - integrity sha512-WaOq/fvQrsRkPK0Fs6utC9FNVc8llm74QLLaYiMzotKR/BKug4R0Z7JIJ65zY/PYNQj2a6px389LYdHQnPJOtQ== - dependencies: - "@types/lodash.merge" "^4.6.6" - "@wdio/config" "6.6.3" - "@wdio/logger" "6.6.0" - "@wdio/protocols" "6.6.0" - "@wdio/utils" "6.7.0" - got "^11.0.2" - lodash.merge "^4.6.1" +wdio-dot-reporter@~0.0.8: + version "0.0.10" + resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.10.tgz#facfb7c9c5984149951f59cbc3cd0752101cf0e0" + integrity sha512-A0TCk2JdZEn3M1DSG9YYbNRcGdx/YRw19lTiRpgwzH4qqWkO/oRDZRmi3Snn4L2j54KKTfPalBhlOtc8fojVgg== -webdriverio@^6.1.20: - version "6.7.2" - resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-6.7.2.tgz#60715ebc4b621f999da42fc1e80957fc3fee76f7" - integrity sha512-+ZHkwYTV6G/8+osxq4mUUHqplaOviQ4XpTRfO5RRMXEV3RfMhoC1Fxkr772JFqrtQZ/iY2b90ZyZxfSjZrbrzw== +webdriverio@^4.13.0: + version "4.14.4" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.14.4.tgz#f7a94e9a6530819796088f42b009833d83de0386" + integrity sha512-Knp2vzuzP5c5ybgLu+zTwy/l1Gh0bRP4zAr8NWcrStbuomm9Krn9oRF0rZucT6AyORpXinETzmeowFwIoo7mNA== dependencies: - "@types/archiver" "^3.1.1" - "@types/atob" "^2.1.2" - "@types/fs-extra" "^9.0.2" - "@types/lodash.clonedeep" "^4.5.6" - "@types/lodash.isplainobject" "^4.0.6" - "@types/puppeteer-core" "^2.0.0" - "@wdio/config" "6.6.3" - "@wdio/logger" "6.6.0" - "@wdio/repl" "6.7.1" - "@wdio/utils" "6.7.0" - archiver "^5.0.0" - atob "^2.1.2" - css-value "^0.0.1" - devtools "6.7.0" - fs-extra "^9.0.1" - get-port "^5.1.1" + archiver "~2.1.0" + babel-runtime "^6.26.0" + css-parse "^2.0.0" + css-value "~0.0.1" + deepmerge "~2.0.1" + ejs "~2.5.6" + gaze "~1.1.2" + glob "~7.1.1" grapheme-splitter "^1.0.2" - lodash.clonedeep "^4.5.0" - lodash.isobject "^3.0.2" - lodash.isplainobject "^4.0.6" - lodash.zip "^4.2.0" - minimatch "^3.0.4" - puppeteer-core "^5.1.0" - resq "^1.9.1" - rgb2hex "^0.2.0" - serialize-error "^7.0.0" - webdriver "6.7.1" + inquirer "~3.3.0" + json-stringify-safe "~5.0.1" + mkdirp "~0.5.1" + npm-install-package "~2.1.0" + optimist "~0.6.1" + q "~1.5.0" + request "^2.83.0" + rgb2hex "^0.1.9" + safe-buffer "~5.1.1" + supports-color "~5.0.0" + url "~0.11.0" + wdio-dot-reporter "~0.0.8" + wgxpath "~1.0.0" webidl-conversions@^4.0.2: version "4.0.2" @@ -13373,6 +13094,11 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +wgxpath@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690" + integrity sha1-7vikudVYzEla06mit1FZfs2a9pA= + whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" @@ -13441,6 +13167,11 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + worker-farm@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" @@ -13535,7 +13266,7 @@ ws@^6.0.0, ws@^6.2.1: dependencies: async-limiter "~1.0.0" -ws@^7.0.0, ws@^7.2.3, ws@^7.3.1: +ws@^7.0.0, ws@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== @@ -13687,11 +13418,12 @@ yorkie@^2.0.0: normalize-path "^1.0.0" strip-indent "^2.0.0" -zip-stream@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.0.2.tgz#3a20f1bd7729c2b59fd4efa04df5eb7a5a217d2e" - integrity sha512-TGxB2g+1ur6MHkvM644DuZr8Uzyz0k0OYWtS3YlpfWBEmK4woaC2t3+pozEL3dBfIPmpgmClR5B2QRcMgGt22g== +zip-stream@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" + integrity sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ= dependencies: - archiver-utils "^2.1.0" - compress-commons "^4.0.0" - readable-stream "^3.6.0" + archiver-utils "^1.3.0" + compress-commons "^1.2.0" + lodash "^4.8.0" + readable-stream "^2.0.0" From 0eb6c654d95fcf21cd0ba9998cff4645980adabc Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 14:52:41 -0500 Subject: [PATCH 17/66] cicd --- .gitlab-ci.yml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4d77815..ca677b1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ build: - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env - - yarn electron:build --macos dmg + - yarn electron:build --macos dmg # specify platform artifacts: reports: dotenv: variables.env diff --git a/README.md b/README.md index 6fb4b27..c13a8ab 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ yarn install ### Compiles and hot-reloads for development ``` -yarn dev +yarn electron:serve ``` ### Compiles and minifies for production @@ -15,7 +15,7 @@ yarn dev yarn electron:build ``` -### Run your unit tests + ### Customize configuration See [Configuration Reference](https://cli.vuejs.org/config/). From 9a849474bd425d390aba6c11aada2e66ccca395f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 19:42:12 -0500 Subject: [PATCH 18/66] cicd --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ca677b1..3661985 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,8 @@ build: - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env - - yarn electron:build --macos dmg # specify platform + - export + - yarn electron:build --macos dmg artifacts: reports: dotenv: variables.env From ab8765697ad772f5117fd007280878b360d170a7 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 13 Apr 2021 19:44:10 -0500 Subject: [PATCH 19/66] cicd --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3661985..4d77815 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,6 @@ build: - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env - - export - yarn electron:build --macos dmg artifacts: reports: From 7bd806cc9210387605055297c3c1c0f8f81820b3 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 07:39:31 -0500 Subject: [PATCH 20/66] cicd --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a0f7a5e..2507439 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.1", + "version": "0.9.2", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { From 6dc4d568184e909e9f29418ac297b48789ed5984 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 07:40:08 -0500 Subject: [PATCH 21/66] cicd --- .gitlab-ci.yml | 60 -------------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 4d77815..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,60 +0,0 @@ -stages: - - Build - - Upload - - Release - -build: - stage: Build - image: electronuserland/builder - before_script: - - yarn - script: - - export VERSION=$(node -e "console.log(require('./package.json').version)") - - echo "VERSION=$VERSION" >> variables.env - - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - - echo "APPNAME=$APPNAME" >> variables.env - - yarn electron:build --macos dmg - artifacts: - reports: - dotenv: variables.env - name: $CI_COMMIT_REF_SLUG - paths: - - $CI_PROJECT_DIR/dist_electron/*.* - when: on_success - only: - - main - -variables: - PACKAGE: '${APPNAME}-${VERSION}.dmg' - PACKAGE_REGISTRY_URL: '${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${APPNAME}/${VERSION}' - -upload: - stage: Upload - needs: - - job: build - artifacts: true - rules: - - if: $CI_COMMIT_TAG - when: never # Do not run this job when a tag is created manually - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch - script: - - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist_electron/${PACKAGE}" "${PACKAGE_REGISTRY_URL}/${PACKAGE}"' - -auto-release-master: - image: registry.gitlab.com/gitlab-org/release-cli - needs: - - job: build - artifacts: true - - job: upload - artifacts: true - stage: Release - rules: - - if: $CI_COMMIT_TAG - when: never # Do not run this job when a tag is created manually - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch - script: - - echo "Release $VERSION" - - | - release-cli create --name "Release $VERSION" --tag-name v$VERSION \ - --description 'Created using the release-cli. $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ - --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE}\"}" From babb85ad7c6bfc48fc86add5bb55b9b18123b7d5 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 08:13:43 -0500 Subject: [PATCH 22/66] cicd --- package.json | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 2507439..ceec30e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.2", + "version": "0.9.3", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { @@ -71,15 +71,12 @@ "electronBuilder": { "preload": "src/preload.ts", "builderOptions": { - "mac": { - "target": "dmg" - }, "appId": "com.crimata.${name}", "productName": "Crimata Messenger", "artifactName": "${productName}-${version}.${ext}", "publish": { - "provider": "generic", - "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/raw/dist?job=build" + "provider": "github", + "token": "fSCN8xr4EgccV7z1UNaw" } } } From b0587897298c93ea18e1326f877293f3a3d85ca2 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 08:18:49 -0500 Subject: [PATCH 23/66] cicd --- package.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/package.json b/package.json index ceec30e..743457c 100644 --- a/package.json +++ b/package.json @@ -73,11 +73,6 @@ "builderOptions": { "appId": "com.crimata.${name}", "productName": "Crimata Messenger", - "artifactName": "${productName}-${version}.${ext}", - "publish": { - "provider": "github", - "token": "fSCN8xr4EgccV7z1UNaw" - } } } } From 216290dd52a1d0cd2d1978185929614d9aad302f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 13:22:53 -0500 Subject: [PATCH 24/66] cicd --- .gitlab-ci.yml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 +---- 2 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..0043baf --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,60 @@ +stages: + - Build + - Upload + - Release + +build: + stage: Build + image: osx_11 + before_script: + - yarn + script: + - export VERSION=$(node -e "console.log(require('./package.json').version)") + - echo "VERSION=$VERSION" >> variables.env + - export APPNAME=$(node -e "console.log(require('./package.json').productName)") + - echo "APPNAME=$APPNAME" >> variables.env + - yarn electron:build + artifacts: + reports: + dotenv: variables.env + name: $CI_COMMIT_REF_SLUG + paths: + - $CI_PROJECT_DIR/dist_electron/*.* + when: on_success + only: + - main + +variables: + PACKAGE: '${APPNAME}-${VERSION}.dmg' + PACKAGE_REGISTRY_URL: '${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${APPNAME}/${VERSION}' + +upload: + stage: Upload + needs: + - job: build + artifacts: true + rules: + - if: $CI_COMMIT_TAG + when: never # Do not run this job when a tag is created manually + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch + script: + - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist_electron/${PACKAGE}" "${PACKAGE_REGISTRY_URL}/${PACKAGE}"' + +auto-release-master: + image: registry.gitlab.com/gitlab-org/release-cli + needs: + - job: build + artifacts: true + - job: upload + artifacts: true + stage: Release + rules: + - if: $CI_COMMIT_TAG + when: never # Do not run this job when a tag is created manually + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch + script: + - echo "Release $VERSION" + - | + release-cli create --name "Release $VERSION" --tag-name v$VERSION \ + --description 'Created using the release-cli. $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ + --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE}\"}" diff --git a/package.json b/package.json index 743457c..667bf64 100644 --- a/package.json +++ b/package.json @@ -70,10 +70,6 @@ "pluginOptions": { "electronBuilder": { "preload": "src/preload.ts", - "builderOptions": { - "appId": "com.crimata.${name}", - "productName": "Crimata Messenger", - } } } }, @@ -86,7 +82,7 @@ "git add" ] }, - "productName": "Crimata Messenger", + "productName": "crimata-messenger", "repository": { "type": "git", "url": "https://gitlab.com/crimata/electron-app.git", From 288cfe21001e0c491737ac8ad6831ece7fddd226 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 13:35:16 -0500 Subject: [PATCH 25/66] cicd --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0043baf..c54cd44 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,8 @@ stages: build: stage: Build - image: osx_11 + tags: + - osx_11 before_script: - yarn script: From 7e8ebf72db028edbe41209670eec0423888009af Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 14:59:48 -0500 Subject: [PATCH 26/66] cicd --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c54cd44..d76c2a0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ stages: build: stage: Build tags: - - osx_11 + - darwin before_script: - yarn script: From 0c3be6442c9b175d76dbbef67eb6df5f03b1c9a2 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 15:02:29 -0500 Subject: [PATCH 27/66] cicd --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d76c2a0..6b96f59 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,8 +7,6 @@ build: stage: Build tags: - darwin - before_script: - - yarn script: - export VERSION=$(node -e "console.log(require('./package.json').version)") - echo "VERSION=$VERSION" >> variables.env From 276378b77fbe88ca4bd501ebf7d5e34b3d69fad8 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 15:04:49 -0500 Subject: [PATCH 28/66] cicd --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 667bf64..aaadae8 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "lintOnSave": false, "pluginOptions": { "electronBuilder": { - "preload": "src/preload.ts", + "preload": "src/preload.ts" } } }, From 594011f8cef8f4819799523368a230d837accc7e Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Wed, 14 Apr 2021 15:14:39 -0500 Subject: [PATCH 29/66] cicd --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6b96f59..ebd9da8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,7 @@ build: - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env + - cd ~/Documents/crimata-electron - yarn electron:build artifacts: reports: From e638062021146e3a77789c14cef5735acf0f36cf Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 08:56:16 -0500 Subject: [PATCH 30/66] cicd --- .gitlab-ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ebd9da8..951f12a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,20 +6,22 @@ stages: build: stage: Build tags: + # Use a macos runner to build. - darwin + before_script: + - yarn script: - export VERSION=$(node -e "console.log(require('./package.json').version)") - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env - - cd ~/Documents/crimata-electron - yarn electron:build artifacts: reports: dotenv: variables.env name: $CI_COMMIT_REF_SLUG paths: - - $CI_PROJECT_DIR/dist_electron/*.* + - dist_electron/ when: on_success only: - main @@ -28,6 +30,7 @@ variables: PACKAGE: '${APPNAME}-${VERSION}.dmg' PACKAGE_REGISTRY_URL: '${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/${APPNAME}/${VERSION}' +# Upload package to gitlab registry. upload: stage: Upload needs: @@ -38,6 +41,7 @@ upload: when: never # Do not run this job when a tag is created manually - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: + # Take the package we built and place it in the package registry. - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist_electron/${PACKAGE}" "${PACKAGE_REGISTRY_URL}/${PACKAGE}"' auto-release-master: From ddffe1a40aea105258dc9623a118c844a615c464 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 09:22:08 -0500 Subject: [PATCH 31/66] cicd --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 951f12a..07c36fa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,7 +42,7 @@ upload: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: # Take the package we built and place it in the package registry. - - 'curl --header "JOB-TOKEN: $CI_DEPLOY_PASSWORD" --upload-file "./dist_electron/${PACKAGE}" "${PACKAGE_REGISTRY_URL}/${PACKAGE}"' + - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file "dist_electron/${PACKAGE}" "${PACKAGE_REGISTRY_URL}/${PACKAGE}"' auto-release-master: image: registry.gitlab.com/gitlab-org/release-cli From 6da8bf4b7a355579ac8600506b91a1bc30c8a145 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 10:07:18 -0500 Subject: [PATCH 32/66] cicd --- .gitlab-ci.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 07c36fa..61cb248 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -60,5 +60,5 @@ auto-release-master: - echo "Release $VERSION" - | release-cli create --name "Release $VERSION" --tag-name v$VERSION \ - --description 'Created using the release-cli. $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ + --description Release $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE}\"}" diff --git a/package.json b/package.json index aaadae8..60f4b83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.3", + "version": "0.9.4", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { From a166753c5b21f9ea1e972ae60c7f1c256edd20e0 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 10:33:26 -0500 Subject: [PATCH 33/66] cicd --- .gitlab-ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 61cb248..a03631e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,7 +58,4 @@ auto-release-master: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: - echo "Release $VERSION" - - | - release-cli create --name "Release $VERSION" --tag-name v$VERSION \ - --description Release $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA \ - --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE}\"}" + - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description Release $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA --assets-link '{"name":${APPNAME},"url":"${PACKAGE_REGISTRY_URL}/${PACKAGE}"}' From 72fd4aa6e0febdfcb024f5479865e5ed2b7a24f1 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 10:50:52 -0500 Subject: [PATCH 34/66] cicd --- .gitlab-ci.yml | 2 +- src/background.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a03631e..f03b700 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,4 +58,4 @@ auto-release-master: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: - echo "Release $VERSION" - - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description Release $CI_COMMIT_TITLE' --ref $CI_COMMIT_SHA --assets-link '{"name":${APPNAME},"url":"${PACKAGE_REGISTRY_URL}/${PACKAGE}"}' + - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description Release $CI_COMMIT_TITLE --ref $CI_COMMIT_SHA --assets-link '{"name":${APPNAME},"url":"${PACKAGE_REGISTRY_URL}/${PACKAGE}"}' diff --git a/src/background.ts b/src/background.ts index 77e704c..2f28bb2 100644 --- a/src/background.ts +++ b/src/background.ts @@ -5,7 +5,6 @@ "use strict"; -const log = require("electron-log") const { autoUpdater } = require('electron-updater') import { initApp } from './background/init'; @@ -23,7 +22,14 @@ const isDev = require('electron-is-dev'); (async () => { autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'seMF_apn237iUw8puG9a' } - autoUpdater.logger = log; + + const dialogConfig = { + type: 'info', + buttons: ['Restart', 'Later'], + title: 'Application Update', + message: releaseName, + detail: 'A new version has been downloaded. Restart to update.' + } autoUpdater.on('update-downloaded', () => { autoUpdater.quitAndInstall() From 72b3368b48d5a1f52ba2a607816e80ae07e1777f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 11:29:39 -0500 Subject: [PATCH 35/66] cicd --- .gitlab-ci.yml | 2 +- src/background.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f03b700..4a8dbe8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,4 +58,4 @@ auto-release-master: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: - echo "Release $VERSION" - - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description Release $CI_COMMIT_TITLE --ref $CI_COMMIT_SHA --assets-link '{"name":${APPNAME},"url":"${PACKAGE_REGISTRY_URL}/${PACKAGE}"}' + - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description "Release $CI_COMMIT_TITLE" --ref $CI_COMMIT_SHA --assets-link '{"name":${APPNAME},"url":"${PACKAGE_REGISTRY_URL}/${PACKAGE}"}' diff --git a/src/background.ts b/src/background.ts index 2f28bb2..294c0af 100644 --- a/src/background.ts +++ b/src/background.ts @@ -27,12 +27,13 @@ const isDev = require('electron-is-dev'); type: 'info', buttons: ['Restart', 'Later'], title: 'Application Update', - message: releaseName, - detail: 'A new version has been downloaded. Restart to update.' + message: 'A new version has been downloaded. Restart to update.' } autoUpdater.on('update-downloaded', () => { - autoUpdater.quitAndInstall() + dialog.showMessageBox(dialogConfig).then((returnValue) => { + if (returnValue.response === 0) autoUpdater.quitAndInstall() + }) }) autoUpdater.checkForUpdatesAndNotify() From 0ac4a5ba6398de4c9e0173e36494eb838232db9b Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 16:42:33 +0000 Subject: [PATCH 36/66] Update .gitlab-ci.yml --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4a8dbe8..91a9b96 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -58,4 +58,4 @@ auto-release-master: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when when commits are pushed to the default branch script: - echo "Release $VERSION" - - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description "Release $CI_COMMIT_TITLE" --ref $CI_COMMIT_SHA --assets-link '{"name":${APPNAME},"url":"${PACKAGE_REGISTRY_URL}/${PACKAGE}"}' + - release-cli create --name "Release $VERSION" --tag-name v$VERSION --description "Release $CI_COMMIT_TITLE" --ref $CI_COMMIT_SHA --assets-link "{\"name\":\"${APPNAME}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${PACKAGE}\"}" From 0f18d8fca274ef810d77fb14e5847a9d5e5eec2e Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 12:12:41 -0500 Subject: [PATCH 37/66] cicd --- package.json | 2 +- src/background.ts | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 60f4b83..56a7cf8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.4", + "version": "0.9.5", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { diff --git a/src/background.ts b/src/background.ts index 294c0af..1147f86 100644 --- a/src/background.ts +++ b/src/background.ts @@ -30,7 +30,24 @@ const isDev = require('electron-is-dev'); message: 'A new version has been downloaded. Restart to update.' } + autoUpdater.on('checking-for-update', () => { + console.log("Checking for update...") + }) + + autoUpdater.on('update-available', () => { + console.log("Update available.") + }) + + autoUpdater.on('download-progress', function (progress: any) { + console.log(`Downloading update: ${progress.percent}`) + }) + + autoUpdater.on('error', (err: any) => { + console.log(String(err)) + }) + autoUpdater.on('update-downloaded', () => { + console.log("Update downloaded.") dialog.showMessageBox(dialogConfig).then((returnValue) => { if (returnValue.response === 0) autoUpdater.quitAndInstall() }) @@ -40,9 +57,11 @@ const isDev = require('electron-is-dev'); setInterval(() => { autoUpdater.checkForUpdatesAndNotify() - }, 120000) + }, 5000) console.log('Starting Crimata electron app.'); initApp(isDev); })(); + +https://gitlab.com/crimata/electron-app/-/package_files/9495519/download \ No newline at end of file From 36491c589492d368c59dd88993f2f20d77471a14 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 15 Apr 2021 18:55:06 -0500 Subject: [PATCH 38/66] testing autoupdate --- package.json | 2 +- src/background.ts | 46 ++---------------------------------------- src/background/init.ts | 43 ++++++++++++++++++++++++++++++++------- 3 files changed, 39 insertions(+), 52 deletions(-) diff --git a/package.json b/package.json index 56a7cf8..bfd57b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.5", + "version": "0.9.6", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { diff --git a/src/background.ts b/src/background.ts index 1147f86..8fafb4f 100644 --- a/src/background.ts +++ b/src/background.ts @@ -5,10 +5,8 @@ "use strict"; -const { autoUpdater } = require('electron-updater') - import { initApp } from './background/init'; -import { protocol, dialog } from "electron"; +import { protocol } from "electron"; // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([ @@ -21,47 +19,7 @@ const isDev = require('electron-is-dev'); // NOTE Program Begins Here (async () => { - autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'seMF_apn237iUw8puG9a' } - - const dialogConfig = { - type: 'info', - buttons: ['Restart', 'Later'], - title: 'Application Update', - message: 'A new version has been downloaded. Restart to update.' - } - - autoUpdater.on('checking-for-update', () => { - console.log("Checking for update...") - }) - - autoUpdater.on('update-available', () => { - console.log("Update available.") - }) - - autoUpdater.on('download-progress', function (progress: any) { - console.log(`Downloading update: ${progress.percent}`) - }) - - autoUpdater.on('error', (err: any) => { - console.log(String(err)) - }) - - autoUpdater.on('update-downloaded', () => { - console.log("Update downloaded.") - dialog.showMessageBox(dialogConfig).then((returnValue) => { - if (returnValue.response === 0) autoUpdater.quitAndInstall() - }) - }) - - autoUpdater.checkForUpdatesAndNotify() - - setInterval(() => { - autoUpdater.checkForUpdatesAndNotify() - }, 5000) - console.log('Starting Crimata electron app.'); - initApp(isDev); + await initApp(isDev); })(); - -https://gitlab.com/crimata/electron-app/-/package_files/9495519/download \ No newline at end of file diff --git a/src/background/init.ts b/src/background/init.ts index 52e184a..3c24203 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -1,12 +1,11 @@ "use strict"; -import { app } from "electron"; +import { app, dialog } from "electron"; import { createWindow } from './window'; import { initSession } from './session'; import { initAudioIO } from './audio'; import { backgroundMitt } from '@/modules/emitter'; -const { autoUpdater } = require('electron-updater'); let win: boolean; @@ -15,6 +14,30 @@ backgroundMitt.on('window-active', (state: boolean) => { win = state; }); +// Auto updating. +const { autoUpdater } = require('electron-updater') +autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'seMF_apn237iUw8puG9a' } + +autoUpdater.on('update-available', (info: any) => { + console.log(`Update available: ${info.version}`) +}) + +autoUpdater.on('update-downloaded', (info: any) => { + + const updateDialog = { + type: 'info', + buttons: ['Restart', 'Later'], + title: 'Application Update', + message: info.version, + detail: 'A new version has been downloaded. Restart the application to apply the updates.' + } + + dialog.showMessageBox(updateDialog).then((returnValue) => { + if (returnValue.response === 0) autoUpdater.quitAndInstall() + }) + +}) + // Run when electron app is initialized. async function main() { console.log("MAIN:Initializing Electron App.") @@ -35,7 +58,13 @@ export function initApp(dev: boolean): void { // On initial startup. app.on("ready", () => { - main() + + // Check for updates every 2min. + setInterval(() => { + autoUpdater.checkForUpdates() + }, 5000) // 5s for development. + + main() }); // Must keep to ensure app doesn't quit on close. @@ -49,16 +78,16 @@ export function initApp(dev: boolean): void { // When user clicks app icon (re-open) app.on("activate", () => { - if (!win) { - createWindow(); - } + if (!win) { + createWindow(); + } }); // Exit cleanly on request from parent process in development mode. if (dev) { process.on("SIGTERM", () => { - app.quit(); + app.quit(); }); } } From 17bcda5906a39f3a34bd4a0d52dea3f880847289 Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Fri, 16 Apr 2021 09:46:29 -0400 Subject: [PATCH 39/66] rename dev and build scripts --- .gitlab-ci.yml | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 91a9b96..01b0f33 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ build: - echo "VERSION=$VERSION" >> variables.env - export APPNAME=$(node -e "console.log(require('./package.json').productName)") - echo "APPNAME=$APPNAME" >> variables.env - - yarn electron:build + - yarn build artifacts: reports: dotenv: variables.env diff --git a/package.json b/package.json index bfd57b4..058bcb6 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "name": "Enrique Hernandez" }, "scripts": { - "electron:build": "vue-cli-service electron:build", - "electron:serve": "vue-cli-service electron:serve", + "build": "vue-cli-service electron:build", + "dev": "vue-cli-service electron:serve", "postinstall": "electron-builder install-app-deps", "postuninstall": "electron-builder install-app-deps" }, From ff5db54ac14a215d64d369990a9a26b01c862800 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Fri, 16 Apr 2021 12:00:04 -0500 Subject: [PATCH 40/66] debugging auto updater --- package.json | 12 ++++++++++-- src/background/init.ts | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 058bcb6..43ed620 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.6", + "version": "0.9.7", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { @@ -69,7 +69,15 @@ "lintOnSave": false, "pluginOptions": { "electronBuilder": { - "preload": "src/preload.ts" + "preload": "src/preload.ts", + "builderOptions": { + "appId": "com.crimata.ElectronUpdaterApp", + "artifactName": "${productName}-${version}.${ext}", + "publish": { + "provider": "generic", + "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/dist_electron?job=build" + } + } } } }, diff --git a/src/background/init.ts b/src/background/init.ts index 3c24203..b4f1240 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -16,7 +16,7 @@ backgroundMitt.on('window-active', (state: boolean) => { // Auto updating. const { autoUpdater } = require('electron-updater') -autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'seMF_apn237iUw8puG9a' } +autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'mvvgWYwWnot4bisiQMh_' } autoUpdater.on('update-available', (info: any) => { console.log(`Update available: ${info.version}`) From 3bcf1b594d4bde3e8aa8c54918c3758d5524e50e Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Fri, 16 Apr 2021 12:33:25 -0500 Subject: [PATCH 41/66] lightening build atrifacts --- .gitlab-ci.yml | 3 ++- package.json | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 01b0f33..a3d417a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,8 @@ build: dotenv: variables.env name: $CI_COMMIT_REF_SLUG paths: - - dist_electron/ + - dist_electron/*.dmg + - dist_electron/*.yml when: on_success only: - main diff --git a/package.json b/package.json index 43ed620..7cd9285 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.7", + "version": "0.9.6", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { @@ -75,7 +75,7 @@ "artifactName": "${productName}-${version}.${ext}", "publish": { "provider": "generic", - "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/master/dist_electron?job=build" + "url": "https://gitlab.com/api/v4/projects/25637892/jobs/artifacts/main/raw/dist_electron?job=build" } } } From ce0e7af363ef757d909f997c5620b1e836e62ebe Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Fri, 16 Apr 2021 12:57:34 -0500 Subject: [PATCH 42/66] lightening build atrifacts --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7cd9285..916d2c5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.6", + "version": "0.9.7", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { From 451e0380ac5274ca4b1f32f025d973292a81de2f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Fri, 16 Apr 2021 13:42:46 -0500 Subject: [PATCH 43/66] testing auto update --- .gitlab-ci.yml | 1 + package.json | 2 +- src/background/init.ts | 7 +------ 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a3d417a..2c0d22c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,6 +22,7 @@ build: name: $CI_COMMIT_REF_SLUG paths: - dist_electron/*.dmg + - dist_electron/*.zip - dist_electron/*.yml when: on_success only: diff --git a/package.json b/package.json index 916d2c5..961035f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.7", + "version": "0.9.8", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { diff --git a/src/background/init.ts b/src/background/init.ts index b4f1240..715228a 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -58,12 +58,7 @@ export function initApp(dev: boolean): void { // On initial startup. app.on("ready", () => { - - // Check for updates every 2min. - setInterval(() => { - autoUpdater.checkForUpdates() - }, 5000) // 5s for development. - + autoUpdater.checkForUpdates() main() }); From aab9ae136d001c514e8fa22fedf9e81d4a58e1de Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Sat, 17 Apr 2021 12:57:22 -0400 Subject: [PATCH 44/66] add userData config path to helper functions --- src/background/helpers.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/background/helpers.ts b/src/background/helpers.ts index bd3d279..f0074fb 100644 --- a/src/background/helpers.ts +++ b/src/background/helpers.ts @@ -1,7 +1,9 @@ import fs from 'fs'; import { backgroundMitt } from "@/modules/emitter"; import { SessionState, WindowState } from "@/types"; +import { app } from "electron"; +const configPath = app.getPath("userData"); export const ipcEmit = (channel: string, payload: any) => { backgroundMitt.emit('ipc-renderer', { @@ -14,7 +16,7 @@ export const loadState = (fileName: string): SessionState => { let state: SessionState; try { - state = JSON.parse(fs.readFileSync(fileName).toString()); + state = JSON.parse(fs.readFileSync(configPath + fileName).toString()); } catch (error) { @@ -32,7 +34,7 @@ export const loadWinState = (fileName: string): WindowState => { let state: WindowState; try { - state = JSON.parse(fs.readFileSync(fileName).toString()); + state = JSON.parse(fs.readFileSync(configPath + fileName).toString()); } catch (error) { @@ -51,7 +53,7 @@ export const loadWinState = (fileName: string): WindowState => { // Save session or window state. export const saveToJson = (fileName: string, data: any) => { - fs.writeFile(fileName, JSON.stringify(data), (err) => { + fs.writeFile(configPath + fileName, JSON.stringify(data), (err) => { if (err) { console.log("Error when saving to json.") } From 7c2f3cad8cfcecdb98cdb2d6e5e6fb3bae5f0de6 Mon Sep 17 00:00:00 2001 From: riqo Date: Mon, 26 Apr 2021 07:22:38 -0500 Subject: [PATCH 45/66] fix audio stream shutdown --- src/background/audio.ts | 33 +++++++++++++++++++++------------ src/background/init.ts | 5 +++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/background/audio.ts b/src/background/audio.ts index 6dd3bdd..0a98206 100644 --- a/src/background/audio.ts +++ b/src/background/audio.ts @@ -40,7 +40,7 @@ const onRecordingEnd = async (_event: any, payload: any) => { try { resolve(audioContainer.input); - record = false; + record = false; } catch (e) { reject() } @@ -120,7 +120,7 @@ export function play(input: string): void { // Format the audio. const audio = bufSplit( - Buffer.from(input as string, 'hex'), + Buffer.from(input as string, 'hex'), 8192 ); @@ -165,15 +165,24 @@ export function play(input: string): void { // ------------------------------------------------------------- // Get's called on window close. -// export function stopStream() { -// console.log("AUDIO:Stopping audio stream.") -// if (ai) { -// ai.quit() -// } -// if (ao) { -// ao.quit() -// } -// console.log("AUDIO:Audio closed.") -// } +export async function stopStream() { + console.log("AUDIO:Stopping audio stream.") + if (ai) { + try { + await ai.quit() + } catch(e){ + console.log('AUDIO: Failed to shutdown audio input.'); + throw e; + } + } + if (ao) { + try { + await ao.quit() + } catch(e){ + console.log('AUDIO: Failed to shutdown audio output.'); + throw e; + } + } +} diff --git a/src/background/init.ts b/src/background/init.ts index 715228a..a17716c 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -4,7 +4,7 @@ import { app, dialog } from "electron"; import { createWindow } from './window'; import { initSession } from './session'; -import { initAudioIO } from './audio'; +import { initAudioIO, stopStream } from './audio'; import { backgroundMitt } from '@/modules/emitter'; let win: boolean; @@ -63,7 +63,8 @@ export function initApp(dev: boolean): void { }); // Must keep to ensure app doesn't quit on close. - app.on("before-quit", () => { + app.on("before-quit", async () => { + await stopStream(); }); // Must keep to ensure app doesn't quit on close. From 730cb4b31a7706300673e5b9ee9dab1eabc6e9b0 Mon Sep 17 00:00:00 2001 From: riqo Date: Mon, 26 Apr 2021 07:44:43 -0500 Subject: [PATCH 46/66] fix transparent logout button --- src/components/settings.vue | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/settings.vue b/src/components/settings.vue index a70b797..51347b2 100644 --- a/src/components/settings.vue +++ b/src/components/settings.vue @@ -1,8 +1,8 @@ @@ -27,7 +29,7 @@ import { defineComponent, ref } from "vue"; import { useIpc } from "@/modules/ipc"; - import { logoutRequest } from '@/modules/message'; + import { logoutRequest } from '@/modules/message'; export default defineComponent({ name: "Settings", @@ -58,7 +60,7 @@ } return { - onActive, + onActive, toggleSettings, onLogout } @@ -141,6 +143,11 @@ border: none; outline: none; text-decoration: none; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: 5; } .settingsOption:hover { From 6db693f9d3fd8abbe0f8c81b939c13ad63e99b95 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Thu, 20 May 2021 19:21:39 -0500 Subject: [PATCH 47/66] changing ip addr --- src/modules/websockets.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/websockets.ts b/src/modules/websockets.ts index 9af0448..12ce9f3 100644 --- a/src/modules/websockets.ts +++ b/src/modules/websockets.ts @@ -53,7 +53,7 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC } const createSocket = () => { - socket = new WebSocket(`ws://127.0.0.1:8760`) + socket = new WebSocket(`ws://crimata.com:8760`) // Add listeners. socket.addEventListener("open", onOpen) From 69dc3177eef5103c406141c46706175c19bbe0e7 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Fri, 21 May 2021 14:34:04 -0500 Subject: [PATCH 48/66] automating devops --- package.json | 2 +- src/background/init.ts | 8 ++++---- src/background/session.ts | 6 ++++-- src/modules/websockets.ts | 5 +++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 961035f..04f3603 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "Crimata", - "version": "0.9.8", + "version": "0.9.9", "private": true, "description": "Cross-platform messenger application built with electron, vue3, and TS.", "author": { diff --git a/src/background/init.ts b/src/background/init.ts index 715228a..22f0cbe 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -39,14 +39,14 @@ autoUpdater.on('update-downloaded', (info: any) => { }) // Run when electron app is initialized. -async function main() { +async function main(dev: boolean) { console.log("MAIN:Initializing Electron App.") // Must wait til window is created. await createWindow(); // Instantiate socket session with crimata-platorm. - initSession(); + initSession(dev); // Begin audio stream. initAudioIO(); @@ -58,8 +58,8 @@ export function initApp(dev: boolean): void { // On initial startup. app.on("ready", () => { - autoUpdater.checkForUpdates() - main() + if (!dev) autoUpdater.checkForUpdates() + main(dev) }); // Must keep to ensure app doesn't quit on close. diff --git a/src/background/session.ts b/src/background/session.ts index 35773c8..89a8802 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -137,7 +137,7 @@ const onClientMessage = (_event: IpcMainEvent, payload: any) => { } // Call this to initialize session with Crimata servers. -export const initSession = () => { +export const initSession = (dev: boolean) => { console.log("SESS:Creating new session.") // Load Json or createState. @@ -148,7 +148,9 @@ export const initSession = () => { ` new: ${state.newMessages}`) // Open socket connection. - createSocket() + let url = "ws://crimata.com:8760"; + if (dev) url = "ws://localhost:8760"; + createSocket(url) // Attack browser window init listener. ipcMain.removeAllListeners("app-mounted") diff --git a/src/modules/websockets.ts b/src/modules/websockets.ts index 12ce9f3..c75fc11 100644 --- a/src/modules/websockets.ts +++ b/src/modules/websockets.ts @@ -52,8 +52,9 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC setTimeout(createSocket, 1000) } - const createSocket = () => { - socket = new WebSocket(`ws://crimata.com:8760`) + const createSocket = (url: string) => { + + socket = new WebSocket(url) // Add listeners. socket.addEventListener("open", onOpen) From ddb2f4df0fdb7f1b5b33c808c3025db736eff1dd Mon Sep 17 00:00:00 2001 From: riqo Date: Sat, 22 May 2021 15:02:49 -0500 Subject: [PATCH 49/66] refactor main and rendered ipc --- .env | 4 + .gitignore | 1 + package.json | 4 + src/App.vue | 55 ++++++--- src/api/account.ts | 36 ++++++ src/background.ts | 1 + src/background/audio.ts | 32 ++---- src/background/init.ts | 25 ++-- src/background/ipc/account.ts | 117 +++++++++++++++++++ src/background/ipc/audio.ts | 40 +++++++ src/background/ipc/index.ts | 17 +++ src/background/ipc/session.ts | 62 ++++++++++ src/background/session.ts | 132 ++++++---------------- src/background/store.ts | 16 +++ src/{modules => background}/websockets.ts | 35 ++++-- src/background/window.ts | 4 - src/components/controllers/audioCtrl.ts | 33 +++--- src/components/controllers/textCtrl.ts | 26 +++-- src/components/login.vue | 23 +++- src/components/messenger.vue | 15 ++- src/components/settings.vue | 20 +++- src/ipcRend/account.ts | 27 +++++ src/ipcRend/audio.ts | 15 +++ src/ipcRend/session.ts | 21 ++++ src/modules/auth.ts | 23 ++++ src/modules/http.ts | 54 +++++++++ src/types.ts | 10 +- yarn.lock | 123 +++++++++++++++++++- 28 files changed, 759 insertions(+), 212 deletions(-) create mode 100644 .env create mode 100644 src/api/account.ts create mode 100644 src/background/ipc/account.ts create mode 100644 src/background/ipc/audio.ts create mode 100644 src/background/ipc/index.ts create mode 100644 src/background/ipc/session.ts create mode 100644 src/background/store.ts rename src/{modules => background}/websockets.ts (64%) create mode 100644 src/ipcRend/account.ts create mode 100644 src/ipcRend/audio.ts create mode 100644 src/ipcRend/session.ts create mode 100644 src/modules/auth.ts create mode 100644 src/modules/http.ts diff --git a/.env b/.env new file mode 100644 index 0000000..6aa5026 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ + +BUSINESS_URL="http://localhost:3000" + +PLATFORM_URL="ws://127.0.0.1:8760" diff --git a/.gitignore b/.gitignore index 46762a2..20128fc 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ crash.log # local env files .env.local .env.*.local +.env # Log files npm-debug.log* diff --git a/package.json b/package.json index 04f3603..38c1348 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,11 @@ "@types/uuid": "^8.3.0", "@types/ws": "^7.2.7", "animejs": "^3.2.0", + "axios": "^0.21.1", "core-js": "^3.6.5", + "dotenv": "^10.0.0", "electron-is-dev": "^2.0.0", + "electron-store": "^8.0.0", "electron-updater": "^4.3.8", "mitt": "^2.1.0", "naudiodon": "^2.3.2", @@ -36,6 +39,7 @@ "ws": "^7.3.1" }, "devDependencies": { + "@types/axios": "^0.14.0", "@types/electron-devtools-installer": "^2.2.0", "@types/jest": "^24.0.19", "@typescript-eslint/eslint-plugin": "^2.33.0", diff --git a/src/App.vue b/src/App.vue index 320b62f..5a29c17 100644 --- a/src/App.vue +++ b/src/App.vue @@ -35,12 +35,19 @@ import { defineComponent, onMounted, onUnmounted, ref } from "vue"; import { IpcRendererEvent } from "electron"; import { useIpc } from "@/modules/ipc"; +import { useProfile } from "@/modules/auth" +import { invokeProfile } from "@/ipcRend/account"; +import { postInitSession, postMount } from "@/ipcRend/session"; import Splash from "@/components/splash.vue"; import Messenger from "@/components/messenger.vue"; import Login from "@/components/login.vue"; +import { Profile } from "@/types"; + + export default defineComponent({ + components: { Splash, Messenger, @@ -48,39 +55,38 @@ export default defineComponent({ }, setup() { - const { post } = useIpc(); + + const { post, invoke } = useIpc(); + + const { profile, setProfile, clearProfile } = useProfile(); // Whether browser has received user info yet. const ready = ref(false); - // Information about current user. - const profile = ref(false); - // New messages that browser missed while closed. - const newMessages = ref([]) + const newMessages = ref([]); // Receive updated information about the session. const updateState = (_event: IpcRendererEvent, payload: any) => { + console.log('YAYAYAYAYA'); console.log("APP:Received updated profile and new messages: \n" + ` profile: ${payload.message.profile}\n` + - ` new: ${payload.message.newMessages}`) + ` new: ${payload.message.newMessages}`); if (payload.message.profile) { - console.log(`APP:Logged-in, showing Messenger View.`) + console.log(`APP:Logged-in, showing Messenger View.`); } else { - console.log(`APP:Logged-out, showing Login View.`) + console.log(`APP:Logged-out, showing Login View.`); } - // Set profile and newMessages. - profile.value = payload.message.profile; newMessages.value = payload.message.newMessages; ready.value = true; } - onMounted(() => { - console.log("APP:mounted.") + onMounted(async () => { + console.log("APP:mounted."); window.ipcRenderer.on("update-state", updateState) window.ipcRenderer.on("update_available", () => { console.log('testing auto update'); @@ -89,18 +95,35 @@ export default defineComponent({ window.ipcRenderer.on("update_downloaded", () => { console.log('testing update download'); }) - post("app-mounted", "") + + postMount(); + + try { + + const profile = await invokeProfile() as Profile; + setProfile(profile); + } catch(e) { + console.log('[AUTH]', e); + clearProfile(); + } finally { + ready.value = true; + if (profile.value.crimataId) { + // start session + postInitSession(profile.value.crimataId); + } + } + }); onUnmounted(() => { - window.ipcRenderer.removeAllListeners("update-state") + window.ipcRenderer.removeAllListeners("update-state"); }) return { ready, - profile, post, - newMessages + newMessages, + profile } } }) diff --git a/src/api/account.ts b/src/api/account.ts new file mode 100644 index 0000000..1d72822 --- /dev/null +++ b/src/api/account.ts @@ -0,0 +1,36 @@ + +import { useHttp } from "@/modules/http"; +import axios from "axios"; + +const { post } = useHttp(); + +export const submit = + async (email: string, password: string) => ( + + await post('/account/login', { + email, + password + }) + +) + + +export const logout = + async (): Promise => (await post('/account/logout')); + + + +export const fetchProfile = async(email: string, token: string) => ( + + await axios({ + url: "http://127.0.0.1:3000/api/account/profile", + headers: { + Cookie: `jwt=${token}` + }, + method: 'GET', + data: { + email, + } + }) +) + diff --git a/src/background.ts b/src/background.ts index 8fafb4f..1ecee83 100644 --- a/src/background.ts +++ b/src/background.ts @@ -7,6 +7,7 @@ import { initApp } from './background/init'; import { protocol } from "electron"; +require('dotenv').config() // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([ diff --git a/src/background/audio.ts b/src/background/audio.ts index 0a98206..fa6efb2 100644 --- a/src/background/audio.ts +++ b/src/background/audio.ts @@ -2,9 +2,7 @@ "use strict"; -import { ipcMain } from "electron"; import { backgroundMitt } from '@/modules/emitter'; - const portAudio = require('naudiodon'); // Audio in and out stream objects. @@ -26,27 +24,22 @@ const audioOptions = { closeOnError: false, } -// Toggles record to true to begin capturing chunks. -const onRecordingStart = (_event: any, _payload: any) => { - console.log("AUDIO: Beginning audio capture.") - record = true; -} +export const toggleRecord = (): void => { record = !record }; -// Returns recorded audio to frontend and sets record to false. -const onRecordingEnd = async (_event: any, payload: any) => { - console.log("AUDIO:Sending audio to browser.") - return new Promise((resolve, reject) => { +export const fetchAudioInput = (): Promise => ( + + new Promise((resolve, reject) => { try { resolve(audioContainer.input); - record = false; + toggleRecord(); } catch (e) { - reject() + reject(new Error('Failed to fetch the audio.')) } - }); -}; + }) +) // Main audio function run by run.ts module. @@ -86,15 +79,6 @@ export function initAudioIO(): void { ao.start(); } - - // Listen to record. - console.log("AUDIO:Adding recording listeners.") - - ipcMain.removeAllListeners("start-recording"); - ipcMain.on("start-recording", onRecordingStart); - - ipcMain.removeHandler("stop-recording"); - ipcMain.handle("stop-recording", onRecordingEnd); } diff --git a/src/background/init.ts b/src/background/init.ts index f251246..1f47214 100644 --- a/src/background/init.ts +++ b/src/background/init.ts @@ -3,9 +3,10 @@ import { app, dialog } from "electron"; import { createWindow } from './window'; -import { initSession } from './session'; -import { initAudioIO, stopStream } from './audio'; +import { stopStream } from './audio'; import { backgroundMitt } from '@/modules/emitter'; +import useIpc from "@/background/ipc/index"; +const { autoUpdater } = require('electron-updater'); let win: boolean; @@ -15,7 +16,6 @@ backgroundMitt.on('window-active', (state: boolean) => { }); // Auto updating. -const { autoUpdater } = require('electron-updater') autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'mvvgWYwWnot4bisiQMh_' } autoUpdater.on('update-available', (info: any) => { @@ -38,19 +38,18 @@ autoUpdater.on('update-downloaded', (info: any) => { }) + + // Run when electron app is initialized. -async function main(dev: boolean) { - console.log("MAIN:Initializing Electron App.") +async function main(): Promise { + + console.log("MAIN:Initializing Electron App."); + + useIpc(); // Must wait til window is created. await createWindow(); - // Instantiate socket session with crimata-platorm. - initSession(dev); - - // Begin audio stream. - initAudioIO(); - } // Root function of app. @@ -58,8 +57,8 @@ export function initApp(dev: boolean): void { // On initial startup. app.on("ready", () => { - if (!dev) autoUpdater.checkForUpdates() - main(dev) + // autoUpdater.checkForUpdates() + main(); }); // Must keep to ensure app doesn't quit on close. diff --git a/src/background/ipc/account.ts b/src/background/ipc/account.ts new file mode 100644 index 0000000..c336ac3 --- /dev/null +++ b/src/background/ipc/account.ts @@ -0,0 +1,117 @@ + +"use strict"; + +import { Profile } from "@/types"; +import { submit, fetchProfile, logout } from "@/api/account"; +import { ipcMain, IpcMainInvokeEvent } from "electron"; +import { store } from "@/background/store"; + + +const parseAuthRes = (authRes: any) => { + const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string; + const profile = authRes.data as Profile; + return { + token, + profile + } +}; + + +const onProfile = async ( + _event: IpcMainInvokeEvent, + _payload: null +): Promise => ( + + new Promise(async (resolve, reject) => { + console.log('[IPC]: user-profile'); + + // get jwt token and crimataId from store + const token = store.get('key'); + const crimataId = store.get('crimataId'); + + // authenticate and fetch profile + try { + + const res = await fetchProfile( + crimataId, + token + ); + + const parsed = parseAuthRes(res); + resolve(parsed.profile); + + } catch(e) { + reject(new Error('Failed to fetch profile.')); + } + }) +) + + +const onLogin = async ( + _event: IpcMainInvokeEvent, + payload: string +): Promise => ( + + new Promise(async (resolve, reject) => { + console.log('[IPC]: user-login'); + + const account = JSON.parse(payload); + + if ( account.password && account.email ) { + try { + const res = await submit(account.email, account.password); + const parsed = parseAuthRes(res); + + // save jwt token and profile + store.set('key', parsed.token); + store.set('crimataId', parsed.profile.crimataId); + + // return profile to renderer + resolve(parsed.profile); + + } catch(e) { + console.log('[API]', e.response); + reject(new Error('Failed to authenticate')); + } + } + }) +) + +const onLogout = async ( + _event: IpcMainInvokeEvent, + _payload: null +): Promise => ( + + new Promise(async (resolve, reject) => { + console.log('[IPC]: user-logout'); + + try { + // post logout to backend + await logout(); + + // remove key and crimataId + store.delete('key'); + store.delete('crimataId'); + + // TODO: kill crimata platform session + + resolve(); + } catch(e) { + reject(new Error('Failed to logout. Please try again.')); + } + }) +) + + +export default function useAccountListeners(): void { + + ipcMain.removeHandler("user-profile"); + ipcMain.handle("user-profile", onProfile); + + ipcMain.removeHandler("user-login"); + ipcMain.handle("user-login", onLogin); + + ipcMain.removeHandler("user-logout"); + ipcMain.handle("user-logout", onLogout); + +} diff --git a/src/background/ipc/audio.ts b/src/background/ipc/audio.ts new file mode 100644 index 0000000..1419273 --- /dev/null +++ b/src/background/ipc/audio.ts @@ -0,0 +1,40 @@ + +"use strict"; + +import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; +import { fetchAudioInput, toggleRecord } from "@/background/audio"; + + +// Toggles record to true to begin capturing chunks. +const onRecordingStart = ( + _event: IpcMainEvent, + _payload: null +): void => { + + console.log('[IPC]: start-recording'); + + toggleRecord(); +}; + + +// Returns recorded audio to frontend and sets record to false. +const onRecordingStop = async ( + _event: IpcMainInvokeEvent, + _payload: null +): Promise => { + + console.log('[IPC]: stop-recording'); + + return await fetchAudioInput() +}; + + +export default function useAudioListeners(): void { + + ipcMain.removeAllListeners("start-recording"); + ipcMain.on("start-recording", onRecordingStart); + + ipcMain.removeHandler("stop-recording"); + ipcMain.handle("stop-recording", onRecordingStop); + +} diff --git a/src/background/ipc/index.ts b/src/background/ipc/index.ts new file mode 100644 index 0000000..933bda1 --- /dev/null +++ b/src/background/ipc/index.ts @@ -0,0 +1,17 @@ + +"use strict"; + +import useAccountListeners from "./account"; +import useSessionListeners from "./session"; +import useAudioListeners from "./audio"; + + +export default function useIpc(): void { + + useAccountListeners(); + + useSessionListeners(); + + useAudioListeners(); + +} diff --git a/src/background/ipc/session.ts b/src/background/ipc/session.ts new file mode 100644 index 0000000..a2496dc --- /dev/null +++ b/src/background/ipc/session.ts @@ -0,0 +1,62 @@ + +"use strict"; + +import { initSession, emitNewMessages, sendMessage } from '@/background/session'; +import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; +import { initAudioIO } from "@/background/audio"; +import { ClientMessage } from "@/types"; + + +// Instantiate socket session with crimata-platorm. +const onSessionInit = ( + _event: IpcMainInvokeEvent, + cid: string +): void => { + + console.log('[IPC]: init-session'); + + initSession(cid); + + initAudioIO(); +} + + +const onAppMounted = ( + _event: IpcMainInvokeEvent, + _payload: null +): void => { + + console.log('[IPC]: app-mounted'); + + emitNewMessages() +}; + + +// Handle messages from window/client. +const onClientMessage = ( + _event: IpcMainEvent, + payload: ClientMessage +): void => { + + console.log('[IPC]: client-message'); + + sendMessage(payload); +} + + +export default function useSessionListeners(): void { + + console.log('[IPC]: Init session listeners.'); + + // Attach listeners for frontend. + ipcMain.removeAllListeners("client-message"); + ipcMain.on("client-message", onClientMessage); + + // Attack browser window init listener. + ipcMain.removeAllListeners("app-mounted"); + ipcMain.on("app-mounted", onAppMounted); + + ipcMain.removeAllListeners("init-session"); + ipcMain.on("init-session", onSessionInit); + +} diff --git a/src/background/session.ts b/src/background/session.ts index 89a8802..fc3e4fd 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -1,82 +1,35 @@ /* * Creates a websocket session with Crimata Servers. - * - * Connects to Servers and attempts key authentication. Server will respond - * with key and user profile. We send the profile to the browser. We also - * resend this information on new broser window. We then serve as a - * communication interface between the window and the servers. It will + * + * Connects to Servers and attempts key authentication. Server will respond + * with key and user profile. We send the profile to the browser. We also + * resend this information on new broser window. We then serve as a + * communication interface between the window and the servers. It will * automatically try to reconnect on websocket disconnect. */ import { backgroundMitt } from "@/modules/emitter"; -import { ipcEmit, loadState, saveToJson } from './helpers'; -import { ipcMain, IpcMainEvent, IpcMainInvokeEvent } from "electron"; +import { ipcEmit, loadState } from './helpers'; -import useWebSockets from "@/modules/websockets"; +import useWebSockets from "./websockets"; import { play } from "./audio"; import { renderMessage } from "@/modules/message"; -import { AuthProtocol, SessionState, Profile } from "@/types"; +import { SessionState } from "@/types"; let win = true; // Info saved to json on quit (key, newMessages). let state: SessionState; -// Profile of current user. -let profile: Profile | boolean; - -// Called when server sends auth message. -const updateState = (res: AuthProtocol) => { - console.log("SESS:Auth message received: \n" + - ` key: ${res.key}\n` + - ` alias: ${res.profile}`) - - if (state) { - - // Update key. - state.key = res.key; - - // Update the user profile. - profile = res.profile; - - // Send upated profile to frontend. - console.log("SESS:Sending updated user profile to browser.") - ipcEmit("update-state", { - profile: profile, - newMessages: state.newMessages - }) - - // Save the updated state to json. - console.log("SESS:Saving session state.") - saveToJson("session.json", state) - - } - -} - -// Send state on new window. -const onNewBrowserWindow = (_event: IpcMainInvokeEvent, _payload: any) => { - if (typeof profile !== 'undefined') { - console.log("SESS:Sending user profile to browser.") - ipcEmit("update-state", { - profile: profile, - newMessages: state.newMessages - }) - } -} // Calls appropriate endpoint for a server message. -const onMessage = (data: string) => { - let message = JSON.parse(data) - - // AuthProtocol message. - if (message.hasOwnProperty("key")) { - updateState(message) - } +const onMessage = (data: string): void => { + let message = JSON.parse(data); + console.log('received new message', message); // Standard message. - else if (message.content) { + if (message.content) { // Convert to render message message = renderMessage( @@ -93,7 +46,7 @@ const onMessage = (data: string) => { } ipcEmit("render-message", message) } - + else { console.log("SESS:No window: saving message.") state.newMessages.push(message); @@ -108,57 +61,40 @@ const onMessage = (data: string) => { }; -// When socket connects, we update state. -const onOpen = () => { - console.log(`SESS:Sending key: ${state.key}`) - - if (state) { - sendMessage({ - "key": state.key, - "usr": false, - "pwd": false - }) - } -} // Websockets module. -const { createSocket, sendMessage } = useWebSockets(onMessage, onOpen); +const { createSocket, send } = useWebSockets(onMessage); -// Handle messages from window/client. -const onClientMessage = (_event: IpcMainEvent, payload: any) => { - console.log("New client message") - const success = sendMessage(payload) - - if (!success) { - console.log("Unable to send message: ", payload) +export const emitNewMessages = (): void => { + if (state) { + ipcEmit("update-state", { + newMessages: state.newMessages, + }); } - + } + +export const sendMessage = (payload: Record): void => { + try { + send(payload) + } catch(e) { + console.log("Unable to send message: ", payload); + } + +} + + // Call this to initialize session with Crimata servers. -export const initSession = (dev: boolean) => { +export const initSession = (cid: string): void => { console.log("SESS:Creating new session.") // Load Json or createState. - state = loadState("session.json") - - console.log("SESS:State loaded: \n" + - ` key: ${state.key}\n` + - ` new: ${state.newMessages}`) + state = loadState("session.json"); // Open socket connection. - let url = "ws://crimata.com:8760"; - if (dev) url = "ws://localhost:8760"; - createSocket(url) - - // Attack browser window init listener. - ipcMain.removeAllListeners("app-mounted") - ipcMain.on("app-mounted", onNewBrowserWindow); - - // Attach listeners for frontend. - ipcMain.removeAllListeners("client-message") - ipcMain.on("client-message", onClientMessage); + createSocket(); // Keep win up-to-date. backgroundMitt.on('window-active', (state: boolean) => { diff --git a/src/background/store.ts b/src/background/store.ts new file mode 100644 index 0000000..16f8409 --- /dev/null +++ b/src/background/store.ts @@ -0,0 +1,16 @@ + +const Store = require('electron-store'); + +const schema = { + key: { + type: 'string', + }, + crimataId: { + type: 'string' + } +}; + +export const store = new Store({ + schema, + encryptionKey: "super user test" +}); diff --git a/src/modules/websockets.ts b/src/background/websockets.ts similarity index 64% rename from src/modules/websockets.ts rename to src/background/websockets.ts index c75fc11..9fcc5e8 100644 --- a/src/modules/websockets.ts +++ b/src/background/websockets.ts @@ -1,13 +1,16 @@ "use strict"; import WebSocket from 'ws'; -import { ipcMain } from "electron"; let socket: WebSocket; +const socketUrl = process.env.PLATFORM_URL; // Run every time we want to connect to backend. -export default function useWebSockets(receiveCallback: (s: string) => any, openCallback: () => any) { +export default function useWebSockets( + receiveCallback: (s: string) => void, + openCallback?: () => void +) { // Returns bool (sucess or fail). const sendMessage = (data: any) => { @@ -24,11 +27,22 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC } - const onOpen = (event: WebSocket.OpenEvent) => { + const send = async (data: Record): Promise => ( + new Promise((resolve, reject) => { + if (socket.readyState !== 1) { + reject(false); + } + socket.send(JSON.stringify(data)) + resolve(true); + + })) + + + const onOpen = (_event: WebSocket.OpenEvent) => { console.log("WS:Connected to WS Server!"); - openCallback() + if (openCallback) openCallback(); } @@ -40,7 +54,7 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC } - const onClose = (event: WebSocket.CloseEvent) => { + const onClose = (_event: WebSocket.CloseEvent) => { console.log("WS:Socket closed normally.") } @@ -52,9 +66,9 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC setTimeout(createSocket, 1000) } - const createSocket = (url: string) => { - - socket = new WebSocket(url) + const createSocket = () => { + if (socketUrl) + socket = new WebSocket(socketUrl) // Add listeners. socket.addEventListener("open", onOpen) @@ -67,7 +81,8 @@ export default function useWebSockets(receiveCallback: (s: string) => any, openC return { createSocket, - sendMessage + sendMessage, + send } -} \ No newline at end of file +} diff --git a/src/background/window.ts b/src/background/window.ts index e312572..162b3e1 100644 --- a/src/background/window.ts +++ b/src/background/window.ts @@ -57,7 +57,6 @@ const saveWindowState = () => { // Do this on window mount. const onWindowMount = (): void => { - console.log("BW:Adding window listeners. ") // Must tell initApp that window exists. backgroundMitt.emit('window-active', true); @@ -70,12 +69,10 @@ const onWindowMount = (): void => { backgroundMitt.removeAllListeners("ipc-renderer") backgroundMitt.on("ipc-renderer", renderMessage); - console.log("BW:Listeners created.") } // Do this on window dismount (close). const onWindowDismount = (): void => { - console.log("BW:Window closed.") win = null; backgroundMitt.emit('window-active', false); } @@ -89,7 +86,6 @@ export async function createWindow(): Promise { // Load the saved window state. winState = loadWinState("window.json") - console.log(`BW:Creating window [${winState.width}, ${winState.height}].`) // Define the browser window. win = new BrowserWindow({ diff --git a/src/components/controllers/audioCtrl.ts b/src/components/controllers/audioCtrl.ts index c9efaa9..f635c0b 100644 --- a/src/components/controllers/audioCtrl.ts +++ b/src/components/controllers/audioCtrl.ts @@ -4,6 +4,8 @@ import { useIpc } from '@/modules/ipc'; import { onMounted, onUnmounted, ref, Ref } from "vue"; import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; import { renderMessage, clientMessage } from '@/modules/message'; +import { postMessage } from "@/ipcRend/session"; +import { invokeStopRecord } from "@/ipcRend/audio"; function showRecIcon () { @@ -13,7 +15,7 @@ function showRecIcon () { opacity: [0, 0.75], scale: [0.0, 1], duration: 250, - easing: 'linear', + easing: 'linear', }) } @@ -25,7 +27,7 @@ function hideRecIcon () { opacity: [0.75, 0], scale: [1, 0], duration: 250, - easing: 'linear', + easing: 'linear', }) } @@ -50,7 +52,7 @@ export default function useAudioInputController (typing: Ref) { if (cmd == "SPACE" && !recording.value && !typing.value) { console.log("INPT:Starting record.") - post("start-recording", ""); + post("start-recording", null); showRecIcon() recording.value = true; @@ -67,9 +69,9 @@ export default function useAudioInputController (typing: Ref) { // Create a message. const message = renderMessage( - "", - "", - "", + "", + "", + "", "sf" ) @@ -78,14 +80,19 @@ export default function useAudioInputController (typing: Ref) { // Stop recording and get audio from recorder. console.log("INPT:Stopping record.") - const audio = await invoke("stop-recording", ""); - - // Send message to the backend for processing. - const clientM = clientMessage("", audio, message.uid); - post('client-message', clientM); + try { + const audio = await invokeStopRecord() as string; + // Send message to the backend for processing. + const clientM = clientMessage("", audio, message.uid); + postMessage(clientM); + } catch(e) { + console.log('Failed to fetch audio.') + } finally { + hideRecIcon(); + recording.value = false; + } + - hideRecIcon() - recording.value = false; } diff --git a/src/components/controllers/textCtrl.ts b/src/components/controllers/textCtrl.ts index 7a2e2e8..ced8aaf 100644 --- a/src/components/controllers/textCtrl.ts +++ b/src/components/controllers/textCtrl.ts @@ -4,6 +4,8 @@ import { useIpc } from '@/modules/ipc'; import { Ref, ref, watch, onMounted, onUnmounted } from "vue"; import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; import { clientMessage, renderMessage } from '@/modules/message'; +import { postMessage } from "@/ipcRend/session"; + //---Animations----------------------------------------------- @@ -19,7 +21,7 @@ function showTextInput () { translateX: [t1, t2], scale: [0.3, 1], duration: 500, - easing: 'easeOutExpo', + easing: 'easeOutExpo', }) } @@ -33,7 +35,7 @@ function hideTextInput() { translateX: t, scale: 0.3, duration: 500, - easing: 'easeOutExpo', + easing: 'easeOutExpo', }) } @@ -45,7 +47,7 @@ function switchSide(currentSide: string) { targets: '#textInput', translateX: t, duration: 500, - easing: 'easeOutExpo', + easing: 'easeOutExpo', }) } @@ -75,7 +77,7 @@ export default function useTextInputController(elementX: Ref) { textInput.value = ""; textInput.blur(); } - + hideTextInput() firstKey = true; typing.value = false; @@ -87,9 +89,9 @@ export default function useTextInputController(elementX: Ref) { // Create the message. const message = renderMessage( - textInput.value, - false, - "", + textInput.value, + false, + "", "sf" ) @@ -97,7 +99,7 @@ export default function useTextInputController(elementX: Ref) { // Send it to the backend for processing. const clientM = clientMessage(textInput.value, false, message.uid); - post('client-message', clientM); + postMessage(clientM); clearInput() } @@ -115,9 +117,9 @@ export default function useTextInputController(elementX: Ref) { const onKeyDown = (e: KeyboardEvent) => { const key = keyboardNameMap[e.keyCode] - + if (textInput) { - + // Only runs on firstKey. if (firstKey) { @@ -165,7 +167,7 @@ export default function useTextInputController(elementX: Ref) { switchSide(side) side = "left" } - } + } else { if (winW - elementX > 230) { @@ -173,7 +175,7 @@ export default function useTextInputController(elementX: Ref) { side = "right" } } - + }); onMounted(() => { diff --git a/src/components/login.vue b/src/components/login.vue index 521517c..8232a67 100644 --- a/src/components/login.vue +++ b/src/components/login.vue @@ -25,7 +25,7 @@ - + @@ -37,21 +37,34 @@ import { defineComponent, ref } from "vue"; import { useIpc } from "@/modules/ipc"; import { authRequest } from '@/modules/message'; +import { useProfile } from '@/modules/auth'; +import { invokeLogin } from "@/ipcRend/account"; +import { Profile } from "@/types"; export default defineComponent({ name: "Login", setup() { - const { post } = useIpc(); + const { setProfile } = useProfile(); const usr = ref(""); const pwd = ref(""); // Submit login credentials to the backend. - const submitForm = () => { - console.log(`Submitting login form: ${usr.value}, ${pwd.value}`) - post("client-message", authRequest(false, usr.value, pwd.value)) + const submitForm = async () => { + + try { + const profile = await invokeLogin({ + email: usr.value, + password: pwd.value + }) as Profile; + + setProfile(profile); + + } catch(e) { + + } } return { diff --git a/src/components/messenger.vue b/src/components/messenger.vue index edc50a1..f5512a9 100644 --- a/src/components/messenger.vue +++ b/src/components/messenger.vue @@ -6,9 +6,9 @@
-
@@ -48,25 +48,24 @@ export default defineComponent({ // Load the message history. if (crimataId === window.localStorage.getItem("last_usr")) { - prepMessageView(props.newMessages) + prepMessageView(props.newMessages); } else { - messages.value.clear() + messages.value.clear(); } // New content listeners. emitter.on('self-message', (message) => updateMessageView(message)); window.ipcRenderer.on("render-message", (_e: any, payload: any) => { - updateMessageView(payload.message) + updateMessageView(payload.message); }); // Save the usr for next time. - window.localStorage.setItem("last_usr", crimataId) + window.localStorage.setItem("last_usr", crimataId); }); onUnmounted(() => { window.ipcRenderer.removeAllListeners("render-message"); - window.ipcRenderer.removeAllListeners("annotate-message"); emitter.all.clear(); }); diff --git a/src/components/settings.vue b/src/components/settings.vue index 51347b2..7c4b9ce 100644 --- a/src/components/settings.vue +++ b/src/components/settings.vue @@ -30,6 +30,8 @@ import { defineComponent, ref } from "vue"; import { useIpc } from "@/modules/ipc"; import { logoutRequest } from '@/modules/message'; + import { useProfile } from "@/modules/auth" + import { invokeLogout } from "@/ipcRend/account"; export default defineComponent({ name: "Settings", @@ -37,7 +39,9 @@ setup() { const toggleSettings = ref(false); - const { post } = useIpc(); + const { post, invoke } = useIpc(); + + const { clearProfile } = useProfile(); // Listen for escape key to close settings. const onEscape = (e: any) => { @@ -54,9 +58,17 @@ } // We ask server to log us out. - const onLogout = () => { - console.log("Submitting logout request.") - post("client-message", logoutRequest()) + const onLogout = async () => { + + console.log("Submitting logout request."); + + try { + clearProfile(); + await invokeLogout(); + } catch(e) { + console.log('error') + } + } return { diff --git a/src/ipcRend/account.ts b/src/ipcRend/account.ts new file mode 100644 index 0000000..9300aa6 --- /dev/null +++ b/src/ipcRend/account.ts @@ -0,0 +1,27 @@ + +import { useIpc } from "@/modules/ipc"; +import { Profile } from "@/types"; + +const { invoke } = useIpc(); + +interface LoginPayload { + email: string; + password: string; +} + + +export const invokeProfile = async (): Promise => ( + await invoke('user-profile', null) +); + + +export const invokeLogin = async ( + payload: LoginPayload +): Promise => ( + await invoke('user-login', JSON.stringify(payload)) +); + + +export const invokeLogout = async (): Promise => ( + await invoke("user-logout", null) +); diff --git a/src/ipcRend/audio.ts b/src/ipcRend/audio.ts new file mode 100644 index 0000000..6f25d29 --- /dev/null +++ b/src/ipcRend/audio.ts @@ -0,0 +1,15 @@ + +import { useIpc } from "@/modules/ipc"; + + +const { post, invoke } = useIpc(); + + +export const postStartRecord = (): void => ( + post("start-recording", null) +); + + +export const invokeStopRecord = async (): Promise => ( + await invoke("stop-recording", null) +); diff --git a/src/ipcRend/session.ts b/src/ipcRend/session.ts new file mode 100644 index 0000000..966b121 --- /dev/null +++ b/src/ipcRend/session.ts @@ -0,0 +1,21 @@ + +import { useIpc } from "@/modules/ipc"; + +import { ClientMessage } from "@/types"; + +const { post } = useIpc(); + + +export const postMount = (): void => ( + post("app-mounted", null) +); + + +export const postInitSession = (cid: string): void => ( + post("init-session", cid) +); + + +export const postMessage = (payload: ClientMessage): void => ( + post('client-message', payload) +); diff --git a/src/modules/auth.ts b/src/modules/auth.ts new file mode 100644 index 0000000..5fb40c1 --- /dev/null +++ b/src/modules/auth.ts @@ -0,0 +1,23 @@ +import { ref } from "vue"; +import { Profile } from "@/types"; + + +const profile = ref(); + +export const useProfile = () => { + + const setProfile = (payload: Profile) => { + profile.value = payload; + } + + const clearProfile = () => { + profile.value = null; + } + + return { + setProfile, + clearProfile, + profile + } + +} diff --git a/src/modules/http.ts b/src/modules/http.ts new file mode 100644 index 0000000..de241e0 --- /dev/null +++ b/src/modules/http.ts @@ -0,0 +1,54 @@ + +import axios, { AxiosRequestConfig } from 'axios'; + +const preFix = '/api'; + +const baseURL = process.env.BUSSINESS_URL + preFix; + + +interface Request { + endpoint: string; + query?: Record; + config?: Record; +} + + +const makeQuery = (reqQuery: Record) => { + + let result = ''; + + result = '?' + Object.entries(reqQuery) + .map(([ key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&') + + return result; +}; + + +export const useHttp = () => { + + const api = axios.create({ + baseURL, + withCredentials: true, + }); + + + const post = async (endpoint: string, payload?: Record): Promise => ( + await api.post(endpoint, payload) + ) + + + const get = async (req: Request) => { + + if (req.query) { + req.endpoint += makeQuery(req.query); + } + + const res = await api.get(req.endpoint, req.config); + return res; + }; + + return { + get, post + } +} diff --git a/src/types.ts b/src/types.ts index 37b18ac..2e35fc5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,7 +19,7 @@ export interface ClientMessage { } export interface ClientRequest { - intent: string; + intent: string; params: object; epic: string | boolean; confidence: number; @@ -50,8 +50,10 @@ export interface Profile { } export interface AuthProtocol { - key: boolean | string; - profile: boolean | Profile; + token: null | string; + profile: null | Profile; + password?: string; + email?: string; } export interface LogoutRequest { @@ -71,4 +73,4 @@ export interface StandardMessage { }; context: string; modifier: string; -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 8dc3fba..465adc9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1279,6 +1279,13 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/axios@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46" + integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY= + dependencies: + axios "*" + "@types/babel__core@^7.1.0": version "7.1.12" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" @@ -2348,6 +2355,13 @@ ajv-errors@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== +ajv-formats@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.0.tgz#96eaf83e38d32108b66d82a9cb0cfa24886cdfeb" + integrity sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q== + dependencies: + ajv "^8.0.0" + ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -2363,6 +2377,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.2, ajv@^6.12.3, ajv json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.0, ajv@^8.1.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.5.0.tgz#695528274bcb5afc865446aa275484049a18ae4b" + integrity sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -2710,6 +2734,11 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +atomically@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/atomically/-/atomically-1.7.0.tgz#c07a0458432ea6dbc9a3506fffa424b48bccaafe" + integrity sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w== + autoprefixer@^9.8.6: version "9.8.6" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" @@ -2733,6 +2762,13 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@*, axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -3946,6 +3982,22 @@ condense-newlines@^0.2.1: is-whitespace "^0.3.0" kind-of "^3.0.2" +conf@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/conf/-/conf-10.0.1.tgz#038093e5cbddc0e59bc14f63382c4ce732a4781d" + integrity sha512-QClEoNcruwBL84QgMEPHibL3ERxWIrRKhbjJKG1VsFBadm5QpS0jsu4QjY/maxUvhyAKXeyrs+ws+lC6PajnEg== + dependencies: + ajv "^8.1.0" + ajv-formats "^2.0.2" + atomically "^1.7.0" + debounce-fn "^4.0.0" + dot-prop "^6.0.1" + env-paths "^2.2.1" + json-schema-typed "^7.0.3" + onetime "^5.1.2" + pkg-up "^3.1.0" + semver "^7.3.5" + config-chain@^1.1.11, config-chain@^1.1.12: version "1.1.12" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" @@ -4468,6 +4520,13 @@ deasync@^0.1.15: bindings "^1.5.0" node-addon-api "^1.7.1" +debounce-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7" + integrity sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ== + dependencies: + mimic-fn "^3.0.0" + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -4827,11 +4886,23 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" + dotenv-expand@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + dotenv@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" @@ -4985,6 +5056,14 @@ electron-publish@22.9.1: lazy-val "^1.0.4" mime "^2.4.6" +electron-store@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-8.0.0.tgz#81a4e687958e2dae1c5c84cc099a8148be776337" + integrity sha512-ZgRPUZkfrrjWSqxZeaxu7lEvmYf6tgl49dLMqxXGnEmliSiwv3u4rJPG+mH3fBQP9PBqgSh4TCuxHZImMMUgWg== + dependencies: + conf "^10.0.0" + type-fest "^1.0.2" + electron-to-chromium@^1.3.585: version "1.3.589" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.589.tgz#bd26183ed8697dde6ac19acbc16a3bf33b1f8220" @@ -5091,6 +5170,11 @@ env-paths@^2.2.0: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -5871,6 +5955,11 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== +follow-redirects@^1.10.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" + integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -8043,6 +8132,16 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-schema-typed@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz#23ff481b8b4eebcd2ca123b4fa0409e66469a2d9" + integrity sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -8758,6 +8857,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" + integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== + mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -9822,6 +9926,13 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + please-upgrade-node@^3.1.1: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -10765,6 +10876,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -11116,7 +11232,7 @@ semver@^7.2.1, semver@^7.3.2: resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== -semver@^7.3.4: +semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -12388,6 +12504,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^1.0.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.1.3.tgz#ea1a602e98e5a968a56a289886a52f04c686fc81" + integrity sha512-CsiQeFMR1jZEq8R+H59qe+bBevnjoV5N2WZTTdlyqxeoODQOOepN2+msQOywcieDq5sBjabKzTn3U+sfHZlMdw== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" From 716730fdd21b8630fd1b408420e8ed0f3d07c18f Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Tue, 1 Jun 2021 09:50:25 -0400 Subject: [PATCH 50/66] send auth payload on websocket open --- src/background/ipc/session.ts | 10 +++++++++- src/background/session.ts | 7 +++++-- src/background/websockets.ts | 13 ++++++++++--- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/background/ipc/session.ts b/src/background/ipc/session.ts index a2496dc..cc6edeb 100644 --- a/src/background/ipc/session.ts +++ b/src/background/ipc/session.ts @@ -5,6 +5,7 @@ import { initSession, emitNewMessages, sendMessage } from '@/background/session' import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; import { initAudioIO } from "@/background/audio"; import { ClientMessage } from "@/types"; +import { store } from "@/background/store"; // Instantiate socket session with crimata-platorm. @@ -15,7 +16,14 @@ const onSessionInit = ( console.log('[IPC]: init-session'); - initSession(cid); + const token = store.get('key'); + const crimataId = store.get('crimataId'); + + + initSession({ + token, + crimataId + }); initAudioIO(); } diff --git a/src/background/session.ts b/src/background/session.ts index fc3e4fd..0fed780 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -87,14 +87,17 @@ export const sendMessage = (payload: Record): void => { // Call this to initialize session with Crimata servers. -export const initSession = (cid: string): void => { +export const initSession = (authPayload: { + token: string; + crimataId: string; +}): void => { console.log("SESS:Creating new session.") // Load Json or createState. state = loadState("session.json"); // Open socket connection. - createSocket(); + createSocket(authPayload); // Keep win up-to-date. backgroundMitt.on('window-active', (state: boolean) => { diff --git a/src/background/websockets.ts b/src/background/websockets.ts index 9fcc5e8..6f1abc2 100644 --- a/src/background/websockets.ts +++ b/src/background/websockets.ts @@ -41,7 +41,6 @@ export default function useWebSockets( const onOpen = (_event: WebSocket.OpenEvent) => { console.log("WS:Connected to WS Server!"); - if (openCallback) openCallback(); } @@ -66,12 +65,20 @@ export default function useWebSockets( setTimeout(createSocket, 1000) } - const createSocket = () => { + const createSocket = (authPayload: { + token: string; + crimataId: string; + }) => { if (socketUrl) socket = new WebSocket(socketUrl) // Add listeners. - socket.addEventListener("open", onOpen) + socket.addEventListener("open", (_event: WebSocket.OpenEvent) => { + socket.send(JSON.stringify({ + key: authPayload.token, + crimata_id: authPayload.crimataId + })); + }) socket.addEventListener("message", onServerMessage) socket.addEventListener("close", onClose) socket.addEventListener("error", onError) From 7dbf4e6aa6b2f9b3e1ef6f5af191427f07cb6728 Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Wed, 2 Jun 2021 21:11:53 -0400 Subject: [PATCH 51/66] remove .env file(electron not picking it up) --- .env | 4 ---- src/App.vue | 7 +++++++ src/background.ts | 4 ++-- src/background/ipc/account.ts | 2 +- src/background/session.ts | 5 ++++- src/background/websockets.ts | 5 ++--- src/components/login.vue | 10 +++++++++- src/ipcRend/session.ts | 2 ++ src/main.ts | 1 + src/modules/http.ts | 2 +- 10 files changed, 29 insertions(+), 13 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index 6aa5026..0000000 --- a/.env +++ /dev/null @@ -1,4 +0,0 @@ - -BUSINESS_URL="http://localhost:3000" - -PLATFORM_URL="ws://127.0.0.1:8760" diff --git a/src/App.vue b/src/App.vue index 5a29c17..52e44e6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -85,8 +85,14 @@ export default defineComponent({ } + const onSessionAuthFail = (_event: IpcRendererEvent, _payload: null) => { + clearProfile(); + } + onMounted(async () => { console.log("APP:mounted."); + + window.ipcRenderer.on("session-auth-fail", onSessionAuthFail) window.ipcRenderer.on("update-state", updateState) window.ipcRenderer.on("update_available", () => { console.log('testing auto update'); @@ -117,6 +123,7 @@ export default defineComponent({ onUnmounted(() => { window.ipcRenderer.removeAllListeners("update-state"); + window.ipcRenderer.removeAllListeners("session-auth-fail"); }) return { diff --git a/src/background.ts b/src/background.ts index 1ecee83..b67e829 100644 --- a/src/background.ts +++ b/src/background.ts @@ -18,9 +18,9 @@ protocol.registerSchemesAsPrivileged([ const isDev = require('electron-is-dev'); // NOTE Program Begins Here -(async () => { +(() => { console.log('Starting Crimata electron app.'); - await initApp(isDev); + initApp(isDev); })(); diff --git a/src/background/ipc/account.ts b/src/background/ipc/account.ts index c336ac3..c9594be 100644 --- a/src/background/ipc/account.ts +++ b/src/background/ipc/account.ts @@ -70,7 +70,7 @@ const onLogin = async ( resolve(parsed.profile); } catch(e) { - console.log('[API]', e.response); + console.log('[API]', e); reject(new Error('Failed to authenticate')); } } diff --git a/src/background/session.ts b/src/background/session.ts index 0fed780..fac6572 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -26,7 +26,10 @@ let state: SessionState; // Calls appropriate endpoint for a server message. const onMessage = (data: string): void => { let message = JSON.parse(data); - console.log('received new message', message); + if (message === "CLOSE_AUTH_FAIL") { + ipcEmit("session-auth-fail", null) + return; + } // Standard message. if (message.content) { diff --git a/src/background/websockets.ts b/src/background/websockets.ts index 6f1abc2..5556ece 100644 --- a/src/background/websockets.ts +++ b/src/background/websockets.ts @@ -4,7 +4,7 @@ import WebSocket from 'ws'; let socket: WebSocket; -const socketUrl = process.env.PLATFORM_URL; +const socketUrl = "ws://127.0.0.1:8760" // Run every time we want to connect to backend. export default function useWebSockets( @@ -53,7 +53,7 @@ export default function useWebSockets( } - const onClose = (_event: WebSocket.CloseEvent) => { + const onClose = (event: WebSocket.CloseEvent) => { console.log("WS:Socket closed normally.") } @@ -69,7 +69,6 @@ export default function useWebSockets( token: string; crimataId: string; }) => { - if (socketUrl) socket = new WebSocket(socketUrl) // Add listeners. diff --git a/src/components/login.vue b/src/components/login.vue index 8232a67..2cb82f8 100644 --- a/src/components/login.vue +++ b/src/components/login.vue @@ -40,13 +40,14 @@ import { authRequest } from '@/modules/message'; import { useProfile } from '@/modules/auth'; import { invokeLogin } from "@/ipcRend/account"; import { Profile } from "@/types"; +import { postInitSession } from "@/ipcRend/session"; export default defineComponent({ name: "Login", setup() { - const { setProfile } = useProfile(); + const { profile, setProfile } = useProfile(); const usr = ref(""); const pwd = ref(""); @@ -63,6 +64,13 @@ export default defineComponent({ setProfile(profile); } catch(e) { + console.log('Error login in.') + } finally{ + + if (profile.value.crimataId) { + // start session + postInitSession(profile.value.crimataId); + } } } diff --git a/src/ipcRend/session.ts b/src/ipcRend/session.ts index 966b121..2eb4405 100644 --- a/src/ipcRend/session.ts +++ b/src/ipcRend/session.ts @@ -19,3 +19,5 @@ export const postInitSession = (cid: string): void => ( export const postMessage = (payload: ClientMessage): void => ( post('client-message', payload) ); + + diff --git a/src/main.ts b/src/main.ts index 35774f7..68cc98e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,6 +4,7 @@ import App from "./App.vue"; import mitt from "mitt"; import { createApp } from "vue"; +require('dotenv').config() // Handle events. diff --git a/src/modules/http.ts b/src/modules/http.ts index de241e0..a9519a8 100644 --- a/src/modules/http.ts +++ b/src/modules/http.ts @@ -3,7 +3,7 @@ import axios, { AxiosRequestConfig } from 'axios'; const preFix = '/api'; -const baseURL = process.env.BUSSINESS_URL + preFix; +const baseURL = "http://127.0.0.1:3000" + preFix; interface Request { From ac8f338d758cd19dd95648f3ed62a3d91714ac06 Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Thu, 3 Jun 2021 09:55:50 -0400 Subject: [PATCH 52/66] close session on logout --- src/background/ipc/account.ts | 2 ++ src/background/session.ts | 13 ++++++++++++- src/background/websockets.ts | 6 ++++-- tests/server.js | 5 +++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/background/ipc/account.ts b/src/background/ipc/account.ts index c9594be..5898509 100644 --- a/src/background/ipc/account.ts +++ b/src/background/ipc/account.ts @@ -5,6 +5,7 @@ import { Profile } from "@/types"; import { submit, fetchProfile, logout } from "@/api/account"; import { ipcMain, IpcMainInvokeEvent } from "electron"; import { store } from "@/background/store"; +import { endSession } from "@/background/session"; const parseAuthRes = (authRes: any) => { @@ -94,6 +95,7 @@ const onLogout = async ( store.delete('crimataId'); // TODO: kill crimata platform session + endSession(); resolve(); } catch(e) { diff --git a/src/background/session.ts b/src/background/session.ts index fac6572..ebfbc26 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -10,6 +10,7 @@ import { backgroundMitt } from "@/modules/emitter"; import { ipcEmit, loadState } from './helpers'; +import WebSocket from 'ws'; import useWebSockets from "./websockets"; @@ -22,6 +23,8 @@ let win = true; // Info saved to json on quit (key, newMessages). let state: SessionState; +let socket: WebSocket | null = null; + // Calls appropriate endpoint for a server message. const onMessage = (data: string): void => { @@ -88,6 +91,13 @@ export const sendMessage = (payload: Record): void => { } +export const endSession = (): void => { + if (socket) { + socket.close(); + socket = null; + } +} + // Call this to initialize session with Crimata servers. export const initSession = (authPayload: { @@ -100,7 +110,8 @@ export const initSession = (authPayload: { state = loadState("session.json"); // Open socket connection. - createSocket(authPayload); + if (!socket) + socket = createSocket(authPayload); // Keep win up-to-date. backgroundMitt.on('window-active', (state: boolean) => { diff --git a/src/background/websockets.ts b/src/background/websockets.ts index 5556ece..36eae6f 100644 --- a/src/background/websockets.ts +++ b/src/background/websockets.ts @@ -1,3 +1,4 @@ + "use strict"; import WebSocket from 'ws'; @@ -68,7 +69,7 @@ export default function useWebSockets( const createSocket = (authPayload: { token: string; crimataId: string; - }) => { + }):WebSocket => { socket = new WebSocket(socketUrl) // Add listeners. @@ -82,7 +83,8 @@ export default function useWebSockets( socket.addEventListener("close", onClose) socket.addEventListener("error", onError) - console.log("WS:New socket created.") + return socket; + } return { diff --git a/tests/server.js b/tests/server.js index 6731be9..9616e8a 100644 --- a/tests/server.js +++ b/tests/server.js @@ -6,6 +6,7 @@ const wss = new WebSocket.Server({ let auth = false; wss.on("connection", function connection(ws, req) { + ws.on("message", function incoming(message) { console.log(message) @@ -19,13 +20,13 @@ wss.on("connection", function connection(ws, req) { auth = true; } else { const parsed = JSON.parse(message); - console.log('got a message', message) + console.log('got a message', message); } } else { const parsed = JSON.parse(message); - console.log('parsed', parsed) + console.log('parsed', parsed); } }); From 0079c72ea023bee0622e5b566cd99c5755d6a8a5 Mon Sep 17 00:00:00 2001 From: Enrique Hernandez Date: Tue, 1 Jun 2021 09:50:25 -0400 Subject: [PATCH 53/66] send auth payload on websocket open close session on logout add socket reconnect on close --- .env | 4 ---- package.json | 1 - src/App.vue | 12 +++++++++--- src/background.ts | 5 ++--- src/background/authPayload.ts | 13 +++++++++++++ src/background/ipc/account.ts | 4 +++- src/background/ipc/session.ts | 4 ++-- src/background/session.ts | 21 ++++++++++++++++++--- src/background/websockets.ts | 34 +++++++++++++++++++--------------- src/components/login.vue | 10 +++++++++- src/ipcRend/session.ts | 6 ++++-- src/modules/http.ts | 2 +- tests/server.js | 5 +++-- 13 files changed, 83 insertions(+), 38 deletions(-) delete mode 100644 .env create mode 100644 src/background/authPayload.ts diff --git a/.env b/.env deleted file mode 100644 index 6aa5026..0000000 --- a/.env +++ /dev/null @@ -1,4 +0,0 @@ - -BUSINESS_URL="http://localhost:3000" - -PLATFORM_URL="ws://127.0.0.1:8760" diff --git a/package.json b/package.json index 38c1348..ac64b5a 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "animejs": "^3.2.0", "axios": "^0.21.1", "core-js": "^3.6.5", - "dotenv": "^10.0.0", "electron-is-dev": "^2.0.0", "electron-store": "^8.0.0", "electron-updater": "^4.3.8", diff --git a/src/App.vue b/src/App.vue index 5a29c17..99ffe6a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -85,8 +85,14 @@ export default defineComponent({ } + const onSessionAuthFail = (_event: IpcRendererEvent, _payload: null) => { + clearProfile(); + } + onMounted(async () => { console.log("APP:mounted."); + + window.ipcRenderer.on("session-auth-fail", onSessionAuthFail) window.ipcRenderer.on("update-state", updateState) window.ipcRenderer.on("update_available", () => { console.log('testing auto update'); @@ -99,17 +105,16 @@ export default defineComponent({ postMount(); try { - const profile = await invokeProfile() as Profile; setProfile(profile); } catch(e) { - console.log('[AUTH]', e); + console.log('[REND] Auth:', e); clearProfile(); } finally { ready.value = true; if (profile.value.crimataId) { // start session - postInitSession(profile.value.crimataId); + postInitSession(); } } @@ -117,6 +122,7 @@ export default defineComponent({ onUnmounted(() => { window.ipcRenderer.removeAllListeners("update-state"); + window.ipcRenderer.removeAllListeners("session-auth-fail"); }) return { diff --git a/src/background.ts b/src/background.ts index 1ecee83..977c265 100644 --- a/src/background.ts +++ b/src/background.ts @@ -7,7 +7,6 @@ import { initApp } from './background/init'; import { protocol } from "electron"; -require('dotenv').config() // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([ @@ -18,9 +17,9 @@ protocol.registerSchemesAsPrivileged([ const isDev = require('electron-is-dev'); // NOTE Program Begins Here -(async () => { +(() => { console.log('Starting Crimata electron app.'); - await initApp(isDev); + initApp(isDev); })(); diff --git a/src/background/authPayload.ts b/src/background/authPayload.ts new file mode 100644 index 0000000..61d68b6 --- /dev/null +++ b/src/background/authPayload.ts @@ -0,0 +1,13 @@ + +import { store } from "@/background/store"; + +interface PlatformAuthProtocol { + key: string; + crimata_id: string; +} + +export const getAuthPayload = (): PlatformAuthProtocol => ({ + key: store.get('key'), + crimata_id: store.get('crimataId') +}); + diff --git a/src/background/ipc/account.ts b/src/background/ipc/account.ts index c336ac3..5898509 100644 --- a/src/background/ipc/account.ts +++ b/src/background/ipc/account.ts @@ -5,6 +5,7 @@ import { Profile } from "@/types"; import { submit, fetchProfile, logout } from "@/api/account"; import { ipcMain, IpcMainInvokeEvent } from "electron"; import { store } from "@/background/store"; +import { endSession } from "@/background/session"; const parseAuthRes = (authRes: any) => { @@ -70,7 +71,7 @@ const onLogin = async ( resolve(parsed.profile); } catch(e) { - console.log('[API]', e.response); + console.log('[API]', e); reject(new Error('Failed to authenticate')); } } @@ -94,6 +95,7 @@ const onLogout = async ( store.delete('crimataId'); // TODO: kill crimata platform session + endSession(); resolve(); } catch(e) { diff --git a/src/background/ipc/session.ts b/src/background/ipc/session.ts index a2496dc..7c42ea2 100644 --- a/src/background/ipc/session.ts +++ b/src/background/ipc/session.ts @@ -10,12 +10,12 @@ import { ClientMessage } from "@/types"; // Instantiate socket session with crimata-platorm. const onSessionInit = ( _event: IpcMainInvokeEvent, - cid: string + _payload: null ): void => { console.log('[IPC]: init-session'); - initSession(cid); + initSession(); initAudioIO(); } diff --git a/src/background/session.ts b/src/background/session.ts index fc3e4fd..c90d32a 100644 --- a/src/background/session.ts +++ b/src/background/session.ts @@ -10,6 +10,7 @@ import { backgroundMitt } from "@/modules/emitter"; import { ipcEmit, loadState } from './helpers'; +import WebSocket from 'ws'; import useWebSockets from "./websockets"; @@ -22,11 +23,17 @@ let win = true; // Info saved to json on quit (key, newMessages). let state: SessionState; +let socket: WebSocket | null = null; + // Calls appropriate endpoint for a server message. const onMessage = (data: string): void => { let message = JSON.parse(data); - console.log('received new message', message); + + if (message === "CLOSE_AUTH_FAIL") { + ipcEmit("session-auth-fail", null) + return; + } // Standard message. if (message.content) { @@ -85,16 +92,24 @@ export const sendMessage = (payload: Record): void => { } +export const endSession = (): void => { + if (socket) { + socket.close(); + socket = null; + } +} + // Call this to initialize session with Crimata servers. -export const initSession = (cid: string): void => { +export const initSession = (): void => { console.log("SESS:Creating new session.") // Load Json or createState. state = loadState("session.json"); // Open socket connection. - createSocket(); + if (!socket) + socket = createSocket(); // Keep win up-to-date. backgroundMitt.on('window-active', (state: boolean) => { diff --git a/src/background/websockets.ts b/src/background/websockets.ts index 9fcc5e8..70eb7ff 100644 --- a/src/background/websockets.ts +++ b/src/background/websockets.ts @@ -1,10 +1,12 @@ + "use strict"; import WebSocket from 'ws'; +import { getAuthPayload } from "./authPayload"; let socket: WebSocket; -const socketUrl = process.env.PLATFORM_URL; +const socketUrl = "ws://127.0.0.1:8760" // Run every time we want to connect to backend. export default function useWebSockets( @@ -41,7 +43,8 @@ export default function useWebSockets( const onOpen = (_event: WebSocket.OpenEvent) => { console.log("WS:Connected to WS Server!"); - + const jwt = getAuthPayload(); + socket.send(JSON.stringify(jwt)); if (openCallback) openCallback(); } @@ -54,29 +57,30 @@ export default function useWebSockets( } - const onClose = (_event: WebSocket.CloseEvent) => { - console.log("WS:Socket closed normally.") + const onClose = (event: WebSocket.CloseEvent) => { + console.log("WS:Socket closed normally.", event.wasClean) + if (!event.wasClean) { + setTimeout(createSocket, 1000); + } } // Reconnect automatically on error. const onError = (event: WebSocket.ErrorEvent) => { console.log("WS:WebSocket error: ", event.message); - - console.log("Attempting reconnect in 1s.") - setTimeout(createSocket, 1000) } - const createSocket = () => { - if (socketUrl) - socket = new WebSocket(socketUrl) + const createSocket = (): WebSocket => { + + socket = new WebSocket(socketUrl); // Add listeners. - socket.addEventListener("open", onOpen) - socket.addEventListener("message", onServerMessage) - socket.addEventListener("close", onClose) - socket.addEventListener("error", onError) + socket.addEventListener("open", onOpen); + socket.addEventListener("message", onServerMessage); + socket.addEventListener("close", onClose); + socket.addEventListener("error", onError); + + return socket; - console.log("WS:New socket created.") } return { diff --git a/src/components/login.vue b/src/components/login.vue index 8232a67..9467a21 100644 --- a/src/components/login.vue +++ b/src/components/login.vue @@ -40,13 +40,14 @@ import { authRequest } from '@/modules/message'; import { useProfile } from '@/modules/auth'; import { invokeLogin } from "@/ipcRend/account"; import { Profile } from "@/types"; +import { postInitSession } from "@/ipcRend/session"; export default defineComponent({ name: "Login", setup() { - const { setProfile } = useProfile(); + const { profile, setProfile } = useProfile(); const usr = ref(""); const pwd = ref(""); @@ -63,6 +64,13 @@ export default defineComponent({ setProfile(profile); } catch(e) { + console.log('Error login in.') + } finally{ + + if (profile.value.crimataId) { + // start session + postInitSession(); + } } } diff --git a/src/ipcRend/session.ts b/src/ipcRend/session.ts index 966b121..a5ff5fc 100644 --- a/src/ipcRend/session.ts +++ b/src/ipcRend/session.ts @@ -11,11 +11,13 @@ export const postMount = (): void => ( ); -export const postInitSession = (cid: string): void => ( - post("init-session", cid) +export const postInitSession = (): void => ( + post("init-session", null) ); export const postMessage = (payload: ClientMessage): void => ( post('client-message', payload) ); + + diff --git a/src/modules/http.ts b/src/modules/http.ts index de241e0..a9519a8 100644 --- a/src/modules/http.ts +++ b/src/modules/http.ts @@ -3,7 +3,7 @@ import axios, { AxiosRequestConfig } from 'axios'; const preFix = '/api'; -const baseURL = process.env.BUSSINESS_URL + preFix; +const baseURL = "http://127.0.0.1:3000" + preFix; interface Request { diff --git a/tests/server.js b/tests/server.js index 6731be9..9616e8a 100644 --- a/tests/server.js +++ b/tests/server.js @@ -6,6 +6,7 @@ const wss = new WebSocket.Server({ let auth = false; wss.on("connection", function connection(ws, req) { + ws.on("message", function incoming(message) { console.log(message) @@ -19,13 +20,13 @@ wss.on("connection", function connection(ws, req) { auth = true; } else { const parsed = JSON.parse(message); - console.log('got a message', message) + console.log('got a message', message); } } else { const parsed = JSON.parse(message); - console.log('parsed', parsed) + console.log('parsed', parsed); } }); From 25b03d501cd0d82075178cb8796274e44cde156a Mon Sep 17 00:00:00 2001 From: riqo Date: Tue, 8 Jun 2021 07:57:57 -0500 Subject: [PATCH 54/66] add websocket ping connection check --- src/background/ipc/account.ts | 2 +- src/background/websockets.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/background/ipc/account.ts b/src/background/ipc/account.ts index 5898509..4bf6411 100644 --- a/src/background/ipc/account.ts +++ b/src/background/ipc/account.ts @@ -42,7 +42,7 @@ const onProfile = async ( resolve(parsed.profile); } catch(e) { - reject(new Error('Failed to fetch profile.')); + reject(new Error('Unable to authenticate and fetch account profile.')); } }) ) diff --git a/src/background/websockets.ts b/src/background/websockets.ts index 70eb7ff..dec0203 100644 --- a/src/background/websockets.ts +++ b/src/background/websockets.ts @@ -3,11 +3,17 @@ import WebSocket from 'ws'; import { getAuthPayload } from "./authPayload"; +import { ipcEmit } from './helpers'; let socket: WebSocket; const socketUrl = "ws://127.0.0.1:8760" +const _connectionCheckTimeout = 4000; +const _reconnectTimeout = 1000; +let _connectionCheckInterval: ReturnType; + + // Run every time we want to connect to backend. export default function useWebSockets( receiveCallback: (s: string) => void, @@ -45,6 +51,20 @@ export default function useWebSockets( console.log("WS:Connected to WS Server!"); const jwt = getAuthPayload(); socket.send(JSON.stringify(jwt)); + + // ping server + _connectionCheckInterval = setInterval(() => { + + if (socket) socket.ping(null, true, (e: Error) => { + if (e) { + ipcEmit('connection-alive', false); + socket.close(); + setTimeout(createSocket, 1000); + } + }); + + }, _connectionCheckTimeout); + if (openCallback) openCallback(); } @@ -59,7 +79,11 @@ export default function useWebSockets( const onClose = (event: WebSocket.CloseEvent) => { console.log("WS:Socket closed normally.", event.wasClean) + + clearInterval(_connectionCheckInterval); + if (!event.wasClean) { + ipcEmit('connection-alive', false); setTimeout(createSocket, 1000); } } @@ -69,8 +93,11 @@ export default function useWebSockets( console.log("WS:WebSocket error: ", event.message); } + const createSocket = (): WebSocket => { + if (_connectionCheckInterval) clearInterval(_connectionCheckInterval); + socket = new WebSocket(socketUrl); // Add listeners. @@ -78,6 +105,9 @@ export default function useWebSockets( socket.addEventListener("message", onServerMessage); socket.addEventListener("close", onClose); socket.addEventListener("error", onError); + socket.addEventListener("pong", () => { + ipcEmit('connection-alive', true); + }); return socket; From 3b5da6124fba4696bb87f5255dae7a7612a1ce0b Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Tue, 8 Jun 2021 21:21:11 -0500 Subject: [PATCH 55/66] beginnings of refactor --- src/App.vue | 213 --------- src/api/account.ts | 21 +- src/assets/crimata.svg | 14 - src/audio.ts | 0 src/background.ts | 26 -- src/background/audio.ts | 172 ------- src/background/helpers.ts | 62 --- src/background/init.ts | 89 ---- src/background/ipc/audio.ts | 40 -- src/background/ipc/session.ts | 70 --- src/background/session.ts | 121 ----- src/background/websockets.ts | 96 ---- src/components/controllers/audioCtrl.ts | 118 ----- .../keyBoardMaps/keyboardCharMap.ts | 263 ----------- .../keyBoardMaps/keyboardNameMap.ts | 261 ----------- src/components/message.vue | 419 ------------------ src/components/messenger.vue | 114 ----- src/components/textInput.vue | 49 -- src/composables/audio.ts | 187 ++++++++ src/composables/autoUpdate.ts | 31 ++ src/{modules => composables}/emitter.ts | 12 +- src/{modules => composables}/http.ts | 0 src/composables/json.ts | 9 + src/{background => composables}/store.ts | 0 src/composables/websockets.ts | 73 +++ src/init.ts | 46 ++ src/{background => }/ipc/account.ts | 29 +- src/ipc/audio.ts | 34 ++ src/{background => }/ipc/index.ts | 4 +- src/ipc/session.ts | 20 + src/ipcRend/account.ts | 27 -- src/ipcRend/audio.ts | 15 - src/ipcRend/session.ts | 23 - src/main.ts | 76 +++- src/modules/message.ts | 62 --- src/modules/messages.ts | 125 ------ src/modules/mitt.ts | 19 - src/modules/scroll.ts | 50 --- src/render/App.vue | 86 ++++ src/render/components/bubble.vue | 330 ++++++++++++++ .../components/controllers/bubble.control.ts | 0 src/render/components/controllers/helpers.ts | 102 +++++ .../controllers/inputItem.control.audio.ts | 79 ++++ .../controllers/inputItem.control.text.ts} | 104 +---- .../controllers/messenger.control.ts | 143 ++++++ src/render/components/header.vue | 81 ++++ src/{ => render}/components/inputItem.vue | 37 +- src/{ => render}/components/login.vue | 19 +- src/render/components/messenger.vue | 101 +++++ src/{ => render}/components/settings.vue | 0 src/{ => render}/components/splash.vue | 0 src/{modules => render/composables}/auth.ts | 2 - .../composables}/draggify.ts | 0 src/{modules => render/composables}/ipc.ts | 2 +- src/render/composables/scroll.ts | 29 ++ src/render/ipc.ts | 52 +++ src/{ => render}/preload.ts | 0 src/{ => render}/shims-vue.d.ts | 0 src/session.ts | 64 +++ src/state.ts | 29 ++ src/types.ts | 73 +-- src/{background => }/window.ts | 29 +- tsconfig.json | 1 + 63 files changed, 1697 insertions(+), 2656 deletions(-) delete mode 100644 src/App.vue delete mode 100644 src/assets/crimata.svg create mode 100644 src/audio.ts delete mode 100644 src/background.ts delete mode 100644 src/background/audio.ts delete mode 100644 src/background/helpers.ts delete mode 100644 src/background/init.ts delete mode 100644 src/background/ipc/audio.ts delete mode 100644 src/background/ipc/session.ts delete mode 100644 src/background/session.ts delete mode 100644 src/background/websockets.ts delete mode 100644 src/components/controllers/audioCtrl.ts delete mode 100644 src/components/keyBoardMaps/keyboardCharMap.ts delete mode 100644 src/components/keyBoardMaps/keyboardNameMap.ts delete mode 100644 src/components/message.vue delete mode 100644 src/components/messenger.vue delete mode 100644 src/components/textInput.vue create mode 100644 src/composables/audio.ts create mode 100644 src/composables/autoUpdate.ts rename src/{modules => composables}/emitter.ts (51%) rename src/{modules => composables}/http.ts (100%) create mode 100644 src/composables/json.ts rename src/{background => composables}/store.ts (100%) create mode 100644 src/composables/websockets.ts create mode 100644 src/init.ts rename src/{background => }/ipc/account.ts (84%) create mode 100644 src/ipc/audio.ts rename src/{background => }/ipc/index.ts (74%) create mode 100644 src/ipc/session.ts delete mode 100644 src/ipcRend/account.ts delete mode 100644 src/ipcRend/audio.ts delete mode 100644 src/ipcRend/session.ts delete mode 100644 src/modules/message.ts delete mode 100644 src/modules/messages.ts delete mode 100644 src/modules/mitt.ts delete mode 100644 src/modules/scroll.ts create mode 100644 src/render/App.vue create mode 100644 src/render/components/bubble.vue create mode 100644 src/render/components/controllers/bubble.control.ts create mode 100644 src/render/components/controllers/helpers.ts create mode 100644 src/render/components/controllers/inputItem.control.audio.ts rename src/{components/controllers/textCtrl.ts => render/components/controllers/inputItem.control.text.ts} (53%) create mode 100644 src/render/components/controllers/messenger.control.ts create mode 100644 src/render/components/header.vue rename src/{ => render}/components/inputItem.vue (87%) rename src/{ => render}/components/login.vue (89%) create mode 100644 src/render/components/messenger.vue rename src/{ => render}/components/settings.vue (100%) rename src/{ => render}/components/splash.vue (100%) rename src/{modules => render/composables}/auth.ts (90%) rename src/{modules => render/composables}/draggify.ts (100%) rename src/{modules => render/composables}/ipc.ts (91%) create mode 100644 src/render/composables/scroll.ts create mode 100644 src/render/ipc.ts rename src/{ => render}/preload.ts (100%) rename src/{ => render}/shims-vue.d.ts (100%) create mode 100644 src/session.ts create mode 100644 src/state.ts rename src/{background => }/window.ts (86%) diff --git a/src/App.vue b/src/App.vue deleted file mode 100644 index 52e44e6..0000000 --- a/src/App.vue +++ /dev/null @@ -1,213 +0,0 @@ - - - - - diff --git a/src/api/account.ts b/src/api/account.ts index 1d72822..de1335b 100644 --- a/src/api/account.ts +++ b/src/api/account.ts @@ -1,27 +1,14 @@ -import { useHttp } from "@/modules/http"; +import { useHttp } from "@/composables/http"; import axios from "axios"; const { post } = useHttp(); -export const submit = - async (email: string, password: string) => ( - - await post('/account/login', { - email, - password - }) - +export const submit = async (email: string, password: string) => ( + await post('/account/login', { email, password }) ) - -export const logout = - async (): Promise => (await post('/account/logout')); - - - -export const fetchProfile = async(email: string, token: string) => ( - +export const fetchAccount = async (email: string, token: string) => ( await axios({ url: "http://127.0.0.1:3000/api/account/profile", headers: { diff --git a/src/assets/crimata.svg b/src/assets/crimata.svg deleted file mode 100644 index 8bb28dc..0000000 --- a/src/assets/crimata.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/audio.ts b/src/audio.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/background.ts b/src/background.ts deleted file mode 100644 index b67e829..0000000 --- a/src/background.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Entry point for Crimata electron app. - * "Look on my Works, ye Mighty, and despair!" - */ - -"use strict"; - -import { initApp } from './background/init'; -import { protocol } from "electron"; -require('dotenv').config() - -// Scheme must be registered before the app is ready -protocol.registerSchemesAsPrivileged([ - { scheme: "app", privileges: { secure: true, standard: true } } -]); - -// Load environment variable -const isDev = require('electron-is-dev'); - -// NOTE Program Begins Here -(() => { - - console.log('Starting Crimata electron app.'); - initApp(isDev); - -})(); diff --git a/src/background/audio.ts b/src/background/audio.ts deleted file mode 100644 index fa6efb2..0000000 --- a/src/background/audio.ts +++ /dev/null @@ -1,172 +0,0 @@ -/* eslint @typescript-eslint/no-var-requires: "off" */ - -"use strict"; - -import { backgroundMitt } from '@/modules/emitter'; -const portAudio = require('naudiodon'); - -// Audio in and out stream objects. -let ai: typeof portAudio.AudioIO | boolean = false; -let ao: typeof portAudio.AudioIO | boolean = false; - -// Whether activly recording. -let record = false; - -const audioContainer = { - input: '', -} - -const audioOptions = { - channelCount: 1, - sampleFormat: 16, - sampleRate: 16000, - deviceId: -1, - closeOnError: false, -} - -export const toggleRecord = (): void => { record = !record }; - - -export const fetchAudioInput = (): Promise => ( - - new Promise((resolve, reject) => { - - try { - resolve(audioContainer.input); - toggleRecord(); - } catch (e) { - reject(new Error('Failed to fetch the audio.')) - } - - }) -) - - -// Main audio function run by run.ts module. -export function initAudioIO(): void { - console.log("AUDIO:Starting io streams.") - - if (!ai) { - - // Initialize and start input stream. - ai = new portAudio.AudioIO({ inOptions: audioOptions }); - ai.setEncoding("hex"); - ai.start(); - - // On each data chunk... - ai.on('data', (chunk: string) => { - - // If recording, we capture the data. - if (record) { - console.log('AUDIO:Recording...') - audioContainer.input += chunk; - } - - // Else, we don't capture and also clear audioContainer. - else { - if (audioContainer.input.length) { - audioContainer.input = ""; - } - } - - }); - } - - if (!ao) { - - // Initialize and start input stream. - ao = new portAudio.AudioIO({ outOptions: audioOptions }); - ao.start(); - - } -} - - -// ---Audio playback-------------------------------------------- - -// Split Buffer into an array of len-sized Buffers. -function bufSplit(buf: Buffer, len: number): Array { - const chunks = []; - let i = 0; - let L = len; - - while(i < buf.byteLength) { - chunks.push(buf.slice(i, L)); - i = L; - L += len; - } - - return chunks; -} - -// Audio playback. -export function play(input: string): void { - - // Format the audio. - const audio = bufSplit( - Buffer.from(input as string, 'hex'), - 8192 - ); - - // Called on end of write. - const callback = () => { - - // We stop audio playback anim. - backgroundMitt.emit('ipc-renderer', { - endpoint: 'stop-playback-anim' - }); - - } - - write(); - - // Iterate through audio array and write buffers to portAudio writable. - function write() { - let chunk: Buffer; - let ok = true; - let i = 0; - - do { - chunk = audio[i]; - if (i === audio.length - 1) { - // write last chunk. - ao.write(chunk, null, callback); - } else { - // check for backpreassure. - ok = ao.write(chunk, null); - } - i++; - } while (i < audio.length && ok); - - if (i < audio.length) { - // Had to stop early! - // Write some more once it drains. - ao.once('drain', write); - } - } -} - -// ------------------------------------------------------------- - -// Get's called on window close. -export async function stopStream() { - console.log("AUDIO:Stopping audio stream.") - if (ai) { - try { - await ai.quit() - } catch(e){ - console.log('AUDIO: Failed to shutdown audio input.'); - throw e; - } - } - if (ao) { - try { - await ao.quit() - } catch(e){ - console.log('AUDIO: Failed to shutdown audio output.'); - throw e; - } - } -} - - diff --git a/src/background/helpers.ts b/src/background/helpers.ts deleted file mode 100644 index f0074fb..0000000 --- a/src/background/helpers.ts +++ /dev/null @@ -1,62 +0,0 @@ -import fs from 'fs'; -import { backgroundMitt } from "@/modules/emitter"; -import { SessionState, WindowState } from "@/types"; -import { app } from "electron"; - -const configPath = app.getPath("userData"); - -export const ipcEmit = (channel: string, payload: any) => { - backgroundMitt.emit('ipc-renderer', { - endpoint: channel, - message: payload - }); -} - -export const loadState = (fileName: string): SessionState => { - let state: SessionState; - - try { - state = JSON.parse(fs.readFileSync(configPath + fileName).toString()); - } - - catch (error) { - state = { - key: false, - newMessages: [] - } - } - - return state - -} - -export const loadWinState = (fileName: string): WindowState => { - let state: WindowState; - - try { - state = JSON.parse(fs.readFileSync(configPath + fileName).toString()); - } - - catch (error) { - state = { - width: 600, - height: 500, - x: null, - y: null, - } - } - - return state - -} - -// Save session or window state. -export const saveToJson = (fileName: string, data: any) => { - - fs.writeFile(configPath + fileName, JSON.stringify(data), (err) => { - if (err) { - console.log("Error when saving to json.") - } - }) - -} \ No newline at end of file diff --git a/src/background/init.ts b/src/background/init.ts deleted file mode 100644 index 1f47214..0000000 --- a/src/background/init.ts +++ /dev/null @@ -1,89 +0,0 @@ - -"use strict"; - -import { app, dialog } from "electron"; -import { createWindow } from './window'; -import { stopStream } from './audio'; -import { backgroundMitt } from '@/modules/emitter'; -import useIpc from "@/background/ipc/index"; -const { autoUpdater } = require('electron-updater'); - -let win: boolean; - -// Listen for window creation. -backgroundMitt.on('window-active', (state: boolean) => { - win = state; -}); - -// Auto updating. -autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'mvvgWYwWnot4bisiQMh_' } - -autoUpdater.on('update-available', (info: any) => { - console.log(`Update available: ${info.version}`) -}) - -autoUpdater.on('update-downloaded', (info: any) => { - - const updateDialog = { - type: 'info', - buttons: ['Restart', 'Later'], - title: 'Application Update', - message: info.version, - detail: 'A new version has been downloaded. Restart the application to apply the updates.' - } - - dialog.showMessageBox(updateDialog).then((returnValue) => { - if (returnValue.response === 0) autoUpdater.quitAndInstall() - }) - -}) - - - -// Run when electron app is initialized. -async function main(): Promise { - - console.log("MAIN:Initializing Electron App."); - - useIpc(); - - // Must wait til window is created. - await createWindow(); - -} - -// Root function of app. -export function initApp(dev: boolean): void { - - // On initial startup. - app.on("ready", () => { - // autoUpdater.checkForUpdates() - main(); - }); - - // Must keep to ensure app doesn't quit on close. - app.on("before-quit", async () => { - await stopStream(); - }); - - // Must keep to ensure app doesn't quit on close. - app.on("window-all-closed", () => { - }); - - // When user clicks app icon (re-open) - app.on("activate", () => { - - if (!win) { - createWindow(); - } - - }); - - // Exit cleanly on request from parent process in development mode. - if (dev) { - process.on("SIGTERM", () => { - app.quit(); - }); - } -} - diff --git a/src/background/ipc/audio.ts b/src/background/ipc/audio.ts deleted file mode 100644 index 1419273..0000000 --- a/src/background/ipc/audio.ts +++ /dev/null @@ -1,40 +0,0 @@ - -"use strict"; - -import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; -import { fetchAudioInput, toggleRecord } from "@/background/audio"; - - -// Toggles record to true to begin capturing chunks. -const onRecordingStart = ( - _event: IpcMainEvent, - _payload: null -): void => { - - console.log('[IPC]: start-recording'); - - toggleRecord(); -}; - - -// Returns recorded audio to frontend and sets record to false. -const onRecordingStop = async ( - _event: IpcMainInvokeEvent, - _payload: null -): Promise => { - - console.log('[IPC]: stop-recording'); - - return await fetchAudioInput() -}; - - -export default function useAudioListeners(): void { - - ipcMain.removeAllListeners("start-recording"); - ipcMain.on("start-recording", onRecordingStart); - - ipcMain.removeHandler("stop-recording"); - ipcMain.handle("stop-recording", onRecordingStop); - -} diff --git a/src/background/ipc/session.ts b/src/background/ipc/session.ts deleted file mode 100644 index cc6edeb..0000000 --- a/src/background/ipc/session.ts +++ /dev/null @@ -1,70 +0,0 @@ - -"use strict"; - -import { initSession, emitNewMessages, sendMessage } from '@/background/session'; -import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; -import { initAudioIO } from "@/background/audio"; -import { ClientMessage } from "@/types"; -import { store } from "@/background/store"; - - -// Instantiate socket session with crimata-platorm. -const onSessionInit = ( - _event: IpcMainInvokeEvent, - cid: string -): void => { - - console.log('[IPC]: init-session'); - - const token = store.get('key'); - const crimataId = store.get('crimataId'); - - - initSession({ - token, - crimataId - }); - - initAudioIO(); -} - - -const onAppMounted = ( - _event: IpcMainInvokeEvent, - _payload: null -): void => { - - console.log('[IPC]: app-mounted'); - - emitNewMessages() -}; - - -// Handle messages from window/client. -const onClientMessage = ( - _event: IpcMainEvent, - payload: ClientMessage -): void => { - - console.log('[IPC]: client-message'); - - sendMessage(payload); -} - - -export default function useSessionListeners(): void { - - console.log('[IPC]: Init session listeners.'); - - // Attach listeners for frontend. - ipcMain.removeAllListeners("client-message"); - ipcMain.on("client-message", onClientMessage); - - // Attack browser window init listener. - ipcMain.removeAllListeners("app-mounted"); - ipcMain.on("app-mounted", onAppMounted); - - ipcMain.removeAllListeners("init-session"); - ipcMain.on("init-session", onSessionInit); - -} diff --git a/src/background/session.ts b/src/background/session.ts deleted file mode 100644 index ebfbc26..0000000 --- a/src/background/session.ts +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Creates a websocket session with Crimata Servers. - * - * Connects to Servers and attempts key authentication. Server will respond - * with key and user profile. We send the profile to the browser. We also - * resend this information on new broser window. We then serve as a - * communication interface between the window and the servers. It will - * automatically try to reconnect on websocket disconnect. - */ - -import { backgroundMitt } from "@/modules/emitter"; -import { ipcEmit, loadState } from './helpers'; -import WebSocket from 'ws'; - -import useWebSockets from "./websockets"; - -import { play } from "./audio"; -import { renderMessage } from "@/modules/message"; -import { SessionState } from "@/types"; - -let win = true; - -// Info saved to json on quit (key, newMessages). -let state: SessionState; - -let socket: WebSocket | null = null; - - -// Calls appropriate endpoint for a server message. -const onMessage = (data: string): void => { - let message = JSON.parse(data); - if (message === "CLOSE_AUTH_FAIL") { - ipcEmit("session-auth-fail", null) - return; - } - - // Standard message. - if (message.content) { - - // Convert to render message - message = renderMessage( - message.content.text, - message.content.audio, - message.context, - message.modifier - ); - - if (win) { - console.log("SESS:Emitting standard message.") - if (message.audio) { - play(message.audio) - } - ipcEmit("render-message", message) - } - - else { - console.log("SESS:No window: saving message.") - state.newMessages.push(message); - } - } - - else { - if (win) { - ipcEmit("render-message", message) - } - } - -}; - - -// Websockets module. -const { createSocket, send } = useWebSockets(onMessage); - - -export const emitNewMessages = (): void => { - if (state) { - ipcEmit("update-state", { - newMessages: state.newMessages, - }); - } - -} - - -export const sendMessage = (payload: Record): void => { - try { - send(payload) - } catch(e) { - console.log("Unable to send message: ", payload); - } - -} - -export const endSession = (): void => { - if (socket) { - socket.close(); - socket = null; - } -} - - -// Call this to initialize session with Crimata servers. -export const initSession = (authPayload: { - token: string; - crimataId: string; -}): void => { - console.log("SESS:Creating new session.") - - // Load Json or createState. - state = loadState("session.json"); - - // Open socket connection. - if (!socket) - socket = createSocket(authPayload); - - // Keep win up-to-date. - backgroundMitt.on('window-active', (state: boolean) => { - win = state; - }); - -} diff --git a/src/background/websockets.ts b/src/background/websockets.ts deleted file mode 100644 index 36eae6f..0000000 --- a/src/background/websockets.ts +++ /dev/null @@ -1,96 +0,0 @@ - -"use strict"; - -import WebSocket from 'ws'; - -let socket: WebSocket; - -const socketUrl = "ws://127.0.0.1:8760" - -// Run every time we want to connect to backend. -export default function useWebSockets( - receiveCallback: (s: string) => void, - openCallback?: () => void -) { - - // Returns bool (sucess or fail). - const sendMessage = (data: any) => { - console.log("WS:Sending message: ", data) - - if (socket.readyState !== 1) { - return false - } - - else { - socket.send(JSON.stringify(data)) - return true - } - - } - - const send = async (data: Record): Promise => ( - new Promise((resolve, reject) => { - if (socket.readyState !== 1) { - reject(false); - } - socket.send(JSON.stringify(data)) - resolve(true); - - })) - - - const onOpen = (_event: WebSocket.OpenEvent) => { - - console.log("WS:Connected to WS Server!"); - if (openCallback) openCallback(); - - } - - const onServerMessage = (event: WebSocket.MessageEvent) => { - - console.log("WS:Message received: ", event.data); - - receiveCallback(event.data.toString()) - - } - - const onClose = (event: WebSocket.CloseEvent) => { - console.log("WS:Socket closed normally.") - } - - // Reconnect automatically on error. - const onError = (event: WebSocket.ErrorEvent) => { - console.log("WS:WebSocket error: ", event.message); - - console.log("Attempting reconnect in 1s.") - setTimeout(createSocket, 1000) - } - - const createSocket = (authPayload: { - token: string; - crimataId: string; - }):WebSocket => { - socket = new WebSocket(socketUrl) - - // Add listeners. - socket.addEventListener("open", (_event: WebSocket.OpenEvent) => { - socket.send(JSON.stringify({ - key: authPayload.token, - crimata_id: authPayload.crimataId - })); - }) - socket.addEventListener("message", onServerMessage) - socket.addEventListener("close", onClose) - socket.addEventListener("error", onError) - - return socket; - - } - - return { - createSocket, - sendMessage, - send - } - -} diff --git a/src/components/controllers/audioCtrl.ts b/src/components/controllers/audioCtrl.ts deleted file mode 100644 index f635c0b..0000000 --- a/src/components/controllers/audioCtrl.ts +++ /dev/null @@ -1,118 +0,0 @@ -import anime from "animejs"; -import useMitt from "@/modules/mitt"; -import { useIpc } from '@/modules/ipc'; -import { onMounted, onUnmounted, ref, Ref } from "vue"; -import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; -import { renderMessage, clientMessage } from '@/modules/message'; -import { postMessage } from "@/ipcRend/session"; -import { invokeStopRecord } from "@/ipcRend/audio"; - - -function showRecIcon () { - - anime({ - targets: '#recIcon', - opacity: [0, 0.75], - scale: [0.0, 1], - duration: 250, - easing: 'linear', - }) - -} - -function hideRecIcon () { - - anime({ - targets: '#recIcon', - opacity: [0.75, 0], - scale: [1, 0], - duration: 250, - easing: 'linear', - }) - -} - - -export default function useAudioInputController (typing: Ref) { - - // For sending messages. - const { post, invoke } = useIpc(); - const { emitter } = useMitt(); - - // Keepp track of when we are recording. - const recording = ref(false); - - //---Callbacks----------------------------------------------- - - const onKeyDown = (e: KeyboardEvent) => { - const cmd = keyboardNameMap[e.keyCode]; - // console.log(cmd) - - // Start recording on space bar. - if (cmd == "SPACE" && !recording.value && !typing.value) { - - console.log("INPT:Starting record.") - post("start-recording", null); - - showRecIcon() - recording.value = true; - - } - - } - - const onKeyUp = async (e: KeyboardEvent) => { - const cmd = keyboardNameMap[e.keyCode]; - - // Stop recording on space up. - if (cmd == "SPACE" && recording.value) { - - // Create a message. - const message = renderMessage( - "", - "", - "", - "sf" - ) - - // Render it immediately. - emitter.emit("self-message", message); - - // Stop recording and get audio from recorder. - console.log("INPT:Stopping record.") - try { - const audio = await invokeStopRecord() as string; - // Send message to the backend for processing. - const clientM = clientMessage("", audio, message.uid); - postMessage(clientM); - } catch(e) { - console.log('Failed to fetch audio.') - } finally { - hideRecIcon(); - recording.value = false; - } - - - - } - - } - - //----------------------------------------------------------- - - onMounted(() => { - window.addEventListener("keydown", onKeyDown); - window.addEventListener("keyup", onKeyUp); - }) - - onUnmounted(() => { - window.removeEventListener("keydown", onKeyDown); - window.removeEventListener("keyup", onKeyUp); - }); - - - return { - recording - } - -} diff --git a/src/components/keyBoardMaps/keyboardCharMap.ts b/src/components/keyBoardMaps/keyboardCharMap.ts deleted file mode 100644 index 102e9c3..0000000 --- a/src/components/keyBoardMaps/keyboardCharMap.ts +++ /dev/null @@ -1,263 +0,0 @@ -// This has the UnShifted and Shifted characters that each key maps to -// Ones that are to be ignored for character input are empty. -const keyboardCharMap = [ - ["", ""], // [0] - ["", ""], // [1] - ["", ""], // [2] - ["", ""], // [3] - ["", ""], // [4] - ["", ""], // [5] - ["", ""], // [6] - ["", ""], // [7] - ["", ""], // [8] - ["", ""], // [9] - ["", ""], // [10] - ["", ""], // [11] - ["", ""], // [12] - ["\r", "\r"], // [13] - MOST control characters are ignored. This one (Carriage Return, or "Enter") is significant! - ["", ""], // [14] - ["", ""], // [15] - ["", ""], // [16] - ["", ""], // [17] - ["", ""], // [18] - ["", ""], // [19] - ["", ""], // [20] - ["", ""], // [21] - ["", ""], // [22] - ["", ""], // [23] - ["", ""], // [24] - ["", ""], // [25] - ["", ""], // [26] - ["", ""], // [27] - ["", ""], // [28] - ["", ""], // [29] - ["", ""], // [30] - ["", ""], // [31] - [" ", " "], // [32] // SPACE! Don't "clean it up" and remove the space! - ["", ""], // [33] - ["", ""], // [34] - ["", ""], // [35] - ["", ""], // [36] - ["", ""], // [37] - ["", ""], // [38] - ["", ""], // [39] - ["", ""], // [40] - ["", ""], // [41] - ["", ""], // [42] - ["", ""], // [43] - ["", ""], // [44] - ["", ""], // [45] - ["", ""], // [46] - ["", ""], // [47] - ["0", ")"], // [48] - ["1", "!"], // [49] - ["2", "@"], // [50] - ["3", "#"], // [51] - ["4", "$"], // [52] - ["5", "%"], // [53] - ["6", "^"], // [54] - ["7", "&"], // [55] - ["8", "*"], // [56] - ["9", "("], // [57] - ["", ""], // [58] - [";", ":"], // [59] - ["<", ""], // [60] - ["=", ""], // [61] - [">", ""], // [62] - ["?", ""], // [63] shifted; else "/" - ["", ""], // [64] - ["a", "A"], // [65] - ["b", "B"], // [66] - ["c", "C"], // [67] - ["d", "D"], // [68] - ["e", "E"], // [69] - ["f", "F"], // [70] - ["g", "G"], // [71] - ["h", "H"], // [72] - ["i", "I"], // [73] - ["j", "J"], // [74] - ["k", "K"], // [75] - ["l", "L"], // [76] - ["m", "M"], // [77] - ["n", "N"], // [78] - ["o", "O"], // [79] - ["p", "P"], // [80] - ["q", "Q"], // [81] - ["r", "R"], // [82] - ["s", "S"], // [83] - ["t", "T"], // [84] - ["u", "U"], // [85] - ["v", "V"], // [86] - ["w", "W"], // [87] - ["x", "X"], // [88] - ["y", "Y"], // [89] - ["z", "Z"], // [90] - ["", ""], // [91] Windows Key (Windows) or Command Key (Mac) - ["", ""], // [92] - ["", ""], // [93] - ["", ""], // [94] - ["", ""], // [95] - // Number Keypad Entries... - ["0", ""], // [96] - ["1", ""], // [97] - ["2", ""], // [98] - ["3", ""], // [99] - ["4", ""], // [100] - ["5", ""], // [101] - ["6", ""], // [102] - ["7", ""], // [103] - ["8", ""], // [104] - ["9", ""], // [105] - ["*", ""], // [106] - ["+", ""], // [107] - ["", ""], // [108] - ["-", ""], // [109] - [".", ""], // [110] - ["/", ""], // [111] - - ["", ""], // [112] - ["", ""], // [113] - ["", ""], // [114] - ["", ""], // [115] - ["", ""], // [116] - ["", ""], // [117] - ["", ""], // [118] - ["", ""], // [119] - ["", ""], // [120] - ["", ""], // [121] - ["", ""], // [122] - ["", ""], // [123] - ["", ""], // [124] - ["", ""], // [125] - ["", ""], // [126] - ["", ""], // [127] - ["", ""], // [128] - ["", ""], // [129] - ["", ""], // [130] - ["", ""], // [131] - ["", ""], // [132] - ["", ""], // [133] - ["", ""], // [134] - ["", ""], // [135] - ["", ""], // [136] - ["", ""], // [137] - ["", ""], // [138] - ["", ""], // [139] - ["", ""], // [140] - ["", ""], // [141] - ["", ""], // [142] - ["", ""], // [143] - ["", ""], // [144] - ["", ""], // [145] - ["", ""], // [146] - ["", ""], // [147] - ["", ""], // [148] - ["", ""], // [149] - ["", ""], // [150] - ["", ""], // [151] - ["", ""], // [152] - ["", ""], // [153] - ["", ""], // [154] - ["", ""], // [155] - ["", ""], // [156] - ["", ""], // [157] - ["", ""], // [158] - ["", ""], // [159] - ["", ""], // [160] - ["", ""], // [161] - ["", ""], // [162] - ["", ""], // [163] - ["", ""], // [164] - ["", ""], // [165] - ["", ""], // [166] - ["", ""], // [167] - ["", ""], // [168] - ["", ""], // [169] - ["", ""], // [170] - ["", ""], // [171] - ["", ""], // [172] - ["", ""], // [173] - ["", ""], // [174] - ["", ""], // [175] - ["", ""], // [176] - ["", ""], // [177] - ["", ""], // [178] - ["", ""], // [179] - ["", ""], // [180] - ["", ""], // [181] - ["", ""], // [182] - ["", ""], // [183] - ["", ""], // [184] - ["", ""], // [185] - [";", ":"], // [186] - ["=", "+"], // [187] - [",", "<"], // [188] - ["-", "_"], // [189] - [".", ">"], // [190] - ["/", "?"], // [191] - ["`", "~"], // [192] - ["", ""], // [193] - ["", ""], // [194] - ["", ""], // [195] - ["", ""], // [196] - ["", ""], // [197] - ["", ""], // [198] - ["", ""], // [199] - ["", ""], // [200] - ["", ""], // [201] - ["", ""], // [202] - ["", ""], // [203] - ["", ""], // [204] - ["", ""], // [205] - ["", ""], // [206] - ["", ""], // [207] - ["", ""], // [208] - ["", ""], // [209] - ["", ""], // [210] - ["", ""], // [211] - ["", ""], // [212] - ["", ""], // [213] - ["", ""], // [214] - ["", ""], // [215] - ["", ""], // [216] - ["", ""], // [217] - ["", ""], // [218] - ["[", "{"], // [219] - ["\\", "|"], // [220] - ["]", "}"], // [221] - ["'", '"'], // [222] - ["", ""], // [223] - ["", ""], // [224] - ["", ""], // [225] - ["", ""], // [226] - ["", ""], // [227] - ["", ""], // [228] - ["", ""], // [229] - ["", ""], // [230] - ["", ""], // [231] - ["", ""], // [232] - ["", ""], // [233] - ["", ""], // [234] - ["", ""], // [235] - ["", ""], // [236] - ["", ""], // [237] - ["", ""], // [238] - ["", ""], // [239] - ["", ""], // [240] - ["", ""], // [241] - ["", ""], // [242] - ["", ""], // [243] - ["", ""], // [244] - ["", ""], // [245] - ["", ""], // [246] - ["", ""], // [247] - ["", ""], // [248] - ["", ""], // [249] - ["", ""], // [250] - ["", ""], // [251] - ["", ""], // [252] - ["", ""], // [253] - ["", ""], // [254] - ["", ""] // [255] -]; -export default keyboardCharMap; diff --git a/src/components/keyBoardMaps/keyboardNameMap.ts b/src/components/keyBoardMaps/keyboardNameMap.ts deleted file mode 100644 index 8f385ae..0000000 --- a/src/components/keyBoardMaps/keyboardNameMap.ts +++ /dev/null @@ -1,261 +0,0 @@ -// names of known key codes (0-255) -const keyboardNameMap = [ - "", // [0] - "", // [1] - "", // [2] - "CANCEL", // [3] - "", // [4] - "", // [5] - "HELP", // [6] - "", // [7] - "BACK_SPACE", // [8] - "TAB", // [9] - "", // [10] - "", // [11] - "CLEAR", // [12] - "ENTER", // [13] - "ENTER_SPECIAL", // [14] - "", // [15] - "SHIFT", // [16] - "CONTROL", // [17] - "ALT", // [18] - "PAUSE", // [19] - "CAPS_LOCK", // [20] - "KANA", // [21] - "EISU", // [22] - "JUNJA", // [23] - "FINAL", // [24] - "HANJA", // [25] - "", // [26] - "ESCAPE", // [27] - "CONVERT", // [28] - "NONCONVERT", // [29] - "ACCEPT", // [30] - "MODECHANGE", // [31] - "SPACE", // [32] - "PAGE_UP", // [33] - "PAGE_DOWN", // [34] - "END", // [35] - "HOME", // [36] - "LEFT", // [37] - "UP", // [38] - "RIGHT", // [39] - "DOWN", // [40] - "SELECT", // [41] - "PRINT", // [42] - "EXECUTE", // [43] - "PRINTSCREEN", // [44] - "INSERT", // [45] - "DELETE", // [46] - "", // [47] - "0", // [48] - "1", // [49] - "2", // [50] - "3", // [51] - "4", // [52] - "5", // [53] - "6", // [54] - "7", // [55] - "8", // [56] - "9", // [57] - "COLON", // [58] - "SEMICOLON", // [59] - "LESS_THAN", // [60] - "EQUALS", // [61] - "GREATER_THAN", // [62] - "QUESTION_MARK", // [63] - "AT", // [64] - "A", // [65] - "B", // [66] - "C", // [67] - "D", // [68] - "E", // [69] - "F", // [70] - "G", // [71] - "H", // [72] - "I", // [73] - "J", // [74] - "K", // [75] - "L", // [76] - "M", // [77] - "N", // [78] - "O", // [79] - "P", // [80] - "Q", // [81] - "R", // [82] - "S", // [83] - "T", // [84] - "U", // [85] - "V", // [86] - "W", // [87] - "X", // [88] - "Y", // [89] - "Z", // [90] - "OS_KEY", // [91] Windows Key (Windows) or Command Key (Mac) - "", // [92] - "CONTEXT_MENU", // [93] - "", // [94] - "SLEEP", // [95] - "NUMPAD0", // [96] - "NUMPAD1", // [97] - "NUMPAD2", // [98] - "NUMPAD3", // [99] - "NUMPAD4", // [100] - "NUMPAD5", // [101] - "NUMPAD6", // [102] - "NUMPAD7", // [103] - "NUMPAD8", // [104] - "NUMPAD9", // [105] - "MULTIPLY", // [106] - "ADD", // [107] - "SEPARATOR", // [108] - "SUBTRACT", // [109] - "DECIMAL", // [110] - "DIVIDE", // [111] - "F1", // [112] - "F2", // [113] - "F3", // [114] - "F4", // [115] - "F5", // [116] - "F6", // [117] - "F7", // [118] - "F8", // [119] - "F9", // [120] - "F10", // [121] - "F11", // [122] - "F12", // [123] - "F13", // [124] - "F14", // [125] - "F15", // [126] - "F16", // [127] - "F17", // [128] - "F18", // [129] - "F19", // [130] - "F20", // [131] - "F21", // [132] - "F22", // [133] - "F23", // [134] - "F24", // [135] - "", // [136] - "", // [137] - "", // [138] - "", // [139] - "", // [140] - "", // [141] - "", // [142] - "", // [143] - "NUM_LOCK", // [144] - "SCROLL_LOCK", // [145] - "WIN_OEM_FJ_JISHO", // [146] - "WIN_OEM_FJ_MASSHOU", // [147] - "WIN_OEM_FJ_TOUROKU", // [148] - "WIN_OEM_FJ_LOYA", // [149] - "WIN_OEM_FJ_ROYA", // [150] - "", // [151] - "", // [152] - "", // [153] - "", // [154] - "", // [155] - "", // [156] - "", // [157] - "", // [158] - "", // [159] - "CIRCUMFLEX", // [160] - "EXCLAMATION", // [161] - "DOUBLE_QUOTE", // [162] - "HASH", // [163] - "DOLLAR", // [164] - "PERCENT", // [165] - "AMPERSAND", // [166] - "UNDERSCORE", // [167] - "OPEN_PAREN", // [168] - "CLOSE_PAREN", // [169] - "ASTERISK", // [170] - "PLUS", // [171] - "PIPE", // [172] - "HYPHEN_MINUS", // [173] - "OPEN_CURLY_BRACKET", // [174] - "CLOSE_CURLY_BRACKET", // [175] - "TILDE", // [176] - "", // [177] - "", // [178] - "", // [179] - "", // [180] - "VOLUME_MUTE", // [181] - "VOLUME_DOWN", // [182] - "VOLUME_UP", // [183] - "", // [184] - "", // [185] - "SEMICOLON", // [186] - "EQUALS", // [187] - "COMMA", // [188] - "MINUS", // [189] - "PERIOD", // [190] - "SLASH", // [191] - "BACK_QUOTE", // [192] - "", // [193] - "", // [194] - "", // [195] - "", // [196] - "", // [197] - "", // [198] - "", // [199] - "", // [200] - "", // [201] - "", // [202] - "", // [203] - "", // [204] - "", // [205] - "", // [206] - "", // [207] - "", // [208] - "", // [209] - "", // [210] - "", // [211] - "", // [212] - "", // [213] - "", // [214] - "", // [215] - "", // [216] - "", // [217] - "", // [218] - "OPEN_BRACKET", // [219] - "BACK_SLASH", // [220] - "CLOSE_BRACKET", // [221] - "QUOTE", // [222] - "", // [223] - "META", // [224] - "ALTGR", // [225] - "", // [226] - "WIN_ICO_HELP", // [227] - "WIN_ICO_00", // [228] - "", // [229] - "WIN_ICO_CLEAR", // [230] - "", // [231] - "", // [232] - "WIN_OEM_RESET", // [233] - "WIN_OEM_JUMP", // [234] - "WIN_OEM_PA1", // [235] - "WIN_OEM_PA2", // [236] - "WIN_OEM_PA3", // [237] - "WIN_OEM_WSCTRL", // [238] - "WIN_OEM_CUSEL", // [239] - "WIN_OEM_ATTN", // [240] - "WIN_OEM_FINISH", // [241] - "WIN_OEM_COPY", // [242] - "WIN_OEM_AUTO", // [243] - "WIN_OEM_ENLW", // [244] - "WIN_OEM_BACKTAB", // [245] - "ATTN", // [246] - "CRSEL", // [247] - "EXSEL", // [248] - "EREOF", // [249] - "PLAY", // [250] - "ZOOM", // [251] - "", // [252] - "PA1", // [253] - "WIN_OEM_CLEAR", // [254] - "" // [255] -]; - -export default keyboardNameMap; diff --git a/src/components/message.vue b/src/components/message.vue deleted file mode 100644 index e69f29c..0000000 --- a/src/components/message.vue +++ /dev/null @@ -1,419 +0,0 @@ - - - - - diff --git a/src/components/messenger.vue b/src/components/messenger.vue deleted file mode 100644 index f5512a9..0000000 --- a/src/components/messenger.vue +++ /dev/null @@ -1,114 +0,0 @@ - - - - - diff --git a/src/components/textInput.vue b/src/components/textInput.vue deleted file mode 100644 index 45e1af7..0000000 --- a/src/components/textInput.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/composables/audio.ts b/src/composables/audio.ts new file mode 100644 index 0000000..844e791 --- /dev/null +++ b/src/composables/audio.ts @@ -0,0 +1,187 @@ +/* eslint @typescript-eslint/no-var-requires: "off" */ + +"use strict"; + +// where the audio goes +let buffer: ArrayBuffer[] = []; + +// place audio data in buffer +export function collect (chunk: ArrayBuffer) { + buffer.push(chunk); +} + +// return audio and clear buffer +export function flush () { + const bufferCopy = buffer; + buffer = []; + return bufferCopy; +} + +// import { backgroundMitt } from '@/modules/emitter'; +// const portAudio = require('naudiodon'); + +// // Audio in and out stream objects. +// let ai: typeof portAudio.AudioIO | boolean = false; +// let ao: typeof portAudio.AudioIO | boolean = false; + +// // Whether activly recording. +// let record = false; + +// const audioContainer = { +// input: '', +// } + +// const audioOptions = { +// channelCount: 1, +// sampleFormat: 16, +// sampleRate: 16000, +// deviceId: -1, +// closeOnError: false, +// } + +// export const toggleRecord = (): void => { record = !record }; + + +// export const fetchAudioInput = (): Promise => ( + +// new Promise((resolve, reject) => { + +// try { +// resolve(audioContainer.input); +// toggleRecord(); +// } catch (e) { +// reject(new Error('Failed to fetch the audio.')) +// } + +// }) +// ) + + +// // Main audio function run by run.ts module. +// export function initAudioIO(): void { +// console.log("AUDIO:Starting io streams.") + +// if (!ai) { + +// // Initialize and start input stream. +// ai = new portAudio.AudioIO({ inOptions: audioOptions }); +// ai.setEncoding("hex"); +// ai.start(); + +// // On each data chunk... +// ai.on('data', (chunk: string) => { + +// // If recording, we capture the data. +// if (record) { +// console.log('AUDIO:Recording...') +// audioContainer.input += chunk; +// } + +// // Else, we don't capture and also clear audioContainer. +// else { +// if (audioContainer.input.length) { +// audioContainer.input = ""; +// } +// } + +// }); +// } + +// if (!ao) { + +// // Initialize and start input stream. +// ao = new portAudio.AudioIO({ outOptions: audioOptions }); +// ao.start(); + +// } +// } + + +// // ---Audio playback-------------------------------------------- + +// // Split Buffer into an array of len-sized Buffers. +// function bufSplit(buf: Buffer, len: number): Array { +// const chunks = []; +// let i = 0; +// let L = len; + +// while(i < buf.byteLength) { +// chunks.push(buf.slice(i, L)); +// i = L; +// L += len; +// } + +// return chunks; +// } + +// // Audio playback. +// export function play(input: string): void { + +// // Format the audio. +// const audio = bufSplit( +// Buffer.from(input as string, 'hex'), +// 8192 +// ); + +// // Called on end of write. +// const callback = () => { + +// // We stop audio playback anim. +// backgroundMitt.emit('ipc-renderer', { +// endpoint: 'stop-playback-anim' +// }); + +// } + +// write(); + +// // Iterate through audio array and write buffers to portAudio writable. +// function write() { +// let chunk: Buffer; +// let ok = true; +// let i = 0; + +// do { +// chunk = audio[i]; +// if (i === audio.length - 1) { +// // write last chunk. +// ao.write(chunk, null, callback); +// } else { +// // check for backpreassure. +// ok = ao.write(chunk, null); +// } +// i++; +// } while (i < audio.length && ok); + +// if (i < audio.length) { +// // Had to stop early! +// // Write some more once it drains. +// ao.once('drain', write); +// } +// } +// } + +// // ------------------------------------------------------------- + +// // Get's called on window close. +// export async function stopStream() { +// console.log("AUDIO:Stopping audio stream.") +// if (ai) { +// try { +// await ai.quit() +// } catch(e){ +// console.log('AUDIO: Failed to shutdown audio input.'); +// throw e; +// } +// } +// if (ao) { +// try { +// await ao.quit() +// } catch(e){ +// console.log('AUDIO: Failed to shutdown audio output.'); +// throw e; +// } +// } +// } + + diff --git a/src/composables/autoUpdate.ts b/src/composables/autoUpdate.ts new file mode 100644 index 0000000..1a6b780 --- /dev/null +++ b/src/composables/autoUpdate.ts @@ -0,0 +1,31 @@ +const { autoUpdater } = require('electron-updater'); + +let win: boolean; + +// Listen for window creation. +backgroundMitt.on('window-active', (state: boolean) => { + win = state; +}); + +// Auto updating. +autoUpdater.requestHeaders = { 'PRIVATE-TOKEN': 'mvvgWYwWnot4bisiQMh_' } + +autoUpdater.on('update-available', (info: any) => { + console.log(`Update available: ${info.version}`) +}) + +autoUpdater.on('update-downloaded', (info: any) => { + + const updateDialog = { + type: 'info', + buttons: ['Restart', 'Later'], + title: 'Application Update', + message: info.version, + detail: 'A new version has been downloaded. Restart the application to apply the updates.' + } + + dialog.showMessageBox(updateDialog).then((returnValue) => { + if (returnValue.response === 0) autoUpdater.quitAndInstall() + }) + +}) \ No newline at end of file diff --git a/src/modules/emitter.ts b/src/composables/emitter.ts similarity index 51% rename from src/modules/emitter.ts rename to src/composables/emitter.ts index bc91693..ee6bb5e 100644 --- a/src/modules/emitter.ts +++ b/src/composables/emitter.ts @@ -1,13 +1,15 @@ /* eslint-disable */ -import { Emitter } from "mitt"; - // Backend emitter -type Mitt = Emitter; - const EventEmitter = require('events'); - class BackgroundMitt extends EventEmitter { } export const backgroundMitt = new BackgroundMitt(); + +export default function ipcEmit (channel: string, payload: any) { + backgroundMitt.emit('ipc-renderer', { + endpoint: channel, + message: payload + }); +} diff --git a/src/modules/http.ts b/src/composables/http.ts similarity index 100% rename from src/modules/http.ts rename to src/composables/http.ts diff --git a/src/composables/json.ts b/src/composables/json.ts new file mode 100644 index 0000000..43b3804 --- /dev/null +++ b/src/composables/json.ts @@ -0,0 +1,9 @@ +export const saveToJson = (fileName: string, data: any) => { + + fs.writeFile(configPath + fileName, JSON.stringify(data), (err) => { + if (err) { + console.log("Error when saving to json.") + } + }) + +} \ No newline at end of file diff --git a/src/background/store.ts b/src/composables/store.ts similarity index 100% rename from src/background/store.ts rename to src/composables/store.ts diff --git a/src/composables/websockets.ts b/src/composables/websockets.ts new file mode 100644 index 0000000..779f00b --- /dev/null +++ b/src/composables/websockets.ts @@ -0,0 +1,73 @@ + +"use strict"; + +import WebSocket from 'ws'; + +export default function useWebSockets(receiveCallback: (s: string) => void, openCallback?: () => void) { + + let socket: WebSocket | null = null; + + const send = async (data: Record): Promise => { + return new Promise((resolve, reject) => { + if (socket) { + if (socket.readyState === WebSocket.OPEN) { + socket.send(JSON.stringify(data)); + resolve(true); + } + } + reject(false); + }); + } + + const onOpen = (_event: WebSocket.OpenEvent) => { + console.log("WS:Connected to WS Server!"); + if (openCallback) openCallback(); + } + + const onServerMessage = (event: WebSocket.MessageEvent) => { + console.log("WS:Message received: ", event.data); + receiveCallback(event.data.toString()) + } + + const onClose = (event: WebSocket.CloseEvent) => { + console.log("WS:Socket closed normally.") + } + + // Reconnect automatically on error. + const onError = (event: WebSocket.ErrorEvent) => { + console.log("WS:WebSocket error: ", event.message); + console.log("Attempting reconnect in 1s.") + setTimeout(createSocket, 1000); + } + + const createSocket = (socketUrl: string) => { + + socket = new WebSocket(socketUrl) + + // Add listeners. + socket.addEventListener("open", onOpen); + socket.addEventListener("message", onServerMessage); + socket.addEventListener("close", onClose); + socket.addEventListener("error", onError); + + } + + const close = () => { + if (socket) { + socket.close(); + socket = null; + } + } + + const checkConnection = () => { + return true; + } + + return { + createSocket, + send, + close, + checkConnection + }; + +} diff --git a/src/init.ts b/src/init.ts new file mode 100644 index 0000000..3d0b721 --- /dev/null +++ b/src/init.ts @@ -0,0 +1,46 @@ +/** + * Entry point for Crimata electron app. + * "Look on my Works, ye Mighty, and despair!" + */ + +"use strict"; + +import { app, protocol } from "electron"; +import createWindow from "./window"; +import main from "./main"; + +require('dotenv').config(); + +console.log('Starting Crimata electron app.'); + +// Scheme must be registered before the app is ready +protocol.registerSchemesAsPrivileged([ + { scheme: "app", privileges: { secure: true, standard: true } } +]); + +const isDev = require('electron-is-dev'); + +/* Start main process on ready */ +app.on("ready", async () => { + await main(); +}); + +// Must keep to ensure app doesn't quit on close. +app.on("before-quit", async () => { +}); + +// Must keep to ensure app doesn't quit on close. +app.on("window-all-closed", () => { +}); + +// When user clicks app icon (re-open) +app.on("activate", () => { + if (!win) createWindow(); +}); + +// Exit cleanly on request from parent process in development mode. +if (isDev) { + process.on("SIGTERM", () => { + app.quit(); + }); +} \ No newline at end of file diff --git a/src/background/ipc/account.ts b/src/ipc/account.ts similarity index 84% rename from src/background/ipc/account.ts rename to src/ipc/account.ts index 5898509..3860019 100644 --- a/src/background/ipc/account.ts +++ b/src/ipc/account.ts @@ -1,11 +1,9 @@ "use strict"; -import { Profile } from "@/types"; -import { submit, fetchProfile, logout } from "@/api/account"; +import { submit, fetchProfile, logout } from "../api/account"; import { ipcMain, IpcMainInvokeEvent } from "electron"; -import { store } from "@/background/store"; -import { endSession } from "@/background/session"; +import { store } from "@/composables/store"; const parseAuthRes = (authRes: any) => { @@ -18,7 +16,13 @@ const parseAuthRes = (authRes: any) => { }; -const onProfile = async ( + + + +/** + * Get user profile from store and try to login with it. + */ +const onTokenLogin = async ( _event: IpcMainInvokeEvent, _payload: null ): Promise => ( @@ -33,12 +37,11 @@ const onProfile = async ( // authenticate and fetch profile try { - const res = await fetchProfile( - crimataId, - token - ); - + // attempt login with email token + const res = await fetchProfile(crimataId, token); const parsed = parseAuthRes(res); + + // return profile to renderer resolve(parsed.profile); } catch(e) { @@ -60,6 +63,8 @@ const onLogin = async ( if ( account.password && account.email ) { try { + + // attempt login with email password const res = await submit(account.email, account.password); const parsed = parseAuthRes(res); @@ -67,6 +72,8 @@ const onLogin = async ( store.set('key', parsed.token); store.set('crimataId', parsed.profile.crimataId); + // init session + // return profile to renderer resolve(parsed.profile); @@ -95,7 +102,7 @@ const onLogout = async ( store.delete('crimataId'); // TODO: kill crimata platform session - endSession(); + // endSession(); resolve(); } catch(e) { diff --git a/src/ipc/audio.ts b/src/ipc/audio.ts new file mode 100644 index 0000000..31c16ce --- /dev/null +++ b/src/ipc/audio.ts @@ -0,0 +1,34 @@ + +"use strict"; + +import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; +import { collect, flush } from "@/composbales/audio"; + +// handle the new audio data +const onAudioChunk = ( + _e: IpcMainEvent, + payload: ArrayBuffer +) => { + console.log('[IPC]: audio-buffer'); + collect(payload); +} + +// Returns recorded audio to frontend and sets record to false. +const onGetAudio = async ( + _event: IpcMainInvokeEvent, + _payload: null +): Promise => { + console.log('[IPC]: stop-recording'); + return await flush() +}; + + +export default function useAudioListeners(): void { + + ipcMain.removeAllListeners("audio-chunk"); + ipcMain.on("audio-chunk", onAudioChunk); + + ipcMain.removeHandler("get-audio"); + ipcMain.handle("get-audio", onGetAudio); + +} diff --git a/src/background/ipc/index.ts b/src/ipc/index.ts similarity index 74% rename from src/background/ipc/index.ts rename to src/ipc/index.ts index 933bda1..9152ef2 100644 --- a/src/background/ipc/index.ts +++ b/src/ipc/index.ts @@ -3,7 +3,7 @@ import useAccountListeners from "./account"; import useSessionListeners from "./session"; -import useAudioListeners from "./audio"; +// import useAudioListeners from "./audio"; export default function useIpc(): void { @@ -12,6 +12,6 @@ export default function useIpc(): void { useSessionListeners(); - useAudioListeners(); + // useAudioListeners(); } diff --git a/src/ipc/session.ts b/src/ipc/session.ts new file mode 100644 index 0000000..fa50aa1 --- /dev/null +++ b/src/ipc/session.ts @@ -0,0 +1,20 @@ + +"use strict"; + +import { ipcMain, IpcMainEvent, IpcMainInvokeEvent } from "electron"; +import { sendMessage } from '@/session'; + +// Handle messages from window/client. +function onSendMessage(_event: IpcMainEvent, payload: Message): void { + sendMessage(payload); +} + +// Login attempt, returns success or not. +function onLogin(_event: IpcMainEvent, payload: LoginPayload) => { + authenticate(payload.email, payload.password); +} + +export default function useSessionListeners(): void { + ipcMain.removeAllListeners("client-message"); + ipcMain.on("client-message", onSendMessage); +} \ No newline at end of file diff --git a/src/ipcRend/account.ts b/src/ipcRend/account.ts deleted file mode 100644 index 9300aa6..0000000 --- a/src/ipcRend/account.ts +++ /dev/null @@ -1,27 +0,0 @@ - -import { useIpc } from "@/modules/ipc"; -import { Profile } from "@/types"; - -const { invoke } = useIpc(); - -interface LoginPayload { - email: string; - password: string; -} - - -export const invokeProfile = async (): Promise => ( - await invoke('user-profile', null) -); - - -export const invokeLogin = async ( - payload: LoginPayload -): Promise => ( - await invoke('user-login', JSON.stringify(payload)) -); - - -export const invokeLogout = async (): Promise => ( - await invoke("user-logout", null) -); diff --git a/src/ipcRend/audio.ts b/src/ipcRend/audio.ts deleted file mode 100644 index 6f25d29..0000000 --- a/src/ipcRend/audio.ts +++ /dev/null @@ -1,15 +0,0 @@ - -import { useIpc } from "@/modules/ipc"; - - -const { post, invoke } = useIpc(); - - -export const postStartRecord = (): void => ( - post("start-recording", null) -); - - -export const invokeStopRecord = async (): Promise => ( - await invoke("stop-recording", null) -); diff --git a/src/ipcRend/session.ts b/src/ipcRend/session.ts deleted file mode 100644 index 2eb4405..0000000 --- a/src/ipcRend/session.ts +++ /dev/null @@ -1,23 +0,0 @@ - -import { useIpc } from "@/modules/ipc"; - -import { ClientMessage } from "@/types"; - -const { post } = useIpc(); - - -export const postMount = (): void => ( - post("app-mounted", null) -); - - -export const postInitSession = (cid: string): void => ( - post("init-session", cid) -); - - -export const postMessage = (payload: ClientMessage): void => ( - post('client-message', payload) -); - - diff --git a/src/main.ts b/src/main.ts index 68cc98e..744643d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,16 +1,72 @@ -// src/main.ts +/** + * Where the background logic really begins, gets called by app.onReady(). + * + * Handles authentication. If profile is set, we launch a session, which consis + * of opening a connection with the platform, initializing the audio streams. + * + * The session is primarily an interface between the frontend and the platform, + * relaying messages from one to the other. + * + */ -import App from "./App.vue"; +import { fetchAccount, submit } from "@/api/account"; +import { launchSession, endSession } from "@/session"; +import useIpc from "@/ipc/index"; +import store from "@/composables/store"; -import mitt from "mitt"; -import { createApp } from "vue"; -require('dotenv').config() +/* user profile, signals whether user is logged in */ +let auth: Profile | null = null; +/* authenticate the user */ +export async function authenticate(email: string, password: string) { -// Handle events. -const emitter = mitt(); + /* attempt normal login */ + try { + auth = await submit(email, password); + } catch (e) { + console.log(e); + } -const app = createApp(App) + /* launch if profile */ + if (auth) { + launchSession(auth); + } -app.provide("mitt", emitter) -app.mount("#app"); +} + +/* logout the user, end the session */ +export function deauthenticate() { + + /* set profile back to null */ + auth = null; + + /* terminate the session */ + endSession(); + +} + +export default async function main() { + + /* launch browser window */ + // await createWindow(); + + /* attempt key-based authentication with business api */ + const token = store.get('key', null); + const crimataId = store.get('crimataId', null); + + try { + const res = await fetchAccount(crimataId, token); + auth = parseAuthRes(res); + } catch (e) { + console.log('[MAIN]', e); + } + + /* connect to Crimata, or listen for manual login req */ + if (auth) { + launchSession(auth); + } + + /* initiate controls for frontend to use when needed */ + useIpc(); + +} \ No newline at end of file diff --git a/src/modules/message.ts b/src/modules/message.ts deleted file mode 100644 index 71beb70..0000000 --- a/src/modules/message.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - RenderMessage, - ClientMessage, - ClientRequest, - AuthRequest, - LogoutRequest -} from "@/types"; - -import { v4 as uuidv4 } from 'uuid'; - -function getTimeStamp(): number { - const currentdate = new Date(); - return currentdate.getTime(); -} - -// Create a RenderMessage object. -export const renderMessage = (text: boolean | string, audio: boolean | string, context: string, modifier: string): RenderMessage => ( - { - content: { - text: text, - audio: audio - }, - context: context, - modifier: modifier, - time: getTimeStamp(), - uid: uuidv4(), - isChild: "none", - seen: false, - newMessage: false - } -) - -export const clientMessage = (text: string, audio: string | boolean, uid: string): ClientMessage => ( - { - audio, - text, - uid - } -) - -export const clientRequest = (intent: string, params: object, epic: string | boolean): ClientRequest => ( - { - intent: intent, - params: params, - epic: epic, - confidence: 1.0 - } -) - -export const authRequest = (key: boolean | string, usr: boolean | string, pwd: boolean | string): AuthRequest => ( - { - key, - usr, - pwd - } -) - -export const logoutRequest = (): LogoutRequest => ( - { - logout: true - } -) \ No newline at end of file diff --git a/src/modules/messages.ts b/src/modules/messages.ts deleted file mode 100644 index 1d2c4b4..0000000 --- a/src/modules/messages.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { ref } from 'vue'; -import useScroll from "@/modules/scroll"; -import { RenderMessage, Annotation } from "@/types"; - -const messages = ref(new Map()); - -const addMessage = (message: RenderMessage) => { - messages.value.set(message.uid, message) -} - -const updateMessage = (annotation: Annotation) => { - const message = messages.value.get(annotation.uid) - message.context = annotation.context - message.content.text = annotation.text -} - -const loadSavedMessages = () => { - const rawData = window.localStorage.getItem("crimata_messages"); - if (rawData) { - const messageData = JSON.parse(rawData) - messages.value = new Map(Object.entries(messageData)); - } -} - -const saveMessages = () => { - const messageData = Object.fromEntries(messages.value); - window.localStorage.setItem("crimata_messages", JSON.stringify(messageData)); -} - -const isSimmilar = (messageA: RenderMessage, messageB: RenderMessage) => { - if ((Math.abs(messageA.time - messageB.time) < 20000) && (messageA.modifier == messageB.modifier) && (messageA.context == messageB.context)) { - return true - } - return false -} - -const updateGrouping = () => { - console.log("updating grouping") - const refs = Array.from(messages.value.keys()) - - // Get the last three messages. - const first = messages.value.get(refs[refs.length - 1]) - const second = messages.value.get(refs[refs.length - 2]) - const third = messages.value.get(refs[refs.length - 3]) - - // If messages are simmilar, update the classes. - if ((first) && (second)) { - if (isSimmilar(first, second)) { - first.isChild = "last" // i.e. last in group. - second.isChild = "first" - - if (third) { - if ((third.isChild == "first") || (third.isChild == "middle")) { - second.isChild = "middle" - } - } - } - } -} - - -export default function useMessages() { - - // Scroll controller. - const { setScroll, updateScrollRef, adjustScroll } = useScroll("messenger"); - - // Main function for updating the message view. - const updateMessageView = (message: RenderMessage | Annotation) => { - - // Step 1: See if user is scrolled down. - updateScrollRef() - - // Step 2: Add the new content to the view. - if ("content" in message) { - addMessage(message) - } else { - updateMessage(message) - } - - // Step 3: Pop off oldest message (if > 200). - if (messages.value.size >= 200) { - const oldest = Array.from(messages.value.keys()).shift(); - messages.value.delete(oldest); - } - - // Step 4: Update grouping. - updateGrouping() - - // Setp 5: Scroll the view (if scrolled down). - setTimeout(adjustScroll, 20); - - // Step 6: Save the view data. - saveMessages() - - } - - // Seed message view with message history. - const prepMessageView = (newMessages: RenderMessage[]) => { - console.log("MSGR:Prepping messenger view.") - - // Load and render saved messages and immediately scroll to bottom. - loadSavedMessages() - setTimeout(setScroll.bind(false), 10); - - // Render new messages, then wait 1s to scroll. - if (newMessages.length) { - - console.log("MSGR:Adding new messages") - - newMessages.forEach(message => { - message.newMessage = true; - addMessage(message) - }) - - setTimeout(setScroll.bind(true), 1000); - - } - } - - return { - messages, - prepMessageView, - updateMessageView - } -} \ No newline at end of file diff --git a/src/modules/mitt.ts b/src/modules/mitt.ts deleted file mode 100644 index 4f3f448..0000000 --- a/src/modules/mitt.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { inject } from "vue"; -import { Emitter } from "mitt"; - -// Frontend emitter - -type Mitt = Emitter; - -let emitter: Mitt; - -export default function useMitt() { - - const emitterInject: Mitt | undefined = inject("mitt"); - if (emitterInject) { - emitter = emitterInject; - } - return { - emitter - } -} \ No newline at end of file diff --git a/src/modules/scroll.ts b/src/modules/scroll.ts deleted file mode 100644 index 58370f7..0000000 --- a/src/modules/scroll.ts +++ /dev/null @@ -1,50 +0,0 @@ - - -export default function useScroll(element: string) { - - let isScrolledToBottom: boolean; - - // Set the initial scroll position. - const setScroll = (smooth: boolean) => { - const view = document.getElementById(element) - - if (view) { - view.scrollTo({ - top: view.scrollHeight - view.clientHeight, - behavior: (smooth) ? 'smooth' : 'auto' - }); - } - } - - // Update isScrolledToBottom - const updateScrollRef = () => { - const view = document.getElementById(element) - - if (view) { - isScrolledToBottom = view.scrollHeight - view.clientHeight <= view.scrollTop + 1 - } - - } - - // Adjust scroll after we add content to the messenger. - const adjustScroll = () => { - const view = document.getElementById(element) - - if (view) { - if (isScrolledToBottom) { - view.scrollTo({ - top: view.scrollHeight - view.clientHeight, - behavior: 'smooth' - }); - } - } - - } - - return { - updateScrollRef, - adjustScroll, - setScroll, - } - -} diff --git a/src/render/App.vue b/src/render/App.vue new file mode 100644 index 0000000..e5c477d --- /dev/null +++ b/src/render/App.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/render/components/bubble.vue b/src/render/components/bubble.vue new file mode 100644 index 0000000..6a62e62 --- /dev/null +++ b/src/render/components/bubble.vue @@ -0,0 +1,330 @@ + + + + + + + diff --git a/src/render/components/controllers/bubble.control.ts b/src/render/components/controllers/bubble.control.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/render/components/controllers/helpers.ts b/src/render/components/controllers/helpers.ts new file mode 100644 index 0000000..7509bf0 --- /dev/null +++ b/src/render/components/controllers/helpers.ts @@ -0,0 +1,102 @@ +import { ref } from "vue"; +import anime from "animejs"; +import { v4 as uuidv4 } from 'uuid'; + + +export function animateTextInput () { + + const side = ref("right"); + + function show () { + const t1 = (side.value === "right") ? 50 : -70; + const t2 = (side.value === "right") ? 110 : -130; + + anime({ + targets: '#textInput', + opacity: [0, 1], + translateX: [t1, t2], + scale: [0.3, 1], + duration: 500, + easing: 'easeOutExpo', + }) + + } + + function hide () { + const t = (side.value === "right") ? 50 : -80; + + anime({ + targets: '#textInput', + opacity: [1, 0], + translateX: t, + scale: 0.3, + duration: 500, + easing: 'easeOutExpo', + }) + + } + + function switchSide () { + const t = (side.value === "right") ? -130 : 110; + + anime({ + targets: '#textInput', + translateX: t, + duration: 500, + easing: 'easeOutExpo', + }) + + } + + return { + side, + show, + hide, + switchSide + }; + +} + +export function animateAudioInput () { + + function show () { + anime({ + targets: '#recIcon', + opacity: [0, 0.75], + scale: [0.0, 1], + duration: 250, + easing: 'linear', + }) + } + + function hide () { + anime({ + targets: '#recIcon', + opacity: [0.75, 0], + scale: [1, 0], + duration: 250, + easing: 'linear', + }) + } + + return { + show, + hide + }; + +} + + +export function newMessage ({ + text=false, + audio=false, + context=false, + uid=uuidv4() +}): Message { + return { + text: text, + audio: audio, + context: context, + uid: uid + }; +} diff --git a/src/render/components/controllers/inputItem.control.audio.ts b/src/render/components/controllers/inputItem.control.audio.ts new file mode 100644 index 0000000..b699405 --- /dev/null +++ b/src/render/components/controllers/inputItem.control.audio.ts @@ -0,0 +1,79 @@ +import anime from "animejs"; +import { useIpc } from '@/modules/ipc'; +import { onMounted, onUnmounted, ref, Ref } from "vue"; +import { postMessage } from "@/ipc/session"; +import { newMessage, animateAudioInput } from "./helpers"; +import { invokeStopRecord, postAudioChunk } from "@/ipc/audio"; + +export default function useAudioInputController (typing: Ref) { + + const recording = ref(false); + let mediaRecorder: MediaRecorder; + + const { show, hide } = animateAudioInput(); + + // initialize audio + const conf = {audio: true, video: false} + navigator.mediaDevices.getUserMedia(conf).then((stream: MediaStream) => { + + const options = {mimeType: 'audio/webm'}; + mediaRecorder = new MediaRecorder(stream, options); + + // post any mew audio to backend + mediaRecorder.addEventListener('dataavailable', (e: BlobEvent) => { + e.data.arrayBuffer().then((buff: ArrayBuffer) => { + postAudioChunk(buff); + }); + }); + + // get audio and post new message to backend + mediaRecorder.addEventListener('stop', (_e: Event) => { + invokeStopRecord().then((audio: ArrayBuffer[] | Error) => { + console.log(audio); + // postMessage(newMessage({audio: audio})); + }); + }); + + }); + + // start recording on space bar + const record = () => { + console.log("INPT:Capturing audio...") + mediaRecorder.start(); + recording.value = true; + show() + } + + // stop recording and send on release + const stop = () => { + console.log("INPT:Stopping record.") + mediaRecorder.stop(); + recording.value = false; + hide(); + } + + const onKeyDown = (e: KeyboardEvent) => { + if (e.keyCode == 32 && !typing.value) record(); + } + + const onKeyUp = (e: KeyboardEvent) => { + if (e.keyCode == 32 && recording.value) stop(); + } + + //----------------------------------------------------------- + + onMounted(() => { + window.addEventListener("keydown", onKeyDown); + window.addEventListener("keyup", onKeyUp); + }); + + onUnmounted(() => { + window.removeEventListener("keydown", onKeyDown); + window.removeEventListener("keyup", onKeyUp); + }) + + return { + recording + } + +} diff --git a/src/components/controllers/textCtrl.ts b/src/render/components/controllers/inputItem.control.text.ts similarity index 53% rename from src/components/controllers/textCtrl.ts rename to src/render/components/controllers/inputItem.control.text.ts index ced8aaf..21ada72 100644 --- a/src/components/controllers/textCtrl.ts +++ b/src/render/components/controllers/inputItem.control.text.ts @@ -1,72 +1,20 @@ -import anime from "animejs"; -import useMitt from "@/modules/mitt"; -import { useIpc } from '@/modules/ipc'; import { Ref, ref, watch, onMounted, onUnmounted } from "vue"; -import keyboardNameMap from "../keyBoardMaps/keyboardNameMap"; -import { clientMessage, renderMessage } from '@/modules/message'; -import { postMessage } from "@/ipcRend/session"; - - -//---Animations----------------------------------------------- - -let side = "right"; // Side of parent we are on. - -function showTextInput () { - const t1 = (side === "right") ? 50 : -70; - const t2 = (side === "right") ? 110 : -130; - - anime({ - targets: '#textInput', - opacity: [0, 1], - translateX: [t1, t2], - scale: [0.3, 1], - duration: 500, - easing: 'easeOutExpo', - }) - -} - -function hideTextInput() { - const t = (side === "right") ? 50 : -80; - - anime({ - targets: '#textInput', - opacity: [1, 0], - translateX: t, - scale: 0.3, - duration: 500, - easing: 'easeOutExpo', - }) - -} - -function switchSide(currentSide: string) { - const t = (currentSide === "right") ? -130 : 110; - - anime({ - targets: '#textInput', - translateX: t, - duration: 500, - easing: 'easeOutExpo', - }) - -} - -//------------------------------------------------------------ +import { postMessage } from "@/ipc/session"; +import { newMessage, animateTextInput } from "./helpers"; export default function useTextInputController(elementX: Ref) { + let textInput: HTMLInputElement | null; - const { post } = useIpc(); - const { emitter } = useMitt(); + const { side, show, hide, switchSide } = animateTextInput(); let firstKey = true; const typing = ref(false); // Prep inputItem for typing. const prepInput = () => { - showTextInput() + show() typing.value = true } @@ -78,7 +26,7 @@ export default function useTextInputController(elementX: Ref) { textInput.blur(); } - hideTextInput() + hide() firstKey = true; typing.value = false; } @@ -87,28 +35,20 @@ export default function useTextInputController(elementX: Ref) { const sendMessage = () => { if (textInput) { - // Create the message. - const message = renderMessage( - textInput.value, - false, - "", - "sf" - ) - - emitter.emit("self-message", message); - // Send it to the backend for processing. - const clientM = clientMessage(textInput.value, false, message.uid); - postMessage(clientM); + const message = newMessage({ + text: textInput.value + }); + + postMessage(message); clearInput() } } // Keys that are capable of opening the text input (numbers and letters). - const hotKeyRange = keyboardNameMap.slice(47, 91) - const isHotKey = (key: string) => { - if (hotKeyRange.includes(key)) { + const isHotKey = (key: number) => { + if (key >= 47 && key <= 91) { // a letter return true } } @@ -116,7 +56,7 @@ export default function useTextInputController(elementX: Ref) { //---Callbacks----------------------------------------------- const onKeyDown = (e: KeyboardEvent) => { - const key = keyboardNameMap[e.keyCode] + const key = e.keyCode; if (textInput) { @@ -133,18 +73,18 @@ export default function useTextInputController(elementX: Ref) { textInput.focus(); // Close input when no text or on ESC. - if ((textInput.value == "") && (!firstKey) && (key === "BACK_SPACE")) { + if ((textInput.value == "") && (!firstKey) && (key === 8)) { // backspace clearInput() return } - if (key === "ESCAPE") { + if (key === 27) { // escape clearInput() return } // Close and send on enter. - if (key === "ENTER") { + if (key === 13) { if (textInput.value) { sendMessage() return @@ -162,17 +102,17 @@ export default function useTextInputController(elementX: Ref) { const winW = window.innerWidth // Logic depends on the side we are on. - if (side === "right") { + if (side.value === "right") { if (winW - elementX < 230) { - switchSide(side) - side = "left" + switchSide() + side.value = "left" } } else { if (winW - elementX > 230) { - switchSide(side) - side = "right" + switchSide() + side.value = "right" } } diff --git a/src/render/components/controllers/messenger.control.ts b/src/render/components/controllers/messenger.control.ts new file mode 100644 index 0000000..63f15ee --- /dev/null +++ b/src/render/components/controllers/messenger.control.ts @@ -0,0 +1,143 @@ +import { ref } from 'vue'; +import invokeSavedMessages from "@/render/ipc"; +import useScroll from "@/render/composables/scroll"; + +const messages = ref(new Map()); + +function getTimeStamp(): number { + const currentdate = new Date(); + return currentdate.getTime(); +} + +const newViewMessage = (message: Message): ViewMessage => { + return { + text: message.text, + context: message.context, + audio: message.audio, + from: message.from, + uid: message.uid, + time: getTimeStamp(), + isChild: "none", + seen: false, + newMessage: false + }; +} + +const addMessage = (message: Message, newMessage=false) => { + const viewMessage = newViewMessage(message); + if (newMessage) viewMessage.newMessage = true; + messages.value.set(viewMessage.uid, viewMessage); +} + +const updateMessage = (message: Message) => { + const viewMessage = messages.value.get(message.uid); + viewMessage.context = message.context; + viewMessage.text = message.text; +} + +const loadSavedMessages = async () => { + const messageData = await invokeSavedMessages(); + messages.value = new Map(Object.entries(messageData)); +} + +const saveMessages = () => { + const messageData = Object.fromEntries(messages.value); + // must save to json. +} + +const pruneMessages = (limit=200) => { + if (messages.value.size >= limit) { + const oldest = Array.from(messages.value.keys()).shift(); + messages.value.delete(oldest); + } +} + +const updateGrouping = () => { + + const isSimmilar = (messageA: ViewMessage, messageB: ViewMessage) => { + if ((Math.abs(messageA.time - messageB.time) < 20000) && (messageA.from == messageB.from) && (messageA.context == messageB.context)) { + return true + } + return false + } + + const refs = Array.from(messages.value.keys()) + + // Get the last three messages. + const first = messages.value.get(refs[refs.length - 1]) + const second = messages.value.get(refs[refs.length - 2]) + const third = messages.value.get(refs[refs.length - 3]) + + // If messages are simmilar, update the classes. + if ((first) && (second)) { + if (isSimmilar(first, second)) { + first.isChild = "last" // i.e. last in group. + second.isChild = "first" + + if (third) { + if ((third.isChild == "first") || (third.isChild == "middle")) { + second.isChild = "middle" + } + } + } + } +} + +export default function useMessages() { + + const { updateScrollRef, adjustScroll } = useScroll("messenger"); + + /* Given new message object, update the view accordingly */ + const updateMessageView = (newMessages: Message[]) => { + + const bottom = updateScrollRef(); // see if the user is scrolled down + + // take each message and apply view + newMessages.forEach((message: Message) => { + + // add or update message depending + if (messages.value.has(message.uid)) { + updateMessage(message); + } else addMessage(message); + + pruneMessages(); // pop off old messages from view + updateGrouping(); // group like message together + + if (bottom) adjustScroll(); // only scroll if user was at bottom + + saveMessages(); + + }); + + } + + return { + messages, + updateMessageView, + loadSavedMessages + } + +} + + + // // Seed message view with message history. + // const prepMessageView = async (newMessages: Message[]) => { + // console.log("MSGR:Prepping messenger view.") + + // // Load and render saved messages and immediately scroll to bottom. + // await loadSavedMessages(); + // setTimeout(setScroll.bind(false), 10); + + // // Render new messages, then wait 1s to scroll. + // if (newMessages.length) { + + // console.log("MSGR:Adding new messages") + + // newMessages.forEach(message => { + // addMessage(message, true); + // }) + + // setTimeout(setScroll.bind(true), 1000); + + // } + // } \ No newline at end of file diff --git a/src/render/components/header.vue b/src/render/components/header.vue new file mode 100644 index 0000000..f0afc8a --- /dev/null +++ b/src/render/components/header.vue @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/src/components/inputItem.vue b/src/render/components/inputItem.vue similarity index 87% rename from src/components/inputItem.vue rename to src/render/components/inputItem.vue index 861d7c1..30978b3 100644 --- a/src/components/inputItem.vue +++ b/src/render/components/inputItem.vue @@ -13,7 +13,10 @@ - + @@ -29,9 +32,9 @@ import draggify from "@/modules/draggify"; import TextInput from "@/components/textInput.vue"; import useTextInputController from - "@/components/controllers/textCtrl"; + "@/components/controllers/inputItem.control.audio"; import useAudioInputController from - "@/components/controllers/audioCtrl"; + "@/components/controllers/inputItem.control.text"; export default defineComponent({ name: "InputItem", @@ -191,4 +194,32 @@ export default defineComponent({ } } +#textInput { + position: absolute; + + opacity: 0; + + min-width: 150px; + height: 16px; + + border-radius: 18px; + + padding: 10px; + margin-right: 10px; + margin-left: 10px; + + outline: none; + border: none; + pointer-events: none; + + background-color: white; + + z-index: -1; + + box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.15); + + transform: translateX(50px) scale(0.3); + +} + diff --git a/src/components/login.vue b/src/render/components/login.vue similarity index 89% rename from src/components/login.vue rename to src/render/components/login.vue index 2cb82f8..5ed0ad0 100644 --- a/src/components/login.vue +++ b/src/render/components/login.vue @@ -39,7 +39,6 @@ import { useIpc } from "@/modules/ipc"; import { authRequest } from '@/modules/message'; import { useProfile } from '@/modules/auth'; import { invokeLogin } from "@/ipcRend/account"; -import { Profile } from "@/types"; import { postInitSession } from "@/ipcRend/session"; export default defineComponent({ @@ -47,8 +46,6 @@ export default defineComponent({ setup() { - const { profile, setProfile } = useProfile(); - const usr = ref(""); const pwd = ref(""); @@ -56,23 +53,17 @@ export default defineComponent({ const submitForm = async () => { try { + const profile = await invokeLogin({ email: usr.value, password: pwd.value - }) as Profile; + }); - setProfile(profile); + /* emit event to app.vue */ + window.postMessage(profile); - } catch(e) { - console.log('Error login in.') - } finally{ + } catch (e) console.log(e); - if (profile.value.crimataId) { - // start session - postInitSession(profile.value.crimataId); - } - - } } return { diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue new file mode 100644 index 0000000..77d54f3 --- /dev/null +++ b/src/render/components/messenger.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/src/components/settings.vue b/src/render/components/settings.vue similarity index 100% rename from src/components/settings.vue rename to src/render/components/settings.vue diff --git a/src/components/splash.vue b/src/render/components/splash.vue similarity index 100% rename from src/components/splash.vue rename to src/render/components/splash.vue diff --git a/src/modules/auth.ts b/src/render/composables/auth.ts similarity index 90% rename from src/modules/auth.ts rename to src/render/composables/auth.ts index 5fb40c1..dea4bd1 100644 --- a/src/modules/auth.ts +++ b/src/render/composables/auth.ts @@ -1,6 +1,4 @@ import { ref } from "vue"; -import { Profile } from "@/types"; - const profile = ref(); diff --git a/src/modules/draggify.ts b/src/render/composables/draggify.ts similarity index 100% rename from src/modules/draggify.ts rename to src/render/composables/draggify.ts diff --git a/src/modules/ipc.ts b/src/render/composables/ipc.ts similarity index 91% rename from src/modules/ipc.ts rename to src/render/composables/ipc.ts index 36658de..0d067d3 100644 --- a/src/modules/ipc.ts +++ b/src/render/composables/ipc.ts @@ -1,5 +1,5 @@ -export const useIpc = () => { +export default function useIpc () { const invoke = async (endpoint: string, payload: any) => { try { diff --git a/src/render/composables/scroll.ts b/src/render/composables/scroll.ts new file mode 100644 index 0000000..811e7fc --- /dev/null +++ b/src/render/composables/scroll.ts @@ -0,0 +1,29 @@ + + +export default function useScroll(element: string) { + + let isScrolledToBottom: boolean; + const view = document.getElementById(element) + + // Update isScrolledToBottom + const updateScrollRef = () => { + if (view) isScrolledToBottom = view.scrollHeight - view.clientHeight <= view.scrollTop + 1; + return isScrolledToBottom; + } + + // Adjust scroll after we add content to the messenger. + const adjustScroll = () => { + if (view) { + view.scrollTo({ + top: view.scrollHeight - view.clientHeight, + behavior: 'smooth' + }); + } + } + + return { + updateScrollRef, + adjustScroll, + }; + +} \ No newline at end of file diff --git a/src/render/ipc.ts b/src/render/ipc.ts new file mode 100644 index 0000000..a232f7f --- /dev/null +++ b/src/render/ipc.ts @@ -0,0 +1,52 @@ + +import useIpc from "@/render/composables/ipc"; + +const { post, invoke } = useIpc(); + +/** + * + * Account and auth related endpoints + * + */ + +export const invokeProfile = async (): Promise => ( + await invoke('user-profile', null) +); + +export const invokeLogin = async ( + payload: LoginPayload +): Promise => ( + await invoke('user-login', JSON.stringify(payload)) +); + +export const invokeLogout = async (): Promise => ( + await invoke("user-logout", null) +); + +/** + * + * Audio endpoints + * + */ + +export const postAudioChunk = (chunk: ArrayBuffer): void => ( + post("audio-chunk", chunk) +); + +export const invokeReturnAudio = async (): Promise => ( + await invoke("get-audio", null) +); + +/** + * + * Crimata Platform (session) endpoints + * + */ + +export const invokeSession = async (cid: string): Promise => ( + await invoke("messenger-init", cid) +); + +export const postMessage = (payload: Message): void => ( + post('client-message', payload) +); \ No newline at end of file diff --git a/src/preload.ts b/src/render/preload.ts similarity index 100% rename from src/preload.ts rename to src/render/preload.ts diff --git a/src/shims-vue.d.ts b/src/render/shims-vue.d.ts similarity index 100% rename from src/shims-vue.d.ts rename to src/render/shims-vue.d.ts diff --git a/src/session.ts b/src/session.ts new file mode 100644 index 0000000..0a893d8 --- /dev/null +++ b/src/session.ts @@ -0,0 +1,64 @@ + + + + +import useAudio from "@/audio"; +import { loadState, saveState, emitState } from "@/state"; + +/* start and stop audio functionality */ +const { initAudio, closeAudio } = useAudio(); + +/** + * Controls for interfacing with the platform. + * Takes an onMessage callback which we define below. + */ +const { connect, send, close } = usePlatform((message: Message) => { + + /* add the message to the state */ + addMessage(message); + + /* push the message to the browser */ + if (win) emit("new-message", message); + +}); + +/* send a message to the platform */ +export function sendMessage(message: Message) { + + /* add the message to the state */ + addMessage(message); + + /* push the message to the browser */ + if (win) emit("new-message", message); + + /* socket send */ + send(message); + +} + +/* launch a new session (the main process for authenticated users) */ +export function launchSession(profile: Profile) { + + /* load any previously saved state for that user */ + loadState(profile); + + /* connect to the platform */ + connect(profile); + + /* initialize the audio streams */ + // initAudio(); + + /* finally we can push state to browser */ + if (win) emitState(); + +} + +export function endSession() { + + closeAudioStreams(); + + closeSocket(); + + state.clear(); + +} \ No newline at end of file diff --git a/src/state.ts b/src/state.ts new file mode 100644 index 0000000..1d6ce02 --- /dev/null +++ b/src/state.ts @@ -0,0 +1,29 @@ +const Store = require('electron-store'); + +/* simple data persistance */ +const store = new Store; + +/* state of the session (e.g. profile and messages for now) */ +let state: State | null = null; + +/* load saved state in electron store for given user */ +export function loadState(profile: Profile) { + state = store.get("state", null); +} + +/* add a message to state.messages */ +export function addMessage(message: Message) { + if (state) { + state.messages.push(message); + saveState(); + } +} + +export function saveState() { + store.set("state", state); +} + +export function emitState() { + emit("update-state", state); +} + diff --git a/src/types.ts b/src/types.ts index 2e35fc5..b437ffa 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,76 +1,37 @@ -export interface RenderMessage { - content: { - text: boolean | string; - audio: boolean | string; - }; - context: string; - modifier: string; +interface Message { + text: boolean | string; + context: boolean | string; + audio: boolean | string; + type: 1 | 2 | 3; time: number; uid: string; - isChild: string; +} + +interface ViewMessage extends Message { + child: string; seen: boolean; newMessage: boolean; } -export interface ClientMessage { - text: string; - audio: boolean | string; - uid: string; -} - -export interface ClientRequest { - intent: string; - params: object; - epic: string | boolean; - confidence: number; -} - -export interface SessionState { - key: string | boolean; - newMessages: RenderMessage[]; -} - -export interface WindowState { +interface WindowState { width: number; height: number; x: number | null; y: number | null; } -export interface AuthRequest { - key: boolean | string; - usr: boolean | string; - pwd: boolean | string; -} - -export interface Profile { +interface Profile { crimataId: string; alias: string; initials: string; } -export interface AuthProtocol { - token: null | string; - profile: null | Profile; - password?: string; - email?: string; +interface State { + profile: Profile | null; + messages } -export interface LogoutRequest { - logout: boolean; -} - -export interface Annotation { - text: string; - context: string; - uid: string; -} - -export interface StandardMessage { - content: { - text: boolean | string; - audio: boolean | string; - }; - context: string; - modifier: string; +interface LoginPayload { + email: string; + password: string; } diff --git a/src/background/window.ts b/src/window.ts similarity index 86% rename from src/background/window.ts rename to src/window.ts index 162b3e1..4c69387 100644 --- a/src/background/window.ts +++ b/src/window.ts @@ -2,20 +2,39 @@ import { BrowserWindow, ipcMain } from "electron"; import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; -import { backgroundMitt } from '@/modules/emitter'; -import { RenderMessage, WindowState } from "@/types"; -import { loadWinState, saveToJson } from "./helpers"; +import { backgroundMitt } from './coposables/emitter'; +import { saveToJson } from "./coposables/json"; import * as path from "path"; const { autoUpdater } = require('electron-updater'); interface IpcRendererPayload { endpoint: string; - message: RenderMessage | null; + message: Message | null; } let win: BrowserWindow | null; let winState: WindowState; +const loadWinState = (fileName: string): WindowState => { + let state: WindowState; + + try { + state = JSON.parse(fs.readFileSync(configPath + fileName).toString()); + } + + catch (error) { + state = { + width: 600, + height: 500, + x: null, + y: null, + } + } + + return state + +} + // Called when a NavBar button is pressed. const onNavBar = (_event: any, action: string): void => { if (win) { @@ -78,7 +97,7 @@ const onWindowDismount = (): void => { } // function used by run.ts to create the main window. -export async function createWindow(): Promise { +export default async function createWindow(): Promise { return new Promise((resolve, _reject) => { // avoid creating duplicate windows. diff --git a/tsconfig.json b/tsconfig.json index 307539b..5a01f4d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,6 +32,7 @@ ] }, "include": [ + "**/*.ts", "src/*.ts", "src/**/*.ts", "src/**/*.tsx", From 9e8641b4def1a49c8e607475b1dfe1d8a2176b4f Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Sat, 12 Jun 2021 09:49:41 -0500 Subject: [PATCH 56/66] more changes --- src/api/account.ts | 27 +++- src/composables/canvas.ts | 36 +++++ src/composables/store.ts | 16 -- src/composables/websockets.ts | 54 +++---- src/main.ts | 60 ++++---- src/render/App.vue | 12 +- .../controllers/messenger.control.ts | 139 +++--------------- src/render/components/messenger.vue | 20 ++- src/session.ts | 58 ++++---- src/state.ts | 29 ---- src/types.ts | 7 - 11 files changed, 170 insertions(+), 288 deletions(-) create mode 100644 src/composables/canvas.ts delete mode 100644 src/composables/store.ts delete mode 100644 src/state.ts diff --git a/src/api/account.ts b/src/api/account.ts index de1335b..98d3c69 100644 --- a/src/api/account.ts +++ b/src/api/account.ts @@ -4,20 +4,33 @@ import axios from "axios"; const { post } = useHttp(); -export const submit = async (email: string, password: string) => ( - await post('/account/login', { email, password }) -) +export const usrPwdAuth = async (email: string, password: string) => { -export const fetchAccount = async (email: string, token: string) => ( - await axios({ + try { + return await post('/account/login', { email, password }) + + } catch (e) { + return null; + } + +} + +export const tokenAuth = async (cid: string, token: string) => { + + try { + return await axios({ url: "http://127.0.0.1:3000/api/account/profile", headers: { Cookie: `jwt=${token}` }, method: 'GET', data: { - email, + cid, } }) -) + } catch (e) { + return null; + } + +} \ No newline at end of file diff --git a/src/composables/canvas.ts b/src/composables/canvas.ts new file mode 100644 index 0000000..c85f7ed --- /dev/null +++ b/src/composables/canvas.ts @@ -0,0 +1,36 @@ + + + +export default class Canvas { + + messages: Message[]; + + /* seed canvas with messages on init */ + constructor(messages: Message[]) { + this.messages = messages; + ipcEmit("seed-view", this.messages); + } + + /* add a new message to the canvas */ + add(message: Message) { + this.messages.push(message); + ipcEmit("update-view", message); + } + + /* update an existing message */ + update(message: Message) { + + /* get the target message */ + let target_message = this.messages.filter((m: Message) => { + return m.uid = message.uid; + })[0]; + + /* replace the target message */ + if (target_message) { + target_message = message; + ipcEmit("update-view", message); + } + + } + +} diff --git a/src/composables/store.ts b/src/composables/store.ts deleted file mode 100644 index 16f8409..0000000 --- a/src/composables/store.ts +++ /dev/null @@ -1,16 +0,0 @@ - -const Store = require('electron-store'); - -const schema = { - key: { - type: 'string', - }, - crimataId: { - type: 'string' - } -}; - -export const store = new Store({ - schema, - encryptionKey: "super user test" -}); diff --git a/src/composables/websockets.ts b/src/composables/websockets.ts index 779f00b..d034027 100644 --- a/src/composables/websockets.ts +++ b/src/composables/websockets.ts @@ -3,7 +3,7 @@ import WebSocket from 'ws'; -export default function useWebSockets(receiveCallback: (s: string) => void, openCallback?: () => void) { +export default function useWebSockets(onMessageCallback: (s: string) => void) { let socket: WebSocket | null = null; @@ -19,36 +19,25 @@ export default function useWebSockets(receiveCallback: (s: string) => void, open }); } - const onOpen = (_event: WebSocket.OpenEvent) => { - console.log("WS:Connected to WS Server!"); - if (openCallback) openCallback(); - } - - const onServerMessage = (event: WebSocket.MessageEvent) => { - console.log("WS:Message received: ", event.data); - receiveCallback(event.data.toString()) - } - - const onClose = (event: WebSocket.CloseEvent) => { - console.log("WS:Socket closed normally.") - } - - // Reconnect automatically on error. - const onError = (event: WebSocket.ErrorEvent) => { - console.log("WS:WebSocket error: ", event.message); - console.log("Attempting reconnect in 1s.") - setTimeout(createSocket, 1000); - } - - const createSocket = (socketUrl: string) => { + const connect = (socketUrl: string, secret: string) => { + /* create a new socket */ socket = new WebSocket(socketUrl) - // Add listeners. - socket.addEventListener("open", onOpen); - socket.addEventListener("message", onServerMessage); - socket.addEventListener("close", onClose); - socket.addEventListener("error", onError); + /* add event listeners */ + + socket.on("open", () => { + if (socket) + socket.send(secret); + }); + + socket.on("message", (event: WebSocket.MessageEvent) => { + onMessageCallback(event.data.toString()) + }); + + socket.on("close", () => { + return + }); } @@ -59,15 +48,10 @@ export default function useWebSockets(receiveCallback: (s: string) => void, open } } - const checkConnection = () => { - return true; - } - return { - createSocket, + connect, send, - close, - checkConnection + close }; } diff --git a/src/main.ts b/src/main.ts index 744643d..9d6414c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,37 +9,29 @@ * */ -import { fetchAccount, submit } from "@/api/account"; +import { tokenAuth, usrPwdAuth } from "@/api/account"; import { launchSession, endSession } from "@/session"; import useIpc from "@/ipc/index"; import store from "@/composables/store"; -/* user profile, signals whether user is logged in */ -let auth: Profile | null = null; - /* authenticate the user */ export async function authenticate(email: string, password: string) { /* attempt normal login */ - try { - auth = await submit(email, password); - } catch (e) { - console.log(e); - } + const platformKey, token, crimataId = await usrPwdAuth(email, password); - /* launch if profile */ - if (auth) { - launchSession(auth); - } + /* launch if successful */ + if (platformKey) + launchSession(platformKey, crimataId); + + /* save the token */ + store.set("token", token); } /* logout the user, end the session */ export function deauthenticate() { - /* set profile back to null */ - auth = null; - /* terminate the session */ endSession(); @@ -47,26 +39,24 @@ export function deauthenticate() { export default async function main() { - /* launch browser window */ - // await createWindow(); - - /* attempt key-based authentication with business api */ - const token = store.get('key', null); - const crimataId = store.get('crimataId', null); - - try { - const res = await fetchAccount(crimataId, token); - auth = parseAuthRes(res); - } catch (e) { - console.log('[MAIN]', e); - } - - /* connect to Crimata, or listen for manual login req */ - if (auth) { - launchSession(auth); - } - /* initiate controls for frontend to use when needed */ useIpc(); + /* launch browser window */ + await createWindow(); + + /* attempt to get a login token from the store */ + const token = store.get("token"); + + /* try to login with it, returns platform secret and new token on success */ + if (token) + const newToken, profile = await tokenAuth(token); + + /* if secret, we launch a session */ + if (newToken) + launchSession(newToken, profile); + + /* finally, save the most recent token */ + store.set("token", newToken); + } \ No newline at end of file diff --git a/src/render/App.vue b/src/render/App.vue index e5c477d..d90bcc0 100644 --- a/src/render/App.vue +++ b/src/render/App.vue @@ -6,8 +6,9 @@ @@ -39,13 +40,13 @@ export default defineComponent({ setup() { - const state: Ref; + const crimataId = ref(false); onMounted(async () => { console.log("[APP]:mounted."); /* listen for auth related messages */ - window.addEventListener("update-state", (event: any) => { + window.addEventListener("update-auth", (event: any) => { state.value = event.data; }); @@ -56,7 +57,7 @@ export default defineComponent({ }); return { - profile + crimataId } } }) @@ -68,7 +69,6 @@ export default defineComponent({ html, body { margin: 0; padding: 0; - // Background color set in window.ts } #app { diff --git a/src/render/components/controllers/messenger.control.ts b/src/render/components/controllers/messenger.control.ts index 63f15ee..9ae7d47 100644 --- a/src/render/components/controllers/messenger.control.ts +++ b/src/render/components/controllers/messenger.control.ts @@ -1,143 +1,38 @@ import { ref } from 'vue'; -import invokeSavedMessages from "@/render/ipc"; import useScroll from "@/render/composables/scroll"; -const messages = ref(new Map()); +const canvas = ref(); -function getTimeStamp(): number { - const currentdate = new Date(); - return currentdate.getTime(); +/* seed the canvas with messages */ +const seedCanvas = (messages: Message[]) => { + canvas.value = messages; } -const newViewMessage = (message: Message): ViewMessage => { - return { - text: message.text, - context: message.context, - audio: message.audio, - from: message.from, - uid: message.uid, - time: getTimeStamp(), - isChild: "none", - seen: false, - newMessage: false - }; -} - -const addMessage = (message: Message, newMessage=false) => { - const viewMessage = newViewMessage(message); - if (newMessage) viewMessage.newMessage = true; - messages.value.set(viewMessage.uid, viewMessage); +const addMessage = (message: Message) => { + canvas.value.push(message); } const updateMessage = (message: Message) => { - const viewMessage = messages.value.get(message.uid); - viewMessage.context = message.context; - viewMessage.text = message.text; -} -const loadSavedMessages = async () => { - const messageData = await invokeSavedMessages(); - messages.value = new Map(Object.entries(messageData)); -} + let target_message = canvas.value.filter((m: Message) => { + return m.uid = message.uid; + })[0]; -const saveMessages = () => { - const messageData = Object.fromEntries(messages.value); - // must save to json. -} - -const pruneMessages = (limit=200) => { - if (messages.value.size >= limit) { - const oldest = Array.from(messages.value.keys()).shift(); - messages.value.delete(oldest); - } -} - -const updateGrouping = () => { - - const isSimmilar = (messageA: ViewMessage, messageB: ViewMessage) => { - if ((Math.abs(messageA.time - messageB.time) < 20000) && (messageA.from == messageB.from) && (messageA.context == messageB.context)) { - return true - } - return false + if (target_message) { + target_message = message; } - const refs = Array.from(messages.value.keys()) - - // Get the last three messages. - const first = messages.value.get(refs[refs.length - 1]) - const second = messages.value.get(refs[refs.length - 2]) - const third = messages.value.get(refs[refs.length - 3]) - - // If messages are simmilar, update the classes. - if ((first) && (second)) { - if (isSimmilar(first, second)) { - first.isChild = "last" // i.e. last in group. - second.isChild = "first" - - if (third) { - if ((third.isChild == "first") || (third.isChild == "middle")) { - second.isChild = "middle" - } - } - } - } } export default function useMessages() { const { updateScrollRef, adjustScroll } = useScroll("messenger"); - /* Given new message object, update the view accordingly */ - const updateMessageView = (newMessages: Message[]) => { - - const bottom = updateScrollRef(); // see if the user is scrolled down - - // take each message and apply view - newMessages.forEach((message: Message) => { - - // add or update message depending - if (messages.value.has(message.uid)) { - updateMessage(message); - } else addMessage(message); - - pruneMessages(); // pop off old messages from view - updateGrouping(); // group like message together - - if (bottom) adjustScroll(); // only scroll if user was at bottom - - saveMessages(); - - }); - - } - return { - messages, - updateMessageView, - loadSavedMessages - } + canvas, + seedCanvas, + addMessage, + updateMessage + }; -} - - - // // Seed message view with message history. - // const prepMessageView = async (newMessages: Message[]) => { - // console.log("MSGR:Prepping messenger view.") - - // // Load and render saved messages and immediately scroll to bottom. - // await loadSavedMessages(); - // setTimeout(setScroll.bind(false), 10); - - // // Render new messages, then wait 1s to scroll. - // if (newMessages.length) { - - // console.log("MSGR:Adding new messages") - - // newMessages.forEach(message => { - // addMessage(message, true); - // }) - - // setTimeout(setScroll.bind(true), 1000); - - // } - // } \ No newline at end of file +} \ No newline at end of file diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue index 77d54f3..4ea2d5b 100644 --- a/src/render/components/messenger.vue +++ b/src/render/components/messenger.vue @@ -11,6 +11,7 @@ v-for="message in messages" :text="message.text" :context="message.context" + :child :key="message[0]" /> @@ -28,7 +29,7 @@ import useMessages from "@/render/composables/messages"; export default defineComponent({ name: "Messenger", - props: ["state"], + props: ["profile", "messages"], components: { Message, @@ -43,12 +44,19 @@ export default defineComponent({ onMounted(() => { - /* populate the message view with existing messages */ - updateMessageView(state.savedMessages, state.newMessages); + /* seed messages */ + window.ipcRenderer.on("init-messages", (e_: any, payload: any) => { + seedMessages(payload.messages); + }); - /* wait and listen for new messages to come in */ - window.ipcRenderer.on("new-message", (_e: any, payload: any) => { - updateMessageView(payload.message); + /* add a new message */ + window.ipcRenderer.on("add-message", (_e: any, payload: any) => { + addMessage(payload.message); + }); + + /* update an existing message */ + window.ipcRenderer.on("update-message", (_e: any, payload: any) => { + updateMessage(payload.message); }); }); diff --git a/src/session.ts b/src/session.ts index 0a893d8..afebe5b 100644 --- a/src/session.ts +++ b/src/session.ts @@ -3,7 +3,11 @@ import useAudio from "@/audio"; -import { loadState, saveState, emitState } from "@/state"; +import Canvas from "@/composables/convas"; +import ipcEmit from "@/composables/emitter"; + +/* data structure of messages that's tied to the UI */ +let msgrState: UIState | null = null; /* start and stop audio functionality */ const { initAudio, closeAudio } = useAudio(); @@ -12,53 +16,57 @@ const { initAudio, closeAudio } = useAudio(); * Controls for interfacing with the platform. * Takes an onMessage callback which we define below. */ -const { connect, send, close } = usePlatform((message: Message) => { +const { connect, send, close } = useWebsockets((content: any) => { - /* add the message to the state */ - addMessage(message); + /* if the platform fails to authenticate, we must back down */ + if (content === "auth_error") { + deauthenticate(); + return; + } - /* push the message to the browser */ - if (win) emit("new-message", message); + /* on init, platform sends state, used to init canvas */ + if (isInitMessage(content)) { + uiState.set(content); + } + + + else if (isAddMessage(content)) { + uiState.add(content); + } + + else { + uiState.update(content); + } }); /* send a message to the platform */ export function sendMessage(message: Message) { - /* add the message to the state */ - addMessage(message); - - /* push the message to the browser */ - if (win) emit("new-message", message); - /* socket send */ send(message); } /* launch a new session (the main process for authenticated users) */ -export function launchSession(profile: Profile) { - - /* load any previously saved state for that user */ - loadState(profile); +export function launchSession(platformKey: string, crimata_id: string) { /* connect to the platform */ - connect(profile); + connect(PLATFORM_URL, platformKey); /* initialize the audio streams */ - // initAudio(); + initAudio(); - /* finally we can push state to browser */ - if (win) emitState(); + /* push profile to window */ + if (win) + ipcEmit("update-auth", crimata_id); } export function endSession() { - closeAudioStreams(); + closeAudio(); - closeSocket(); + close(); - state.clear(); - -} \ No newline at end of file +} diff --git a/src/state.ts b/src/state.ts deleted file mode 100644 index 1d6ce02..0000000 --- a/src/state.ts +++ /dev/null @@ -1,29 +0,0 @@ -const Store = require('electron-store'); - -/* simple data persistance */ -const store = new Store; - -/* state of the session (e.g. profile and messages for now) */ -let state: State | null = null; - -/* load saved state in electron store for given user */ -export function loadState(profile: Profile) { - state = store.get("state", null); -} - -/* add a message to state.messages */ -export function addMessage(message: Message) { - if (state) { - state.messages.push(message); - saveState(); - } -} - -export function saveState() { - store.set("state", state); -} - -export function emitState() { - emit("update-state", state); -} - diff --git a/src/types.ts b/src/types.ts index b437ffa..e8682b8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,8 +9,6 @@ interface Message { interface ViewMessage extends Message { child: string; - seen: boolean; - newMessage: boolean; } interface WindowState { @@ -26,11 +24,6 @@ interface Profile { initials: string; } -interface State { - profile: Profile | null; - messages -} - interface LoginPayload { email: string; password: string; From d851db2fccf166927d862756eb7ecaf0db3934d3 Mon Sep 17 00:00:00 2001 From: riqo Date: Mon, 14 Jun 2021 08:52:01 -0500 Subject: [PATCH 57/66] update sockets, account, auth --- build/config.gypi | 79 ------------------- package.json | 4 +- public/index.html | 6 +- src/account.ts | 105 +++++++++++++++++++++++++ src/api/account.ts | 49 ++++++------ src/auth.ts | 13 ++++ src/composables/http.ts | 7 +- src/composables/ipcHandler.ts | 50 ++++++++++++ src/composables/json.ts | 10 ++- src/composables/store.ts | 19 +++++ src/composables/websockets.ts | 49 +++++++++--- src/config.ts | 17 +++++ src/init.ts | 4 +- src/ipc/account.ts | 140 ++++++---------------------------- src/ipc/index.ts | 23 +++++- src/ipc/session.ts | 6 +- src/main.ts | 60 +++++---------- src/session.ts | 49 +++++++----- src/types.ts | 23 ++++++ src/window.ts | 20 ++--- 20 files changed, 409 insertions(+), 324 deletions(-) delete mode 100644 build/config.gypi create mode 100644 src/account.ts create mode 100644 src/auth.ts create mode 100644 src/composables/ipcHandler.ts create mode 100644 src/composables/store.ts create mode 100644 src/config.ts diff --git a/build/config.gypi b/build/config.gypi deleted file mode 100644 index 6f84ed7..0000000 --- a/build/config.gypi +++ /dev/null @@ -1,79 +0,0 @@ -# Do not edit. File was generated by node-gyp's "configure" step -{ - "target_defaults": { - "cflags": [], - "default_configuration": "Release", - "defines": [], - "include_dirs": [], - "libraries": [] - }, - "variables": { - "asan": 0, - "build_v8_with_gn": "false", - "coverage": "false", - "dcheck_always_on": 0, - "debug_nghttp2": "false", - "debug_node": "false", - "enable_lto": "false", - "enable_pgo_generate": "false", - "enable_pgo_use": "false", - "error_on_warn": "false", - "force_dynamic_crt": 0, - "host_arch": "x64", - "icu_data_in": "../../deps/icu-tmp/icudt67l.dat", - "icu_endianness": "l", - "icu_gyp_path": "tools/icu/icu-generic.gyp", - "icu_path": "deps/icu-small", - "icu_small": "false", - "icu_ver_major": "67", - "is_debug": 0, - "llvm_version": "0.0", - "napi_build_version": "6", - "node_byteorder": "little", - "node_debug_lib": "false", - "node_enable_d8": "false", - "node_install_npm": "true", - "node_module_version": 83, - "node_no_browser_globals": "false", - "node_prefix": "/", - "node_release_urlbase": "https://nodejs.org/download/release/", - "node_shared": "false", - "node_shared_brotli": "false", - "node_shared_cares": "false", - "node_shared_http_parser": "false", - "node_shared_libuv": "false", - "node_shared_nghttp2": "false", - "node_shared_openssl": "false", - "node_shared_zlib": "false", - "node_tag": "", - "node_target_type": "executable", - "node_use_bundled_v8": "true", - "node_use_dtrace": "true", - "node_use_etw": "false", - "node_use_node_code_cache": "true", - "node_use_node_snapshot": "true", - "node_use_openssl": "true", - "node_use_v8_platform": "true", - "node_with_ltcg": "false", - "node_without_node_options": "false", - "openssl_fips": "", - "openssl_is_fips": "false", - "shlib_suffix": "83.dylib", - "target_arch": "x64", - "v8_enable_31bit_smis_on_64bit_arch": 0, - "v8_enable_gdbjit": 0, - "v8_enable_i18n_support": 1, - "v8_enable_inspector": 1, - "v8_enable_pointer_compression": 0, - "v8_no_strict_aliasing": 1, - "v8_optimized_debug": 1, - "v8_promise_internal_field_count": 1, - "v8_random_seed": 0, - "v8_trace_maps": 0, - "v8_use_siphash": 1, - "want_separate_host_toolset": 0, - "xcode_version": "11.0", - "nodedir": "/Users/Enrique/Library/Caches/node-gyp/14.4.0", - "standalone_static_library": 1 - } -} diff --git a/package.json b/package.json index 38c1348..2b4b7fd 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "postinstall": "electron-builder install-app-deps", "postuninstall": "electron-builder install-app-deps" }, - "main": "background.js", + "main": "init.js", "dependencies": { "@google-cloud/speech": "^4.2.0", "@types/animejs": "^3.1.2", @@ -73,7 +73,7 @@ "lintOnSave": false, "pluginOptions": { "electronBuilder": { - "preload": "src/preload.ts", + "preload": "src/renderer/preload.ts", "builderOptions": { "appId": "com.crimata.ElectronUpdaterApp", "artifactName": "${productName}-${version}.${ext}", diff --git a/public/index.html b/public/index.html index 48809d8..8f79d27 100644 --- a/public/index.html +++ b/public/index.html @@ -11,11 +11,7 @@ - -
+
diff --git a/src/account.ts b/src/account.ts new file mode 100644 index 0000000..4884135 --- /dev/null +++ b/src/account.ts @@ -0,0 +1,105 @@ + +import { postAuth, postLogin, postLogout } from "@/api/account"; +import { endSession, launchSession } from "@/session"; +import { getToken, clearToken, setToken } from "@/composables/store"; +import { parseAuthRes } from "./auth"; + +export const accountAuth = async (): Promise => { + + /* attempt to get a login token from the store */ + const token = getToken(); + + /* try to login with it, returns platform secret and new token on success */ + if (token) { + try { + + const res = await postAuth(token); + + const parsed = parseAuthRes(res); + + setToken(parsed.token) + + return { + profile: parsed.profile, + token: parsed.token + }; + + } catch(e) { + console.log('[ACCOUNT]', e); + clearToken(); + throw(new Error('Failed to authenticate.')); + + } + } else { + throw(new Error('Unable to authenticate.')); + } +}; + +export const accountLogin: IpcHandlerCallback = async (payload) => { + const account = payload as AccountCredentials; + try { + + // attempt login with email password + const res = await postLogin(account.email, account.password); + const parsed = parseAuthRes(res); + + // save jwt token and profile + setToken(parsed.token) + + // launch session + launchSession(parsed.token) + + // return profile to renderer + return parsed.profile; + + } catch(e) { + throw e; + } +} + +// export const accountLogin = async (account: Account): Promise => { +// +// try { +// +// // attempt login with email password +// const res = await postLogin(account.email, account.password); +// const parsed = parseAuthRes(res); +// +// // save jwt token and profile +// setToken(parsed.token) +// +// // launch session +// launchSession(parsed.token) +// +// // return profile to renderer +// return parsed.profile; +// +// } catch(e) { +// console.log('[ACCOUNT]', e); +// throw (new Error('Failed to authenticate')); +// } +// +// } + +export const accountLogout = async (): Promise => { + + try { + // post logout to backend + await postLogout(); + + // remove key and crimataId + clearToken(); + + // kill crimata platform session + endSession(); + + return; + + } catch(e) { + console.log('[ACCOUNT]', e); + return (new Error('Failed to logout. Please try again.')); + } + +} + + diff --git a/src/api/account.ts b/src/api/account.ts index 98d3c69..a907dfb 100644 --- a/src/api/account.ts +++ b/src/api/account.ts @@ -1,36 +1,31 @@ import { useHttp } from "@/composables/http"; import axios from "axios"; +import {config} from "@/config"; const { post } = useHttp(); -export const usrPwdAuth = async (email: string, password: string) => { - - try { - return await post('/account/login', { email, password }) - - } catch (e) { - return null; - } - -} - -export const tokenAuth = async (cid: string, token: string) => { - - try { - return await axios({ - url: "http://127.0.0.1:3000/api/account/profile", - headers: { - Cookie: `jwt=${token}` - }, - method: 'GET', - data: { - cid, - } +export const postAuth = async (token: string) => ( + await axios({ + url: config.BUSINESS_URL + config.BUSINESS_PREFIX + '/account/authenticate', + headers: { + Cookie: `jwt=${token}` + }, + method: 'POST', }) +).data; + + +export const postLogin = async (email: string, password: string) => ( + await post('/account/login', { email, password }) +).data; + + +export const postLogout = + async (): Promise => (await post('/account/logout')); + + + + - } catch (e) { - return null; - } -} \ No newline at end of file diff --git a/src/auth.ts b/src/auth.ts new file mode 100644 index 0000000..14ed36a --- /dev/null +++ b/src/auth.ts @@ -0,0 +1,13 @@ + +export const parseAuthRes = (authRes: any) => { + const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string; + const profile = authRes.data as Profile; + return { + token, + profile + } +}; + + + + diff --git a/src/composables/http.ts b/src/composables/http.ts index a9519a8..e789afa 100644 --- a/src/composables/http.ts +++ b/src/composables/http.ts @@ -1,10 +1,8 @@ import axios, { AxiosRequestConfig } from 'axios'; +import {config} from "@/config"; -const preFix = '/api'; - -const baseURL = "http://127.0.0.1:3000" + preFix; - +const baseURL = config.BUSINESS_URL + config.BUSINESS_PREFIX; interface Request { endpoint: string; @@ -12,7 +10,6 @@ interface Request { config?: Record; } - const makeQuery = (reqQuery: Record) => { let result = ''; diff --git a/src/composables/ipcHandler.ts b/src/composables/ipcHandler.ts new file mode 100644 index 0000000..b588102 --- /dev/null +++ b/src/composables/ipcHandler.ts @@ -0,0 +1,50 @@ + +import { ipcMain, IpcMainInvokeEvent } from "electron"; + +export class IpcHandler implements IIpcHandler { + + readonly channel: string; + + readonly _handlerCallback: IpcHandlerCallback; + + constructor(options: { + channel: string; + handlerCallback: IpcHandlerCallback; + }) { + this.channel = options.channel; + this._handlerCallback = options.handlerCallback; + } + + handle() { + ipcMain.handle(this.channel, this._onInvoke); + } + + remove() { + ipcMain.removeHandler(this.channel); + } + + private async _onInvoke(_e: IpcMainInvokeEvent, payload?: string | null): Promise { + + return new Promise(async (resolve, reject) => { + + console.log(`[IPC]:${this.channel}`); + + try { + + const params = payload ? JSON.parse(payload) : null; + + const res = await this._handlerCallback(params); + + resolve(res as unknown as ReturnType); + + } catch(e) { + console.log(`[IPC]:${this.channel}`, e); + reject(e); + } + }); + } + +} + + + diff --git a/src/composables/json.ts b/src/composables/json.ts index 43b3804..06ab4b9 100644 --- a/src/composables/json.ts +++ b/src/composables/json.ts @@ -1,9 +1,13 @@ + +import {config} from "@/config"; +import fs from 'fs'; + export const saveToJson = (fileName: string, data: any) => { - fs.writeFile(configPath + fileName, JSON.stringify(data), (err) => { + fs.writeFile(config.configPath + fileName, JSON.stringify(data), (err) => { if (err) { console.log("Error when saving to json.") - } + } }) -} \ No newline at end of file +} diff --git a/src/composables/store.ts b/src/composables/store.ts new file mode 100644 index 0000000..88b9c17 --- /dev/null +++ b/src/composables/store.ts @@ -0,0 +1,19 @@ +const Store = require('electron-store'); + +const schema = { + key: { + type: 'string', + }, +}; + +const store = new Store({ + schema, + encryptionKey: "super user test" +}); + +export const getToken = (): string | undefined => (store.get("token")); + +export const clearToken = (): void => (store.delete("token")); + +export const setToken = (token: string): void => (store.set('token', token)); + diff --git a/src/composables/websockets.ts b/src/composables/websockets.ts index d034027..8208109 100644 --- a/src/composables/websockets.ts +++ b/src/composables/websockets.ts @@ -3,9 +3,18 @@ import WebSocket from 'ws'; -export default function useWebSockets(onMessageCallback: (s: string) => void) { - let socket: WebSocket | null = null; +const _connectionCheckTimeout = 4000; +const _reconnectTimeout = 1000; +let _connectionCheckInterval: ReturnType; + + +export default function useWebSockets( + messageCallback: (message: string) => void, + connectionStatusCallback: (alive: boolean) => void, +) { + + let socket: WebSocket; const send = async (data: Record): Promise => { return new Promise((resolve, reject) => { @@ -21,30 +30,52 @@ export default function useWebSockets(onMessageCallback: (s: string) => void) { const connect = (socketUrl: string, secret: string) => { + // avoid setting multiple interval; + if (_connectionCheckInterval) clearInterval(_connectionCheckInterval); + /* create a new socket */ - socket = new WebSocket(socketUrl) + socket = new WebSocket(socketUrl); /* add event listeners */ - socket.on("open", () => { - if (socket) + socket.send(secret); + + // ping server + _connectionCheckInterval = setInterval(() => { + + socket.ping(null, true, (e: Error) => { + if (e) { + socket.close(); + connectionStatusCallback(false); + setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); + } + }); + + }, _connectionCheckTimeout); + }); socket.on("message", (event: WebSocket.MessageEvent) => { - onMessageCallback(event.data.toString()) + messageCallback(event.data.toString()) }); - socket.on("close", () => { - return + socket.on("close", (event: WebSocket.CloseEvent) => { + connectionStatusCallback(false); + clearInterval(_connectionCheckInterval); + if (!event.wasClean) { + setTimeout(() => connect(socketUrl, secret), _reconnectTimeout); + } + }); + socket.on("pong", () => connectionStatusCallback(true)); + } const close = () => { if (socket) { socket.close(); - socket = null; } } diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..b0eb27e --- /dev/null +++ b/src/config.ts @@ -0,0 +1,17 @@ + +import { app } from "electron"; + +const env = process.env; + +const PLATFORM_PORT = env.PLATFORM_PORT || 8760; +const PLATFORM_IP = env.PLATFORM_IP || 'http://127.0.0.1'; + +const BUSINESS_PORT = env.BUSINESS_PORT || 3010; +const BUSINESS_IP = env.BUSINESS_IP || 'http://127.0.0.1'; + +export const config = { + PLATFORM_URL: `${PLATFORM_IP}:${PLATFORM_PORT}`, + BUSINESS_URL: `${BUSINESS_IP}:${BUSINESS_PORT}`, + BUSINESS_PREFIX: '/api', + configPath: app.getPath('userData') +} diff --git a/src/init.ts b/src/init.ts index 3d0b721..e68e766 100644 --- a/src/init.ts +++ b/src/init.ts @@ -9,8 +9,6 @@ import { app, protocol } from "electron"; import createWindow from "./window"; import main from "./main"; -require('dotenv').config(); - console.log('Starting Crimata electron app.'); // Scheme must be registered before the app is ready @@ -43,4 +41,4 @@ if (isDev) { process.on("SIGTERM", () => { app.quit(); }); -} \ No newline at end of file +} diff --git a/src/ipc/account.ts b/src/ipc/account.ts index 3860019..531d1a7 100644 --- a/src/ipc/account.ts +++ b/src/ipc/account.ts @@ -1,126 +1,32 @@ "use strict"; -import { submit, fetchProfile, logout } from "../api/account"; -import { ipcMain, IpcMainInvokeEvent } from "electron"; -import { store } from "@/composables/store"; +import { accountLogin, accountLogout } from "@/account"; +import {IpcHandler} from "@/composables/ipcHandler"; +const LOGIN_CHANNEL = "account-login"; +const LOGOUT_CHANNEL = "account-logout"; -const parseAuthRes = (authRes: any) => { - const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string; - const profile = authRes.data as Profile; - return { - token, - profile - } -}; +const loginHandler = new IpcHandler({ + channel: LOGIN_CHANNEL, + handlerCallback: accountLogin +}); +const logoutHandler = new IpcHandler({ + channel: LOGOUT_CHANNEL, + handlerCallback: accountLogout +}); +const handlers = [loginHandler, logoutHandler]; +export default handlers; - -/** - * Get user profile from store and try to login with it. - */ -const onTokenLogin = async ( - _event: IpcMainInvokeEvent, - _payload: null -): Promise => ( - - new Promise(async (resolve, reject) => { - console.log('[IPC]: user-profile'); - - // get jwt token and crimataId from store - const token = store.get('key'); - const crimataId = store.get('crimataId'); - - // authenticate and fetch profile - try { - - // attempt login with email token - const res = await fetchProfile(crimataId, token); - const parsed = parseAuthRes(res); - - // return profile to renderer - resolve(parsed.profile); - - } catch(e) { - reject(new Error('Failed to fetch profile.')); - } - }) -) - - -const onLogin = async ( - _event: IpcMainInvokeEvent, - payload: string -): Promise => ( - - new Promise(async (resolve, reject) => { - console.log('[IPC]: user-login'); - - const account = JSON.parse(payload); - - if ( account.password && account.email ) { - try { - - // attempt login with email password - const res = await submit(account.email, account.password); - const parsed = parseAuthRes(res); - - // save jwt token and profile - store.set('key', parsed.token); - store.set('crimataId', parsed.profile.crimataId); - - // init session - - // return profile to renderer - resolve(parsed.profile); - - } catch(e) { - console.log('[API]', e); - reject(new Error('Failed to authenticate')); - } - } - }) -) - -const onLogout = async ( - _event: IpcMainInvokeEvent, - _payload: null -): Promise => ( - - new Promise(async (resolve, reject) => { - console.log('[IPC]: user-logout'); - - try { - // post logout to backend - await logout(); - - // remove key and crimataId - store.delete('key'); - store.delete('crimataId'); - - // TODO: kill crimata platform session - // endSession(); - - resolve(); - } catch(e) { - reject(new Error('Failed to logout. Please try again.')); - } - }) -) - - -export default function useAccountListeners(): void { - - ipcMain.removeHandler("user-profile"); - ipcMain.handle("user-profile", onProfile); - - ipcMain.removeHandler("user-login"); - ipcMain.handle("user-login", onLogin); - - ipcMain.removeHandler("user-logout"); - ipcMain.handle("user-logout", onLogout); - -} +// export default function useAccountListeners(): void { +// +// ipcMain.removeHandler(LOGIN_HANDLER); +// ipcMain.handle(LOGIN_HANDLER, onLogin); +// +// ipcMain.removeHandler(LOGOUT_HANDLER); +// ipcMain.handle(LOGOUT_HANDLER, onLogout); +// +// } diff --git a/src/ipc/index.ts b/src/ipc/index.ts index 9152ef2..73a5901 100644 --- a/src/ipc/index.ts +++ b/src/ipc/index.ts @@ -1,17 +1,36 @@ "use strict"; -import useAccountListeners from "./account"; +import { IpcHandler } from "@/composables/ipcHandler"; +import handlers from "./account"; import useSessionListeners from "./session"; // import useAudioListeners from "./audio"; +interface IPCHandlers { + [channel: string]: IpcHandler; +} + +const ipcHandlers: IPCHandlers = {}; + +const _initHandlers = () => { + handlers.forEach((h) => { + if (!(h.channel in ipcHandlers)) { + ipcHandlers[h.channel] = h; + h.handle(); + } + }); +} export default function useIpc(): void { - useAccountListeners(); + _initHandlers(); + + // useAccountListeners(); useSessionListeners(); // useAudioListeners(); } + + diff --git a/src/ipc/session.ts b/src/ipc/session.ts index fa50aa1..bbaf0e9 100644 --- a/src/ipc/session.ts +++ b/src/ipc/session.ts @@ -10,11 +10,11 @@ function onSendMessage(_event: IpcMainEvent, payload: Message): void { } // Login attempt, returns success or not. -function onLogin(_event: IpcMainEvent, payload: LoginPayload) => { - authenticate(payload.email, payload.password); +function onLogin(_event: IpcMainEvent, payload: LoginPayload): void { + console.log('hello') } export default function useSessionListeners(): void { ipcMain.removeAllListeners("client-message"); ipcMain.on("client-message", onSendMessage); -} \ No newline at end of file +} diff --git a/src/main.ts b/src/main.ts index 9d6414c..b015cd9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,41 +1,21 @@ /** * Where the background logic really begins, gets called by app.onReady(). - * + * * Handles authentication. If profile is set, we launch a session, which consis * of opening a connection with the platform, initializing the audio streams. - * + * * The session is primarily an interface between the frontend and the platform, * relaying messages from one to the other. - * + * */ -import { tokenAuth, usrPwdAuth } from "@/api/account"; -import { launchSession, endSession } from "@/session"; import useIpc from "@/ipc/index"; -import store from "@/composables/store"; +import { accountAuth } from "./account"; +import { launchSession } from "./session"; +import ipcEmit from "./composables/emitter"; +import createWindow from "./window"; -/* authenticate the user */ -export async function authenticate(email: string, password: string) { - - /* attempt normal login */ - const platformKey, token, crimataId = await usrPwdAuth(email, password); - - /* launch if successful */ - if (platformKey) - launchSession(platformKey, crimataId); - - /* save the token */ - store.set("token", token); - -} - -/* logout the user, end the session */ -export function deauthenticate() { - - /* terminate the session */ - endSession(); - -} +let authState: AuthState | null; export default async function main() { @@ -45,18 +25,14 @@ export default async function main() { /* launch browser window */ await createWindow(); - /* attempt to get a login token from the store */ - const token = store.get("token"); + try { + authState = await accountAuth() as AuthState; + } catch(e) { + console.log('AUTH:', e); + authState = null; + } finally { + if (authState) launchSession(authState.token as string); + ipcEmit("set-profile", authState?.profile); + } - /* try to login with it, returns platform secret and new token on success */ - if (token) - const newToken, profile = await tokenAuth(token); - - /* if secret, we launch a session */ - if (newToken) - launchSession(newToken, profile); - - /* finally, save the most recent token */ - store.set("token", newToken); - -} \ No newline at end of file +} diff --git a/src/session.ts b/src/session.ts index afebe5b..158c41e 100644 --- a/src/session.ts +++ b/src/session.ts @@ -2,24 +2,34 @@ -import useAudio from "@/audio"; -import Canvas from "@/composables/convas"; +// import useAudio from "@/audio"; import ipcEmit from "@/composables/emitter"; +import useWebsockets from "./composables/websockets"; +import {config} from "@/config"; /* data structure of messages that's tied to the UI */ -let msgrState: UIState | null = null; +const uiState: any | null = null; /* start and stop audio functionality */ -const { initAudio, closeAudio } = useAudio(); +// const { initAudio, closeAudio } = useAudio(); + +let isInitMessage: any; + +let deauthenticate: any; +let isAddMessage: any /** * Controls for interfacing with the platform. * Takes an onMessage callback which we define below. */ -const { connect, send, close } = useWebsockets((content: any) => { + + +const onMessageCallback = (message: string) => { + + const content = JSON.parse(message); /* if the platform fails to authenticate, we must back down */ - if (content === "auth_error") { + if (content === "CLOSE_AUTH_FAIL") { deauthenticate(); return; } @@ -28,8 +38,8 @@ const { connect, send, close } = useWebsockets((content: any) => { if (isInitMessage(content)) { uiState.set(content); } - - + + else if (isAddMessage(content)) { uiState.add(content); } @@ -37,10 +47,15 @@ const { connect, send, close } = useWebsockets((content: any) => { else { uiState.update(content); } +} -}); +const onConnectionStatusCallback = (alive: boolean) => { + ipcEmit('connection-state', alive); +} -/* send a message to the platform */ +const { connect, send, close } = useWebsockets(onMessageCallback, onConnectionStatusCallback); + +/* send a message to the platform */ export function sendMessage(message: Message) { /* socket send */ @@ -48,24 +63,22 @@ export function sendMessage(message: Message) { } + /* launch a new session (the main process for authenticated users) */ -export function launchSession(platformKey: string, crimata_id: string) { +export function launchSession(platformKey: string) { /* connect to the platform */ - connect(PLATFORM_URL, platformKey); + connect(config.PLATFORM_URL, platformKey); /* initialize the audio streams */ - initAudio(); - - /* push profile to window */ - if (win) - ipcEmit("update-auth", crimata_id); + // initAudio(); } + export function endSession() { - closeAudio(); + // closeAudio(); close(); diff --git a/src/types.ts b/src/types.ts index e8682b8..583371e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,4 @@ + interface Message { text: boolean | string; context: boolean | string; @@ -28,3 +29,25 @@ interface LoginPayload { email: string; password: string; } + +interface AuthState { + profile: Profile | null; + token: string | null; +} + +interface AccountCredentials { + email: string; + password: string; +} + +interface IpcHandlerCallback { + (payload: I | null): Promise; +} + +interface IIpcHandler { + handle(): void; + remove(): void; + readonly _handlerCallback: IpcHandlerCallback; +} + + diff --git a/src/window.ts b/src/window.ts index 4c69387..807064a 100644 --- a/src/window.ts +++ b/src/window.ts @@ -1,10 +1,12 @@ "use strict"; -import { BrowserWindow, ipcMain } from "electron"; +import { BrowserWindow, ipcMain, app } from "electron"; import { createProtocol } from "vue-cli-plugin-electron-builder/lib"; -import { backgroundMitt } from './coposables/emitter'; -import { saveToJson } from "./coposables/json"; +import { backgroundMitt } from './composables/emitter'; +import { saveToJson } from "./composables/json"; import * as path from "path"; +import fs from 'fs'; +import { config } from "@/config"; const { autoUpdater } = require('electron-updater'); interface IpcRendererPayload { @@ -19,8 +21,8 @@ const loadWinState = (fileName: string): WindowState => { let state: WindowState; try { - state = JSON.parse(fs.readFileSync(configPath + fileName).toString()); - } + state = JSON.parse(fs.readFileSync(config.configPath + fileName).toString()); + } catch (error) { state = { @@ -32,8 +34,8 @@ const loadWinState = (fileName: string): WindowState => { } return state - -} + +} // Called when a NavBar button is pressed. const onNavBar = (_event: any, action: string): void => { @@ -110,8 +112,8 @@ export default async function createWindow(): Promise { win = new BrowserWindow({ width: winState.width, height: winState.height, - x: winState.x, - y: winState.y, + x: winState.x as number, + y: winState.y as number, resizable: true, backgroundColor: '#EBEBEB', frame: false, From 0a3c9f71d81f54f0d1784c68b26b34e4f32ffe9b Mon Sep 17 00:00:00 2001 From: riqo Date: Tue, 15 Jun 2021 08:48:14 -0500 Subject: [PATCH 58/66] rename composable files to composable notation --- src/audio.ts | 187 ++++++++++++++++++ src/composables/audio.ts | 187 ------------------ src/composables/{emitter.ts => useEmitter.ts} | 0 src/composables/{http.ts => useHttp.ts} | 0 .../{ipcHandler.ts => useIpcMain.ts} | 0 .../{canvas.ts => useMessageCanvas.ts} | 0 src/composables/{json.ts => useSaveToJSON.ts} | 0 .../{websockets.ts => useWebsockets.ts} | 0 .../controllers/messenger.control.ts | 12 +- src/render/components/messenger.vue | 15 +- src/render/components/settings.vue | 2 +- .../{draggify.ts => useDraggify.ts} | 0 .../composables/{ipc.ts => useIpcRend.ts} | 0 src/render/composables/useMessages.ts | 0 .../composables/{auth.ts => useProfile.ts} | 0 .../composables/{scroll.ts => useScroll.ts} | 0 src/render/main.ts | 16 ++ src/{composables => }/store.ts | 0 18 files changed, 217 insertions(+), 202 deletions(-) delete mode 100644 src/composables/audio.ts rename src/composables/{emitter.ts => useEmitter.ts} (100%) rename src/composables/{http.ts => useHttp.ts} (100%) rename src/composables/{ipcHandler.ts => useIpcMain.ts} (100%) rename src/composables/{canvas.ts => useMessageCanvas.ts} (100%) rename src/composables/{json.ts => useSaveToJSON.ts} (100%) rename src/composables/{websockets.ts => useWebsockets.ts} (100%) rename src/render/composables/{draggify.ts => useDraggify.ts} (100%) rename src/render/composables/{ipc.ts => useIpcRend.ts} (100%) create mode 100644 src/render/composables/useMessages.ts rename src/render/composables/{auth.ts => useProfile.ts} (100%) rename src/render/composables/{scroll.ts => useScroll.ts} (100%) create mode 100644 src/render/main.ts rename src/{composables => }/store.ts (100%) diff --git a/src/audio.ts b/src/audio.ts index e69de29..844e791 100644 --- a/src/audio.ts +++ b/src/audio.ts @@ -0,0 +1,187 @@ +/* eslint @typescript-eslint/no-var-requires: "off" */ + +"use strict"; + +// where the audio goes +let buffer: ArrayBuffer[] = []; + +// place audio data in buffer +export function collect (chunk: ArrayBuffer) { + buffer.push(chunk); +} + +// return audio and clear buffer +export function flush () { + const bufferCopy = buffer; + buffer = []; + return bufferCopy; +} + +// import { backgroundMitt } from '@/modules/emitter'; +// const portAudio = require('naudiodon'); + +// // Audio in and out stream objects. +// let ai: typeof portAudio.AudioIO | boolean = false; +// let ao: typeof portAudio.AudioIO | boolean = false; + +// // Whether activly recording. +// let record = false; + +// const audioContainer = { +// input: '', +// } + +// const audioOptions = { +// channelCount: 1, +// sampleFormat: 16, +// sampleRate: 16000, +// deviceId: -1, +// closeOnError: false, +// } + +// export const toggleRecord = (): void => { record = !record }; + + +// export const fetchAudioInput = (): Promise => ( + +// new Promise((resolve, reject) => { + +// try { +// resolve(audioContainer.input); +// toggleRecord(); +// } catch (e) { +// reject(new Error('Failed to fetch the audio.')) +// } + +// }) +// ) + + +// // Main audio function run by run.ts module. +// export function initAudioIO(): void { +// console.log("AUDIO:Starting io streams.") + +// if (!ai) { + +// // Initialize and start input stream. +// ai = new portAudio.AudioIO({ inOptions: audioOptions }); +// ai.setEncoding("hex"); +// ai.start(); + +// // On each data chunk... +// ai.on('data', (chunk: string) => { + +// // If recording, we capture the data. +// if (record) { +// console.log('AUDIO:Recording...') +// audioContainer.input += chunk; +// } + +// // Else, we don't capture and also clear audioContainer. +// else { +// if (audioContainer.input.length) { +// audioContainer.input = ""; +// } +// } + +// }); +// } + +// if (!ao) { + +// // Initialize and start input stream. +// ao = new portAudio.AudioIO({ outOptions: audioOptions }); +// ao.start(); + +// } +// } + + +// // ---Audio playback-------------------------------------------- + +// // Split Buffer into an array of len-sized Buffers. +// function bufSplit(buf: Buffer, len: number): Array { +// const chunks = []; +// let i = 0; +// let L = len; + +// while(i < buf.byteLength) { +// chunks.push(buf.slice(i, L)); +// i = L; +// L += len; +// } + +// return chunks; +// } + +// // Audio playback. +// export function play(input: string): void { + +// // Format the audio. +// const audio = bufSplit( +// Buffer.from(input as string, 'hex'), +// 8192 +// ); + +// // Called on end of write. +// const callback = () => { + +// // We stop audio playback anim. +// backgroundMitt.emit('ipc-renderer', { +// endpoint: 'stop-playback-anim' +// }); + +// } + +// write(); + +// // Iterate through audio array and write buffers to portAudio writable. +// function write() { +// let chunk: Buffer; +// let ok = true; +// let i = 0; + +// do { +// chunk = audio[i]; +// if (i === audio.length - 1) { +// // write last chunk. +// ao.write(chunk, null, callback); +// } else { +// // check for backpreassure. +// ok = ao.write(chunk, null); +// } +// i++; +// } while (i < audio.length && ok); + +// if (i < audio.length) { +// // Had to stop early! +// // Write some more once it drains. +// ao.once('drain', write); +// } +// } +// } + +// // ------------------------------------------------------------- + +// // Get's called on window close. +// export async function stopStream() { +// console.log("AUDIO:Stopping audio stream.") +// if (ai) { +// try { +// await ai.quit() +// } catch(e){ +// console.log('AUDIO: Failed to shutdown audio input.'); +// throw e; +// } +// } +// if (ao) { +// try { +// await ao.quit() +// } catch(e){ +// console.log('AUDIO: Failed to shutdown audio output.'); +// throw e; +// } +// } +// } + + diff --git a/src/composables/audio.ts b/src/composables/audio.ts deleted file mode 100644 index 844e791..0000000 --- a/src/composables/audio.ts +++ /dev/null @@ -1,187 +0,0 @@ -/* eslint @typescript-eslint/no-var-requires: "off" */ - -"use strict"; - -// where the audio goes -let buffer: ArrayBuffer[] = []; - -// place audio data in buffer -export function collect (chunk: ArrayBuffer) { - buffer.push(chunk); -} - -// return audio and clear buffer -export function flush () { - const bufferCopy = buffer; - buffer = []; - return bufferCopy; -} - -// import { backgroundMitt } from '@/modules/emitter'; -// const portAudio = require('naudiodon'); - -// // Audio in and out stream objects. -// let ai: typeof portAudio.AudioIO | boolean = false; -// let ao: typeof portAudio.AudioIO | boolean = false; - -// // Whether activly recording. -// let record = false; - -// const audioContainer = { -// input: '', -// } - -// const audioOptions = { -// channelCount: 1, -// sampleFormat: 16, -// sampleRate: 16000, -// deviceId: -1, -// closeOnError: false, -// } - -// export const toggleRecord = (): void => { record = !record }; - - -// export const fetchAudioInput = (): Promise => ( - -// new Promise((resolve, reject) => { - -// try { -// resolve(audioContainer.input); -// toggleRecord(); -// } catch (e) { -// reject(new Error('Failed to fetch the audio.')) -// } - -// }) -// ) - - -// // Main audio function run by run.ts module. -// export function initAudioIO(): void { -// console.log("AUDIO:Starting io streams.") - -// if (!ai) { - -// // Initialize and start input stream. -// ai = new portAudio.AudioIO({ inOptions: audioOptions }); -// ai.setEncoding("hex"); -// ai.start(); - -// // On each data chunk... -// ai.on('data', (chunk: string) => { - -// // If recording, we capture the data. -// if (record) { -// console.log('AUDIO:Recording...') -// audioContainer.input += chunk; -// } - -// // Else, we don't capture and also clear audioContainer. -// else { -// if (audioContainer.input.length) { -// audioContainer.input = ""; -// } -// } - -// }); -// } - -// if (!ao) { - -// // Initialize and start input stream. -// ao = new portAudio.AudioIO({ outOptions: audioOptions }); -// ao.start(); - -// } -// } - - -// // ---Audio playback-------------------------------------------- - -// // Split Buffer into an array of len-sized Buffers. -// function bufSplit(buf: Buffer, len: number): Array { -// const chunks = []; -// let i = 0; -// let L = len; - -// while(i < buf.byteLength) { -// chunks.push(buf.slice(i, L)); -// i = L; -// L += len; -// } - -// return chunks; -// } - -// // Audio playback. -// export function play(input: string): void { - -// // Format the audio. -// const audio = bufSplit( -// Buffer.from(input as string, 'hex'), -// 8192 -// ); - -// // Called on end of write. -// const callback = () => { - -// // We stop audio playback anim. -// backgroundMitt.emit('ipc-renderer', { -// endpoint: 'stop-playback-anim' -// }); - -// } - -// write(); - -// // Iterate through audio array and write buffers to portAudio writable. -// function write() { -// let chunk: Buffer; -// let ok = true; -// let i = 0; - -// do { -// chunk = audio[i]; -// if (i === audio.length - 1) { -// // write last chunk. -// ao.write(chunk, null, callback); -// } else { -// // check for backpreassure. -// ok = ao.write(chunk, null); -// } -// i++; -// } while (i < audio.length && ok); - -// if (i < audio.length) { -// // Had to stop early! -// // Write some more once it drains. -// ao.once('drain', write); -// } -// } -// } - -// // ------------------------------------------------------------- - -// // Get's called on window close. -// export async function stopStream() { -// console.log("AUDIO:Stopping audio stream.") -// if (ai) { -// try { -// await ai.quit() -// } catch(e){ -// console.log('AUDIO: Failed to shutdown audio input.'); -// throw e; -// } -// } -// if (ao) { -// try { -// await ao.quit() -// } catch(e){ -// console.log('AUDIO: Failed to shutdown audio output.'); -// throw e; -// } -// } -// } - - diff --git a/src/composables/emitter.ts b/src/composables/useEmitter.ts similarity index 100% rename from src/composables/emitter.ts rename to src/composables/useEmitter.ts diff --git a/src/composables/http.ts b/src/composables/useHttp.ts similarity index 100% rename from src/composables/http.ts rename to src/composables/useHttp.ts diff --git a/src/composables/ipcHandler.ts b/src/composables/useIpcMain.ts similarity index 100% rename from src/composables/ipcHandler.ts rename to src/composables/useIpcMain.ts diff --git a/src/composables/canvas.ts b/src/composables/useMessageCanvas.ts similarity index 100% rename from src/composables/canvas.ts rename to src/composables/useMessageCanvas.ts diff --git a/src/composables/json.ts b/src/composables/useSaveToJSON.ts similarity index 100% rename from src/composables/json.ts rename to src/composables/useSaveToJSON.ts diff --git a/src/composables/websockets.ts b/src/composables/useWebsockets.ts similarity index 100% rename from src/composables/websockets.ts rename to src/composables/useWebsockets.ts diff --git a/src/render/components/controllers/messenger.control.ts b/src/render/components/controllers/messenger.control.ts index 9ae7d47..a0f9b09 100644 --- a/src/render/components/controllers/messenger.control.ts +++ b/src/render/components/controllers/messenger.control.ts @@ -1,20 +1,20 @@ import { ref } from 'vue'; import useScroll from "@/render/composables/scroll"; -const canvas = ref(); +const messagesRef = ref(); /* seed the canvas with messages */ const seedCanvas = (messages: Message[]) => { - canvas.value = messages; + messagesRef.value = messages; } const addMessage = (message: Message) => { - canvas.value.push(message); + messagesRef.value.push(message); } const updateMessage = (message: Message) => { - let target_message = canvas.value.filter((m: Message) => { + let target_message = messagesRef.value.filter((m: Message) => { return m.uid = message.uid; })[0]; @@ -29,10 +29,10 @@ export default function useMessages() { const { updateScrollRef, adjustScroll } = useScroll("messenger"); return { - canvas, + messagesRef, seedCanvas, addMessage, updateMessage }; -} \ No newline at end of file +} diff --git a/src/render/components/messenger.vue b/src/render/components/messenger.vue index 4ea2d5b..9bc6448 100644 --- a/src/render/components/messenger.vue +++ b/src/render/components/messenger.vue @@ -8,10 +8,9 @@
@@ -24,7 +23,7 @@ import { defineComponent, onMounted, onUnmounted } from "vue"; import Message from "@/render/components/message.vue"; import InputItem from "@/render/components/inputItem.vue"; import Settings from "@/render/components/settings.vue"; -import useMessages from "@/render/composables/messages"; +import useMessages from "./controllers/messenger.control"; export default defineComponent({ name: "Messenger", @@ -40,23 +39,23 @@ export default defineComponent({ setup(props) { // Handle messages in view. - const { messages, updateMessageView } = useMessages(); + const { messagesRef, updateMessageView } = useMessages(); onMounted(() => { /* seed messages */ window.ipcRenderer.on("init-messages", (e_: any, payload: any) => { - seedMessages(payload.messages); + // seedMessages(payload.messages); }); /* add a new message */ window.ipcRenderer.on("add-message", (_e: any, payload: any) => { - addMessage(payload.message); + // addMessage(payload.message); }); /* update an existing message */ window.ipcRenderer.on("update-message", (_e: any, payload: any) => { - updateMessage(payload.message); + // updateMessage(payload.message); }); }); @@ -66,7 +65,7 @@ export default defineComponent({ }); return { - messages + messagesRef }; }, diff --git a/src/render/components/settings.vue b/src/render/components/settings.vue index 7c4b9ce..9b4f3e5 100644 --- a/src/render/components/settings.vue +++ b/src/render/components/settings.vue @@ -31,7 +31,7 @@ import { useIpc } from "@/modules/ipc"; import { logoutRequest } from '@/modules/message'; import { useProfile } from "@/modules/auth" - import { invokeLogout } from "@/ipcRend/account"; + import { invokeLogout } from "@/render/ipc"; export default defineComponent({ name: "Settings", diff --git a/src/render/composables/draggify.ts b/src/render/composables/useDraggify.ts similarity index 100% rename from src/render/composables/draggify.ts rename to src/render/composables/useDraggify.ts diff --git a/src/render/composables/ipc.ts b/src/render/composables/useIpcRend.ts similarity index 100% rename from src/render/composables/ipc.ts rename to src/render/composables/useIpcRend.ts diff --git a/src/render/composables/useMessages.ts b/src/render/composables/useMessages.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/render/composables/auth.ts b/src/render/composables/useProfile.ts similarity index 100% rename from src/render/composables/auth.ts rename to src/render/composables/useProfile.ts diff --git a/src/render/composables/scroll.ts b/src/render/composables/useScroll.ts similarity index 100% rename from src/render/composables/scroll.ts rename to src/render/composables/useScroll.ts diff --git a/src/render/main.ts b/src/render/main.ts new file mode 100644 index 0000000..50a594a --- /dev/null +++ b/src/render/main.ts @@ -0,0 +1,16 @@ + +// src/main.ts + +import App from "./App.vue"; + +import mitt from "mitt"; +import { createApp } from "vue"; + + +// Handle events. +const emitter = mitt(); + +const app = createApp(App) + +app.provide("mitt", emitter) +app.mount("#app"); diff --git a/src/composables/store.ts b/src/store.ts similarity index 100% rename from src/composables/store.ts rename to src/store.ts From d963f7d8a8e6badf4b376d1300772fbc8354202d Mon Sep 17 00:00:00 2001 From: riqo Date: Wed, 16 Jun 2021 08:42:47 -0500 Subject: [PATCH 59/66] initial working version --- package.json | 4 ++- src/account.ts | 25 +------------------ src/api/account.ts | 2 +- src/composables/useEmitter.ts | 9 ++++--- src/composables/useHttp.ts | 2 +- src/init.ts | 8 ++++++ src/ipc/account.ts | 2 +- src/main.ts | 10 +++++--- src/render/App.vue | 6 ++--- src/render/components/controllers/helpers.ts | 2 +- .../controllers/inputItem.control.audio.ts | 8 +++--- .../controllers/inputItem.control.text.ts | 8 +++--- .../controllers/messenger.control.ts | 2 +- src/render/components/header.vue | 18 +++++++++---- src/render/components/inputItem.vue | 23 +++++++---------- src/render/components/login.vue | 19 +++++++------- src/render/components/messenger.vue | 4 +-- src/render/components/settings.vue | 8 ++---- src/render/composables/useProfile.ts | 2 ++ src/render/ipc.ts | 18 ++++++------- src/session.ts | 4 +-- src/types.ts | 1 - src/window.ts | 4 +-- 23 files changed, 89 insertions(+), 100 deletions(-) diff --git a/package.json b/package.json index 2b4b7fd..7fff91a 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,9 @@ "lintOnSave": false, "pluginOptions": { "electronBuilder": { - "preload": "src/renderer/preload.ts", + "mainProcessFile": "./src/init.ts", + "rendererProcessFile": "./src/render/main.ts", + "preload": "./src/render/preload.ts", "builderOptions": { "appId": "com.crimata.ElectronUpdaterApp", "artifactName": "${productName}-${version}.${ext}", diff --git a/src/account.ts b/src/account.ts index 4884135..95fe629 100644 --- a/src/account.ts +++ b/src/account.ts @@ -1,7 +1,7 @@ import { postAuth, postLogin, postLogout } from "@/api/account"; import { endSession, launchSession } from "@/session"; -import { getToken, clearToken, setToken } from "@/composables/store"; +import { getToken, clearToken, setToken } from "./store"; import { parseAuthRes } from "./auth"; export const accountAuth = async (): Promise => { @@ -57,29 +57,6 @@ export const accountLogin: IpcHandlerCallback = asy } } -// export const accountLogin = async (account: Account): Promise => { -// -// try { -// -// // attempt login with email password -// const res = await postLogin(account.email, account.password); -// const parsed = parseAuthRes(res); -// -// // save jwt token and profile -// setToken(parsed.token) -// -// // launch session -// launchSession(parsed.token) -// -// // return profile to renderer -// return parsed.profile; -// -// } catch(e) { -// console.log('[ACCOUNT]', e); -// throw (new Error('Failed to authenticate')); -// } -// -// } export const accountLogout = async (): Promise => { diff --git a/src/api/account.ts b/src/api/account.ts index a907dfb..59872c8 100644 --- a/src/api/account.ts +++ b/src/api/account.ts @@ -1,5 +1,5 @@ -import { useHttp } from "@/composables/http"; +import useHttp from "@/composables/useHttp"; import axios from "axios"; import {config} from "@/config"; diff --git a/src/composables/useEmitter.ts b/src/composables/useEmitter.ts index ee6bb5e..240c557 100644 --- a/src/composables/useEmitter.ts +++ b/src/composables/useEmitter.ts @@ -1,15 +1,16 @@ -/* eslint-disable */ // Backend emitter - +// const EventEmitter = require('events'); class BackgroundMitt extends EventEmitter { } export const backgroundMitt = new BackgroundMitt(); -export default function ipcEmit (channel: string, payload: any) { +export const ipcEmit = (channel: string, payload: any) => { backgroundMitt.emit('ipc-renderer', { endpoint: channel, message: payload }); -} +}; + + diff --git a/src/composables/useHttp.ts b/src/composables/useHttp.ts index e789afa..6b9ee56 100644 --- a/src/composables/useHttp.ts +++ b/src/composables/useHttp.ts @@ -22,7 +22,7 @@ const makeQuery = (reqQuery: Record) => { }; -export const useHttp = () => { +export default function useHttp() { const api = axios.create({ baseURL, diff --git a/src/init.ts b/src/init.ts index e68e766..9a0fdf6 100644 --- a/src/init.ts +++ b/src/init.ts @@ -8,6 +8,7 @@ import { app, protocol } from "electron"; import createWindow from "./window"; import main from "./main"; +import { backgroundMitt } from '@/composables/useEmitter'; console.log('Starting Crimata electron app.'); @@ -18,6 +19,13 @@ protocol.registerSchemesAsPrivileged([ const isDev = require('electron-is-dev'); +let win: boolean; + +// Listen for window creation. +backgroundMitt.on('window-active', (state: boolean) => { + win = state; +}); + /* Start main process on ready */ app.on("ready", async () => { await main(); diff --git a/src/ipc/account.ts b/src/ipc/account.ts index 531d1a7..7759d12 100644 --- a/src/ipc/account.ts +++ b/src/ipc/account.ts @@ -2,7 +2,7 @@ "use strict"; import { accountLogin, accountLogout } from "@/account"; -import {IpcHandler} from "@/composables/ipcHandler"; +import {IpcHandler} from "@/composables/useIpcMain"; const LOGIN_CHANNEL = "account-login"; const LOGOUT_CHANNEL = "account-logout"; diff --git a/src/main.ts b/src/main.ts index b015cd9..9103cae 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,7 +12,7 @@ import useIpc from "@/ipc/index"; import { accountAuth } from "./account"; import { launchSession } from "./session"; -import ipcEmit from "./composables/emitter"; +import { ipcEmit } from "./composables/useEmitter"; import createWindow from "./window"; let authState: AuthState | null; @@ -31,8 +31,12 @@ export default async function main() { console.log('AUTH:', e); authState = null; } finally { - if (authState) launchSession(authState.token as string); - ipcEmit("set-profile", authState?.profile); + let profile = null; + if (authState) { + launchSession(authState.token as string); + profile = authState.profile; + } + ipcEmit("set-profile", profile); } } diff --git a/src/render/App.vue b/src/render/App.vue index d90bcc0..dfdaeb9 100644 --- a/src/render/App.vue +++ b/src/render/App.vue @@ -21,8 +21,8 @@ @@ -78,4 +86,4 @@ .minimizeButton:active { background-color: #c08e38; } - \ No newline at end of file + diff --git a/src/render/components/inputItem.vue b/src/render/components/inputItem.vue index 30978b3..edd844f 100644 --- a/src/render/components/inputItem.vue +++ b/src/render/components/inputItem.vue @@ -6,16 +6,16 @@ :style="{ top: `${elementY}px`, left: `${elementX}px` }" >
{{ initials }}
- + - @@ -27,24 +27,19 @@ - - diff --git a/src/authPayload.ts b/src/authPayload.ts deleted file mode 100644 index 61d68b6..0000000 --- a/src/authPayload.ts +++ /dev/null @@ -1,13 +0,0 @@ - -import { store } from "@/background/store"; - -interface PlatformAuthProtocol { - key: string; - crimata_id: string; -} - -export const getAuthPayload = (): PlatformAuthProtocol => ({ - key: store.get('key'), - crimata_id: store.get('crimataId') -}); - diff --git a/src/background.ts b/src/background.ts deleted file mode 100644 index 977c265..0000000 --- a/src/background.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Entry point for Crimata electron app. - * "Look on my Works, ye Mighty, and despair!" - */ - -"use strict"; - -import { initApp } from './background/init'; -import { protocol } from "electron"; - -// Scheme must be registered before the app is ready -protocol.registerSchemesAsPrivileged([ - { scheme: "app", privileges: { secure: true, standard: true } } -]); - -// Load environment variable -const isDev = require('electron-is-dev'); - -// NOTE Program Begins Here -(() => { - - console.log('Starting Crimata electron app.'); - initApp(isDev); - -})(); diff --git a/src/background/ipc/account.ts b/src/background/ipc/account.ts deleted file mode 100644 index 4bf6411..0000000 --- a/src/background/ipc/account.ts +++ /dev/null @@ -1,119 +0,0 @@ - -"use strict"; - -import { Profile } from "@/types"; -import { submit, fetchProfile, logout } from "@/api/account"; -import { ipcMain, IpcMainInvokeEvent } from "electron"; -import { store } from "@/background/store"; -import { endSession } from "@/background/session"; - - -const parseAuthRes = (authRes: any) => { - const token = authRes.headers['set-cookie'][0].split(";")[0].split("=")[1] as string; - const profile = authRes.data as Profile; - return { - token, - profile - } -}; - - -const onProfile = async ( - _event: IpcMainInvokeEvent, - _payload: null -): Promise => ( - - new Promise(async (resolve, reject) => { - console.log('[IPC]: user-profile'); - - // get jwt token and crimataId from store - const token = store.get('key'); - const crimataId = store.get('crimataId'); - - // authenticate and fetch profile - try { - - const res = await fetchProfile( - crimataId, - token - ); - - const parsed = parseAuthRes(res); - resolve(parsed.profile); - - } catch(e) { - reject(new Error('Unable to authenticate and fetch account profile.')); - } - }) -) - - -const onLogin = async ( - _event: IpcMainInvokeEvent, - payload: string -): Promise => ( - - new Promise(async (resolve, reject) => { - console.log('[IPC]: user-login'); - - const account = JSON.parse(payload); - - if ( account.password && account.email ) { - try { - const res = await submit(account.email, account.password); - const parsed = parseAuthRes(res); - - // save jwt token and profile - store.set('key', parsed.token); - store.set('crimataId', parsed.profile.crimataId); - - // return profile to renderer - resolve(parsed.profile); - - } catch(e) { - console.log('[API]', e); - reject(new Error('Failed to authenticate')); - } - } - }) -) - -const onLogout = async ( - _event: IpcMainInvokeEvent, - _payload: null -): Promise => ( - - new Promise(async (resolve, reject) => { - console.log('[IPC]: user-logout'); - - try { - // post logout to backend - await logout(); - - // remove key and crimataId - store.delete('key'); - store.delete('crimataId'); - - // TODO: kill crimata platform session - endSession(); - - resolve(); - } catch(e) { - reject(new Error('Failed to logout. Please try again.')); - } - }) -) - - -export default function useAccountListeners(): void { - - ipcMain.removeHandler("user-profile"); - ipcMain.handle("user-profile", onProfile); - - ipcMain.removeHandler("user-login"); - ipcMain.handle("user-login", onLogin); - - ipcMain.removeHandler("user-logout"); - ipcMain.handle("user-logout", onLogout); - -} diff --git a/src/background/ipc/session.ts b/src/background/ipc/session.ts deleted file mode 100644 index 7c42ea2..0000000 --- a/src/background/ipc/session.ts +++ /dev/null @@ -1,62 +0,0 @@ - -"use strict"; - -import { initSession, emitNewMessages, sendMessage } from '@/background/session'; -import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; -import { initAudioIO } from "@/background/audio"; -import { ClientMessage } from "@/types"; - - -// Instantiate socket session with crimata-platorm. -const onSessionInit = ( - _event: IpcMainInvokeEvent, - _payload: null -): void => { - - console.log('[IPC]: init-session'); - - initSession(); - - initAudioIO(); -} - - -const onAppMounted = ( - _event: IpcMainInvokeEvent, - _payload: null -): void => { - - console.log('[IPC]: app-mounted'); - - emitNewMessages() -}; - - -// Handle messages from window/client. -const onClientMessage = ( - _event: IpcMainEvent, - payload: ClientMessage -): void => { - - console.log('[IPC]: client-message'); - - sendMessage(payload); -} - - -export default function useSessionListeners(): void { - - console.log('[IPC]: Init session listeners.'); - - // Attach listeners for frontend. - ipcMain.removeAllListeners("client-message"); - ipcMain.on("client-message", onClientMessage); - - // Attack browser window init listener. - ipcMain.removeAllListeners("app-mounted"); - ipcMain.on("app-mounted", onAppMounted); - - ipcMain.removeAllListeners("init-session"); - ipcMain.on("init-session", onSessionInit); - -} diff --git a/src/background/session.ts b/src/background/session.ts deleted file mode 100644 index c90d32a..0000000 --- a/src/background/session.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Creates a websocket session with Crimata Servers. - * - * Connects to Servers and attempts key authentication. Server will respond - * with key and user profile. We send the profile to the browser. We also - * resend this information on new broser window. We then serve as a - * communication interface between the window and the servers. It will - * automatically try to reconnect on websocket disconnect. - */ - -import { backgroundMitt } from "@/modules/emitter"; -import { ipcEmit, loadState } from './helpers'; -import WebSocket from 'ws'; - -import useWebSockets from "./websockets"; - -import { play } from "./audio"; -import { renderMessage } from "@/modules/message"; -import { SessionState } from "@/types"; - -let win = true; - -// Info saved to json on quit (key, newMessages). -let state: SessionState; - -let socket: WebSocket | null = null; - - -// Calls appropriate endpoint for a server message. -const onMessage = (data: string): void => { - let message = JSON.parse(data); - - if (message === "CLOSE_AUTH_FAIL") { - ipcEmit("session-auth-fail", null) - return; - } - - // Standard message. - if (message.content) { - - // Convert to render message - message = renderMessage( - message.content.text, - message.content.audio, - message.context, - message.modifier - ); - - if (win) { - console.log("SESS:Emitting standard message.") - if (message.audio) { - play(message.audio) - } - ipcEmit("render-message", message) - } - - else { - console.log("SESS:No window: saving message.") - state.newMessages.push(message); - } - } - - else { - if (win) { - ipcEmit("render-message", message) - } - } - -}; - - -// Websockets module. -const { createSocket, send } = useWebSockets(onMessage); - - -export const emitNewMessages = (): void => { - if (state) { - ipcEmit("update-state", { - newMessages: state.newMessages, - }); - } - -} - - -export const sendMessage = (payload: Record): void => { - try { - send(payload) - } catch(e) { - console.log("Unable to send message: ", payload); - } - -} - -export const endSession = (): void => { - if (socket) { - socket.close(); - socket = null; - } -} - - -// Call this to initialize session with Crimata servers. -export const initSession = (): void => { - console.log("SESS:Creating new session.") - - // Load Json or createState. - state = loadState("session.json"); - - // Open socket connection. - if (!socket) - socket = createSocket(); - - // Keep win up-to-date. - backgroundMitt.on('window-active', (state: boolean) => { - win = state; - }); - -} diff --git a/src/background/websockets.ts b/src/background/websockets.ts deleted file mode 100644 index dec0203..0000000 --- a/src/background/websockets.ts +++ /dev/null @@ -1,122 +0,0 @@ - -"use strict"; - -import WebSocket from 'ws'; -import { getAuthPayload } from "./authPayload"; -import { ipcEmit } from './helpers'; - -let socket: WebSocket; - -const socketUrl = "ws://127.0.0.1:8760" - -const _connectionCheckTimeout = 4000; -const _reconnectTimeout = 1000; -let _connectionCheckInterval: ReturnType; - - -// Run every time we want to connect to backend. -export default function useWebSockets( - receiveCallback: (s: string) => void, - openCallback?: () => void -) { - - // Returns bool (sucess or fail). - const sendMessage = (data: any) => { - console.log("WS:Sending message: ", data) - - if (socket.readyState !== 1) { - return false - } - - else { - socket.send(JSON.stringify(data)) - return true - } - - } - - const send = async (data: Record): Promise => ( - new Promise((resolve, reject) => { - if (socket.readyState !== 1) { - reject(false); - } - socket.send(JSON.stringify(data)) - resolve(true); - - })) - - - const onOpen = (_event: WebSocket.OpenEvent) => { - - console.log("WS:Connected to WS Server!"); - const jwt = getAuthPayload(); - socket.send(JSON.stringify(jwt)); - - // ping server - _connectionCheckInterval = setInterval(() => { - - if (socket) socket.ping(null, true, (e: Error) => { - if (e) { - ipcEmit('connection-alive', false); - socket.close(); - setTimeout(createSocket, 1000); - } - }); - - }, _connectionCheckTimeout); - - if (openCallback) openCallback(); - - } - - const onServerMessage = (event: WebSocket.MessageEvent) => { - - console.log("WS:Message received: ", event.data); - - receiveCallback(event.data.toString()) - - } - - const onClose = (event: WebSocket.CloseEvent) => { - console.log("WS:Socket closed normally.", event.wasClean) - - clearInterval(_connectionCheckInterval); - - if (!event.wasClean) { - ipcEmit('connection-alive', false); - setTimeout(createSocket, 1000); - } - } - - // Reconnect automatically on error. - const onError = (event: WebSocket.ErrorEvent) => { - console.log("WS:WebSocket error: ", event.message); - } - - - const createSocket = (): WebSocket => { - - if (_connectionCheckInterval) clearInterval(_connectionCheckInterval); - - socket = new WebSocket(socketUrl); - - // Add listeners. - socket.addEventListener("open", onOpen); - socket.addEventListener("message", onServerMessage); - socket.addEventListener("close", onClose); - socket.addEventListener("error", onError); - socket.addEventListener("pong", () => { - ipcEmit('connection-alive', true); - }); - - return socket; - - } - - return { - createSocket, - sendMessage, - send - } - -} diff --git a/src/ipcRend/session.ts b/src/ipcRend/session.ts deleted file mode 100644 index a5ff5fc..0000000 --- a/src/ipcRend/session.ts +++ /dev/null @@ -1,23 +0,0 @@ - -import { useIpc } from "@/modules/ipc"; - -import { ClientMessage } from "@/types"; - -const { post } = useIpc(); - - -export const postMount = (): void => ( - post("app-mounted", null) -); - - -export const postInitSession = (): void => ( - post("init-session", null) -); - - -export const postMessage = (payload: ClientMessage): void => ( - post('client-message', payload) -); - - From 56196bcbcf3d75d5402eeb9aeb5b50268047e064 Mon Sep 17 00:00:00 2001 From: riqo Date: Sat, 19 Jun 2021 15:22:17 -0500 Subject: [PATCH 64/66] refactor frontend ipc --- src/account.ts | 19 +++++++++++--- src/composables/useIpcMain.ts | 18 +++++-------- src/ipc/handlers.ts | 3 ++- src/ipc/listeners.ts | 7 +++++ src/main.ts | 7 ++--- src/render/App.vue | 24 ++++------------- src/render/composables/useIpcRend.ts | 39 +++++++++++++++++++++++++--- src/render/composables/useProfile.ts | 16 +++++++++--- src/render/ipc.ts | 31 ++++++++++++++++++++++ src/render/listeners.ts | 32 +++++++++++++++++++++++ src/render/main.ts | 9 +++++-- src/store.ts | 14 +++++++++- src/types.ts | 10 ++++--- 13 files changed, 177 insertions(+), 52 deletions(-) create mode 100644 src/render/listeners.ts diff --git a/src/account.ts b/src/account.ts index 9f867f6..581da0e 100644 --- a/src/account.ts +++ b/src/account.ts @@ -1,8 +1,9 @@ import { postAuth, postLogin, postLogout } from "@/api/account"; import { endSession, launchSession } from "@/session"; -import { getToken, clearToken, setToken } from "./store"; +import { getToken, setToken, setProfile, getProfile, clearStore } from "./store"; import { parseAuthRes } from "./auth"; +import { ipcEmit } from "@/composables/useEmitter"; export const accountAuth = async (): Promise => { @@ -18,6 +19,7 @@ export const accountAuth = async (): Promise => { const parsed = parseAuthRes(res); setToken(parsed.token) + setProfile(parsed.profile); return { profile: parsed.profile, @@ -26,7 +28,7 @@ export const accountAuth = async (): Promise => { } catch(e) { console.log('[ACCOUNT]', e); - clearToken(); + clearStore(); throw(new Error('Failed to authenticate.')); } @@ -45,6 +47,7 @@ export const accountLogin: IpcHandlerCallback = asy // save jwt token and profile setToken(parsed.token); + setProfile(parsed.profile); // launch session launchSession(parsed.token); @@ -53,6 +56,7 @@ export const accountLogin: IpcHandlerCallback = asy return parsed.profile; } catch(e) { + clearStore(); throw e; } } @@ -65,7 +69,7 @@ export const accountLogout = async (): Promise => { await postLogout(); // remove key and crimataId - clearToken(); + clearStore(); // kill crimata platform session endSession(); @@ -79,4 +83,13 @@ export const accountLogout = async (): Promise => { } +export const updateAppState = (): void => { + + const profile = getProfile(); + + ipcEmit("set-profile", profile); + + // ipcEmit('messages') etc + +} diff --git a/src/composables/useIpcMain.ts b/src/composables/useIpcMain.ts index 57a2cb3..ebfc4bc 100644 --- a/src/composables/useIpcMain.ts +++ b/src/composables/useIpcMain.ts @@ -1,22 +1,21 @@ import { ipcMain, IpcMainInvokeEvent, IpcMainEvent } from "electron"; -export class IpcHandler implements IIpcHandler { +export class IpcHandler implements IIpcHandler { readonly channel: string; - readonly _handlerCallback: IpcHandlerCallback; + readonly _handlerCallback: IpcHandlerCallback; constructor(options: { channel: string; - handlerCallback: IpcHandlerCallback; + handlerCallback: IpcHandlerCallback; }) { this.channel = options.channel; this._handlerCallback = options.handlerCallback; } handle() { - console.log(`[IPC] INIT: ${this.channel}`); this.remove(); ipcMain.handle(this.channel, this._onInvoke); } @@ -49,22 +48,21 @@ export class IpcHandler implements IIpcHandler implements IIpcListener { +export class IpcListener implements IIpcListener { readonly channel: string; - readonly _listenerCallback: IpcListenerCallback; + readonly _listenerCallback: IpcListenerCallback; constructor(options: { channel: string; - listenerCallback: IpcListenerCallback; + listenerCallback: IpcListenerCallback; }) { this.channel = options.channel; this._listenerCallback = options.listenerCallback; } listen() { - console.log(`[IPC] Init: ${this.channel}`); this.remove(); ipcMain.on(this.channel, this._onPost); } @@ -82,7 +80,3 @@ export class IpcListener implements IIpcListener { } } - - - - diff --git a/src/ipc/handlers.ts b/src/ipc/handlers.ts index bc44fc2..5529662 100644 --- a/src/ipc/handlers.ts +++ b/src/ipc/handlers.ts @@ -1,10 +1,11 @@ "use strict"; -import { accountLogin, accountLogout } from "@/account"; +import { accountLogin, accountLogout, accountProfile } from "@/account"; import { IpcHandler } from "@/composables/useIpcMain"; import { flush } from "@/audio"; + const LOGIN_CHANNEL = "invoke-account-login"; const LOGOUT_CHANNEL = "invoke-account-logout"; const GET_AUDIO_CHANNEL = "invoke-audio-flush"; diff --git a/src/ipc/listeners.ts b/src/ipc/listeners.ts index f88887a..8ef5d45 100644 --- a/src/ipc/listeners.ts +++ b/src/ipc/listeners.ts @@ -2,9 +2,11 @@ import { IpcListener } from "@/composables/useIpcMain" import { sendMessage } from '@/session'; import { collect } from "@/audio"; +import { updateAppState } from "@/account"; const CLIENT_MESSAGE_CHANNEL = "post-session-send" const GET_AUDIO_CHANNEL = "post-audio-collect"; +const APP_MOUNT_CHANNEL = "post-app-mount"; export const messageListener = new IpcListener({ channel: CLIENT_MESSAGE_CHANNEL, @@ -15,3 +17,8 @@ export const audioChunkListener = new IpcListener({ channel: GET_AUDIO_CHANNEL, listenerCallback: collect }); + +export const appMountListener = new IpcListener({ + channel: APP_MOUNT_CHANNEL, + listenerCallback: updateAppState +}); diff --git a/src/main.ts b/src/main.ts index 40dd4da..a360835 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,9 +10,8 @@ */ import initIpcMain from "@/ipc/index"; -import { accountAuth } from "./account"; +import { accountAuth, updateAppState } from "./account"; import { launchSession } from "./session"; -import { ipcEmit } from "./composables/useEmitter"; import createWindow from "./window"; let authState: AuthState | null; @@ -31,12 +30,10 @@ export default async function main() { console.log('AUTH:', e); authState = null; } finally { - let profile = null; if (authState) { launchSession(authState.token as string); - profile = authState.profile; } - ipcEmit("set-profile", profile); + updateAppState(); } } diff --git a/src/render/App.vue b/src/render/App.vue index d53788f..a7645d1 100644 --- a/src/render/App.vue +++ b/src/render/App.vue @@ -23,14 +23,16 @@