diff --git a/package-lock.json b/package-lock.json index 3b0eee9..cef1dc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1980,15 +1980,6 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2357,9 +2348,9 @@ "dev": true }, "chatoverflow-api": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/chatoverflow-api/-/chatoverflow-api-0.2.5.tgz", - "integrity": "sha512-3Y7lTKW8YrU8m3PNpxvGm7ZPLrR7ewHsZeoUdEAjFD37T7wBmcQNMwYHWQHpCCc++pHLG3nc1uyJjevJafrLug==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/chatoverflow-api/-/chatoverflow-api-0.3.2.tgz", + "integrity": "sha512-M0xeIpy6J4UKuG+3Ss1I/ycsdih6N9PEYSvunqgTAB7B2uNGMC6q/bCMKC+7Rm8NMLf4R7KAVH/S4BGA9+9suw==", "requires": { "tslib": "^1.9.0" } @@ -2824,15 +2815,6 @@ "which": "^1.2.9" } }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.x.x" - } - }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", @@ -4167,7 +4149,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4188,12 +4171,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4208,17 +4193,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4335,7 +4323,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4347,6 +4336,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4361,6 +4351,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4368,12 +4359,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4392,6 +4385,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4472,7 +4466,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4484,6 +4479,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4569,7 +4565,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4605,6 +4602,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4624,6 +4622,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4667,12 +4666,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -4719,24 +4720,6 @@ "globule": "^1.0.0" } }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dev": true, - "requires": { - "is-property": "^1.0.2" - } - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "^1.0.0" - } - }, "genfun": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", @@ -5101,18 +5084,6 @@ "minimalistic-assert": "^1.0.1" } }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -5130,12 +5101,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -5887,25 +5852,6 @@ "integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA==", "dev": true }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true - }, - "is-my-json-valid": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz", - "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==", - "dev": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -5989,12 +5935,6 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -6292,12 +6232,6 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6462,12 +6396,6 @@ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true - }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -6480,12 +6408,6 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "lodash.mergewith": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", - "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", - "dev": true - }, "lodash.tail": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", @@ -7216,9 +7138,9 @@ } }, "node-sass": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", - "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", + "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -7228,15 +7150,13 @@ "get-stdin": "^4.0.1", "glob": "^7.0.3", "in-publish": "^2.0.0", - "lodash.assign": "^4.2.0", - "lodash.clonedeep": "^4.3.2", - "lodash.mergewith": "^4.6.0", + "lodash": "^4.17.11", "meow": "^3.7.0", "mkdirp": "^0.5.1", - "nan": "^2.10.0", - "node-gyp": "^3.3.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", "npmlog": "^4.0.0", - "request": "~2.79.0", + "request": "^2.88.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" @@ -7248,24 +7168,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -7279,106 +7181,11 @@ "supports-color": "^2.0.0" } }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - } - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "dev": true - }, - "request": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", - "dev": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "qs": "~6.3.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1", - "uuid": "^3.0.0" - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true - }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "dev": true, - "requires": { - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true } } }, @@ -9634,15 +9441,6 @@ } } }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, "sockjs": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", @@ -10051,12 +9849,6 @@ "is-hexadecimal": "^1.0.0" } }, - "stringstream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", - "dev": true - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", diff --git a/package.json b/package.json index 878f49a..c75fe93 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@angular/platform-browser-dynamic": "7.2.1", "@angular/router": "7.2.1", "@types/crypto-js": "^3.1.43", - "chatoverflow-api": "^0.2.5", + "chatoverflow-api": "^0.3.2", "classlist.js": "1.1.20150312", "core-js": "2.5.6", "crypto-js": "^3.1.9-1", @@ -56,7 +56,7 @@ "@types/node": "10.1.2", "@types/nvd3": "1.8.38", "codelyzer": "4.3.0", - "node-sass": "4.9.0", + "node-sass": "^4.12.0", "pre-commit": "1.2.2", "stylelint": "9.2.1", "stylelint-config-recommended-scss": "3.2.0", diff --git a/src/app/pages/betterrepl/betterrepl.component.html b/src/app/pages/betterrepl/betterrepl.component.html index 2d2612b..80a35da 100644 --- a/src/app/pages/betterrepl/betterrepl.component.html +++ b/src/app/pages/betterrepl/betterrepl.component.html @@ -284,7 +284,7 @@

Start / Stop / Log

Show log -
{{ instanceLogOutput }}
+
{{ instanceLogOutput.join("\n") }}
diff --git a/src/app/pages/betterrepl/betterrepl.component.ts b/src/app/pages/betterrepl/betterrepl.component.ts index 4196cf7..ef90e68 100644 --- a/src/app/pages/betterrepl/betterrepl.component.ts +++ b/src/app/pages/betterrepl/betterrepl.component.ts @@ -1,4 +1,4 @@ -import {Component, HostBinding} from "@angular/core"; +import {Component, HostBinding, ViewChild, ElementRef} from "@angular/core"; import {UpgradableComponent} from "theme/components/upgradable"; import { ResultMessage, @@ -22,7 +22,7 @@ import { PluginLogMessageDTO } from "chatoverflow-api"; import {CryptoService} from "../../../crypto.service"; -import {interval} from "rxjs"; +import { EventService } from "../../../event.service"; @Component({ selector: 'better-repl', @@ -31,6 +31,7 @@ import {interval} from "rxjs"; }) export class BetterREPLComponent extends UpgradableComponent { @HostBinding('class.mdl-grid') private readonly mdlGrid = true; + @ViewChild('instanceLog') private readonly instanceLog: ElementRef; private lastRequestCommand = "..."; private lastRequestMessage = "Please send a request to the server..."; @@ -65,14 +66,58 @@ export class BetterREPLComponent extends UpgradableComponent { private changeReqTypeValue = ""; private changeReqValueValue = ""; - private pingpongCounter = interval(5000); - private pingpongStarted = false; - private pingPongSubscriber = null; - constructor(private configService: ConfigService, private typeService: TypeService, private connectorService: ConnectorService, private instanceService: InstanceService, - private cryptoService: CryptoService) { + private cryptoService: CryptoService, private eventService: EventService) { super(); + + this.addEventListeners(); + } + + private addEventListeners() { + this.eventService.addEventListener("error", () => { + console.log("Lost connection. Trying to reconnect..."); + setTimeout(() => this.login(this.lastPassword), 1000); + }); + + this.eventService.addEventListener("instance", ({ action, data }) => { + const instance = this.pluginInstances.find(i => i.instanceName === data.name); + if (!instance) + return; + + switch (action) { + case "start": + instance.isRunning = true; + break; + case "stop": + instance.isRunning = false; + break; + case "log": + if (data.message && data.timestamp) { + if (!instance.log) + instance.log = []; + + instance.log.push({ timestamp: new Date(data.timestamp).toLocaleTimeString(), message: data.message }); + if (data.name === this.instanceNameSSValue) { + this.instanceLogOutput = this.getInstanceLog(instance); + this.scrollToLogEnd(); + } + } + break; + } + }); + } + + private scrollToLogEnd(force?: boolean) { + if (this.instanceLog && this.instanceLog.nativeElement) { + const element = this.instanceLog.nativeElement; + if (force || element.scrollTop + element.clientHeight === element.scrollHeight) + setTimeout(() => element.scrollTop = element.scrollHeight, 0); + } + } + + private getInstanceLog(instance: PluginInstance) { + return instance.log ? instance.log.map(log => `${log.timestamp} - ${log.message}`) : []; } reloadEverything(clearForms: boolean) { @@ -155,45 +200,28 @@ export class BetterREPLComponent extends UpgradableComponent { this.lastPassword = password; } this.reloadEverything(!response.success); - this.handlePingpong(true); + this.handleEvents(true); }, error => { this.logGenericError("postLogin"); this.reloadEverything(true); }); } - handlePingpong(start: boolean) { + handleEvents(start: boolean) { + if (!("EventSource" in window)) { + console.warn("Event source is not supported"); + return; + } + if (start) { - if (!this.pingpongStarted) { - this.pingPongSubscriber = this.pingpongCounter.subscribe(n => this.pingpong()); - this.pingpongStarted = true; + if (!this.eventService.isRunning()) { + this.eventService.start(this.authKey); } } else { - if (this.pingPongSubscriber != null) { - this.pingPongSubscriber.unsubscribe(); - } - this.pingpongStarted = false; + this.eventService.close(); } } - pingpong() { - this.configService.postPing(this.authKey).subscribe((response: ResultMessage) => { - if (response.success) { - // Pong - } else { - this.reloadEverything(true); - } - }, error => { - if (error.status == 401 || error.status == 400) { - // Try to login again - this.login(this.lastPassword); - - } else if (error.status == 0) { - this.reloadEverything(true); - } - }) - } - register(password: string) { this.configService.postRegister({password: password}).subscribe((response: ResultMessage) => { this.logResultMessage("postRegister", response); @@ -202,7 +230,7 @@ export class BetterREPLComponent extends UpgradableComponent { this.reloadEverything(false); } this.reloadEverything(!response.success); - this.handlePingpong(true); + this.handleEvents(true); }, error => { this.logGenericError("postRegister"); this.reloadEverything(true); @@ -303,8 +331,14 @@ export class BetterREPLComponent extends UpgradableComponent { } getInstances() { - this.pluginInstances = []; this.instanceService.getInstances(this.authKey).subscribe((response: Array) => { + if (this.pluginInstances) { + response.forEach(instance => { + const previousInstance = this.pluginInstances.find(i => i.instanceName === instance.instanceName); + if (previousInstance) + instance.log = previousInstance.log; + }); + } this.pluginInstances = response; this.logRequest("getInstances", true, JSON.stringify(response)); }, error => this.logGenericError("getInstances")); @@ -391,6 +425,8 @@ export class BetterREPLComponent extends UpgradableComponent { this.miPluginAuthorValue = instance.pluginAuthor; this.miInstanceNameValue = instance.instanceName; this.requirementsInstanceNameValue = instance.instanceName; + this.instanceLogOutput = this.getInstanceLog(instance); + this.scrollToLogEnd(true); } copyRequirementData(requirement: Requirement, instanceName: string) { diff --git a/src/event.service.ts b/src/event.service.ts new file mode 100644 index 0000000..69fd9c4 --- /dev/null +++ b/src/event.service.ts @@ -0,0 +1,68 @@ +import { EventsService } from "chatoverflow-api"; +import { Injectable } from "@angular/core"; + +interface EventMessage { + action: string; + data: T; +} + +interface EventTypeMap { + close: Event; + error: Event; + + instance: EventMessage<{ name: string, message?: string, timestamp?: string }>; +} + +@Injectable({ + providedIn: 'root' +}) +export class EventService extends EventsService { + private readonly eventListeners: { [type: string]: ((e: Event | EventMessage) => void)[] } = {}; + private eventSource: EventSource = null; + + isRunning() { + return this.eventSource && this.eventSource.readyState !== EventSource["CLOSED"]; + } + + addEventListener(type: TKey, listener: (e: EventTypeMap[TKey]) => void) { + if (!this.eventListeners[type]) { + this.eventListeners[type] = []; + if (this.eventSource && type !== "close" && type !== "error") { + this.addListener(type); + } + } + + this.eventListeners[type].push(listener); + } + + start(authKey: string) { + this.eventSource = new EventSource(`${this.basePath}/events?authKey=${authKey}`); + this.eventSource.addEventListener("close", this.close); + + for (const type in this.eventListeners) { + if (this.eventListeners.hasOwnProperty(type)) { + this.addListener(type); + } + } + } + + close = () => { + if (this.eventSource) { + this.eventSource.close(); + this.eventSource = null; + } + } + + private addListener(type: string) { + if (type === "close" || type === "error") { + this.eventListeners[type].forEach(listener => this.eventSource.addEventListener(type, listener)); + } else { + this.eventSource.addEventListener(type, (e: MessageEvent) => this.dispatch(type, e)); + } + } + + private dispatch(type: string, e: MessageEvent) { + const message: EventMessage = JSON.parse(e.data); + this.eventListeners[type].forEach(listener => listener(message)); + } +} \ No newline at end of file