Add Socketio support

and modify some websocket and sse code to pick up common function and component
This commit is contained in:
moonrailgun
2020-03-04 14:40:44 +08:00
parent d6fd01d210
commit 14701369bd
7 changed files with 562 additions and 87 deletions

View File

@@ -0,0 +1,58 @@
<template>
<div>
<label for="log">{{ title }}</label>
<div name="log" class="realtime-log" ref="log">
<span v-if="log">
<span v-for="(logEntry, index) in log" :style="{ color: logEntry.color }" :key="index"
>@ {{ logEntry.ts }}{{ getSourcePrefix(logEntry.source) }}{{ logEntry.payload }}</span
>
</span>
<span v-else>{{ $t("waiting_for_connection") }}</span>
</div>
</div>
</template>
<style scoped lang="scss">
div.realtime-log {
margin: 4px;
padding: 8px 16px;
width: calc(100% - 8px);
border-radius: 8px;
background-color: var(--bg-dark-color);
color: var(--fg-color);
height: 256px;
overflow: auto;
&,
span {
font-size: 16px;
font-family: "Roboto Mono", monospace;
font-weight: 400;
}
span {
display: block;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-all;
}
}
</style>
<script>
import { getSourcePrefix } from "~/functions/utils/string"
export default {
props: ["log", "title"],
methods: {
getSourcePrefix,
},
updated: function() {
this.$nextTick(function() {
if (this.$refs.log) {
this.$refs.log.scrollBy(0, this.$refs.log.scrollHeight + 100)
}
})
},
}
</script>

View File

@@ -0,0 +1,216 @@
<template>
<div>
<pw-section class="blue" :label="$t('request')" ref="request">
<ul>
<li>
<label for="url">{{ $t("url") }}</label>
<input
id="url"
type="url"
spellcheck="false"
:class="{ error: !urlValid }"
v-model="url"
@keyup.enter="urlValid ? toggleConnection() : null"
/>
</li>
<div>
<li>
<label for="connect" class="hide-on-small-screen">&nbsp;</label>
<button :disabled="!urlValid" id="connect" name="connect" @click="toggleConnection">
{{ !connectionState ? $t("connect") : $t("disconnect") }}
<span>
<i class="material-icons">
{{ !connectionState ? "sync" : "sync_disabled" }}
</i>
</span>
</button>
</li>
</div>
</ul>
</pw-section>
<pw-section class="purple" :label="$t('communication')" id="response" ref="response">
<ul>
<li>
<realtime-log :log="communication.log" />
</li>
</ul>
<ul>
<li>
<label for="event_name">{{ $t("event_name") }}</label>
<input
name="event_name"
type="text"
v-model="communication.eventName"
:readonly="!connectionState"
/>
</li>
</ul>
<ul>
<li>
<label for="message">{{ $t("message") }}</label>
<input
name="message"
type="text"
v-model="communication.input"
:readonly="!connectionState"
@keyup.enter="connectionState ? sendMessage() : null"
/>
</li>
<div>
<li>
<label for="send" class="hide-on-small-screen">&nbsp;</label>
<button id="send" name="send" :disabled="!connectionState" @click="sendMessage">
{{ $t("send") }}
<span>
<i class="material-icons">send</i>
</span>
</button>
</li>
</div>
</ul>
</pw-section>
</div>
</template>
<script>
import { wsValid } from "~/functions/utils/valid"
import io from "socket.io-client"
import realtimeLog from "./log"
export default {
components: {
"pw-section": () => import("../../components/layout/section"),
realtimeLog,
},
data() {
return {
url: "wss://echo.websocket.org",
connectionState: false,
io: null,
communication: {
log: null,
eventName: "",
input: "",
},
}
},
computed: {
urlValid() {
return wsValid(this.url)
},
},
methods: {
toggleConnection() {
// If it is connecting:
if (!this.connectionState) return this.connect()
// Otherwise, it's disconnecting.
else return this.disconnect()
},
connect() {
this.communication.log = [
{
payload: this.$t("connecting_to", { name: this.url }),
source: "info",
color: "var(--ac-color)",
},
]
try {
this.io = new io(this.url)
this.io.on("connect", () => {
this.connectionState = true
this.communication.log = [
{
payload: this.$t("connected_to", { name: this.url }),
source: "info",
color: "var(--ac-color)",
ts: new Date().toLocaleTimeString(),
},
]
this.$toast.success(this.$t("connected"), {
icon: "sync",
})
})
this.io.on("message", data => {
this.communication.log.push({
payload: data,
source: "server",
ts: new Date().toLocaleTimeString(),
})
})
this.io.on("connect_error", error => {
this.handleError(error)
})
this.io.on("reconnect_error", error => {
this.handleError(error)
})
this.io.on("error", data => {
this.handleError()
})
this.io.on("disconnect", () => {
this.connectionState = false
this.communication.log.push({
payload: this.$t("disconnected_from", { name: this.url }),
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString(),
})
this.$toast.error(this.$t("disconnected"), {
icon: "sync_disabled",
})
})
} catch (ex) {
this.handleError(ex)
this.$toast.error(this.$t("something_went_wrong"), {
icon: "error",
})
}
},
disconnect() {
this.io.close()
},
handleError(error) {
this.disconnect()
this.connectionState = false
this.communication.log.push({
payload: this.$t("error_occurred"),
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString(),
})
if (error !== null)
this.communication.log.push({
payload: error,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString(),
})
},
sendMessage() {
const eventName = this.communication.eventName
const message = this.communication.input
if (this.io) {
// TODO: support only one argument now
// maybe should support more argument
this.io.emit(eventName, message, data => {
// receive response from server
this.communication.log.push({
payload: `[${eventName}] ${JSON.stringify(data)}`,
source: "server",
ts: new Date().toLocaleTimeString(),
})
})
this.communication.log.push({
payload: `[${eventName}] ${message}`,
source: "client",
ts: new Date().toLocaleTimeString(),
})
this.communication.input = ""
}
},
},
}
</script>

12
functions/utils/string.js Normal file
View File

@@ -0,0 +1,12 @@
export function getSourcePrefix(source) {
const sourceEmojis = {
// Source used for info messages.
info: "\t [INFO]:\t",
// Source used for client to server messages.
client: "\t👽 [SENT]:\t",
// Source used for server to client messages.
server: "\t📥 [RECEIVED]:\t",
}
if (Object.keys(sourceEmojis).includes(source)) return sourceEmojis[source]
return ""
}

27
functions/utils/valid.js Normal file
View File

@@ -0,0 +1,27 @@
/**
* valid url for ws/wss
*/
export function wsValid(url) {
const protocol = "^(wss?:\\/\\/)?"
const validIP = new RegExp(
`${protocol}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
)
const validHostname = new RegExp(
`${protocol}(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$`
)
return validIP.test(url) || validHostname.test(url)
}
/**
* valid url for http/https
*/
export function sseValid(url) {
const protocol = "^(https?:\\/\\/)?"
const validIP = new RegExp(
`${protocol}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
)
const validHostname = new RegExp(
`${protocol}(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$`
)
return validIP.test(url) || validHostname.test(url)
}

233
package-lock.json generated
View File

@@ -2207,6 +2207,11 @@
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
},
"after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"aggregate-error": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -2418,6 +2423,11 @@
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
},
"arrify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
@@ -2612,6 +2622,11 @@
"object.assign": "^4.1.0"
}
},
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -2667,6 +2682,11 @@
}
}
},
"base64-arraybuffer": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
@@ -2681,6 +2701,14 @@
"tweetnacl": "^0.14.3"
}
},
"better-assert": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
"requires": {
"callsite": "1.0.0"
}
},
"bfj": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz",
@@ -2711,6 +2739,11 @@
"file-uri-to-path": "1.0.0"
}
},
"blob": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
},
"block-stream": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@@ -3141,6 +3174,11 @@
"caller-callsite": "^2.0.0"
}
},
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
},
"callsites": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
@@ -3601,11 +3639,21 @@
"integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
"dev": true
},
"component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
},
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
},
"component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"compressible": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
@@ -4527,6 +4575,59 @@
"once": "^1.4.0"
}
},
"engine.io-client": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz",
"integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==",
"requires": {
"component-emitter": "1.2.1",
"component-inherit": "0.0.3",
"debug": "~4.1.0",
"engine.io-parser": "~2.2.0",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"ws": "~6.1.0",
"xmlhttprequest-ssl": "~1.5.4",
"yeast": "0.1.2"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"ws": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
"requires": {
"async-limiter": "~1.0.0"
}
}
}
},
"engine.io-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
"integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
"requires": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.5",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"enhanced-resolve": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz",
@@ -6169,6 +6270,26 @@
}
}
},
"has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"requires": {
"isarray": "2.0.1"
},
"dependencies": {
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
},
"has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -6687,6 +6808,11 @@
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
},
"indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
},
"infer-owner": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
@@ -8638,6 +8764,11 @@
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-component": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
},
"object-copy": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
@@ -8938,6 +9069,22 @@
"json-parse-better-errors": "^1.0.1"
}
},
"parseqs": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
"requires": {
"better-assert": "~1.0.0"
}
},
"parseuri": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
"requires": {
"better-assert": "~1.0.0"
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -11300,6 +11447,77 @@
}
}
},
"socket.io-client": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
"integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
"requires": {
"backo2": "1.0.2",
"base64-arraybuffer": "0.1.5",
"component-bind": "1.0.0",
"component-emitter": "1.2.1",
"debug": "~4.1.0",
"engine.io-client": "~3.4.0",
"has-binary2": "~1.0.2",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"object-component": "0.0.3",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"socket.io-parser": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
"requires": {
"component-emitter": "1.2.1",
"debug": "~3.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"sort-keys": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
@@ -12131,6 +12349,11 @@
"rimraf": "^2.6.3"
}
},
"to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
},
"to-arraybuffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -13818,6 +14041,11 @@
"resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
"integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw="
},
"xmlhttprequest-ssl": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -13958,6 +14186,11 @@
}
}
}
},
"yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
}
}
}

View File

@@ -43,6 +43,7 @@
"graphql-language-service-interface": "^2.3.3",
"nuxt": "^2.11.0",
"nuxt-i18n": "^6.6.0",
"socket.io-client": "^2.3.0",
"v-tooltip": "^2.0.3",
"vue-virtual-scroll-list": "^1.4.6",
"vuefire": "^2.2.1",

View File

@@ -36,19 +36,7 @@
<pw-section class="purple" :label="$t('communication')" id="response" ref="response">
<ul>
<li>
<label for="log">{{ $t("log") }}</label>
<div id="log" name="log" class="log">
<span v-if="communication.log">
<span
v-for="(logEntry, index) in communication.log"
:style="{ color: logEntry.color }"
:key="index"
>@ {{ logEntry.ts }}{{ getSourcePrefix(logEntry.source)
}}{{ logEntry.payload }}</span
>
</span>
<span v-else>{{ $t("waiting_for_connection") }}</span>
</div>
<realtime-log :title="$t('log')" :log="communication.log" />
</li>
</ul>
<ul>
@@ -116,59 +104,31 @@
<pw-section class="purple" :label="$t('communication')" id="response" ref="response">
<ul>
<li>
<label for="log">{{ $t("events") }}</label>
<div id="log" name="log" class="log">
<span v-if="events.log">
<span
v-for="(logEntry, index) in events.log"
:style="{ color: logEntry.color }"
:key="index"
>@ {{ logEntry.ts }}{{ getSourcePrefix(logEntry.source)
}}{{ logEntry.payload }}</span
>
</span>
<span v-else>{{ $t("waiting_for_connection") }}</span>
</div>
<realtime-log :title="$t('events')" :log="events.log" />
<div id="result"></div>
</li>
</ul>
</pw-section>
</div>
<input id="tab-three" type="radio" name="options" />
<label for="tab-three">{{ $t("socket.io") }}</label>
<div class="tab">
<socketio />
</div>
</section>
</div>
</template>
<style scoped lang="scss">
div.log {
margin: 4px;
padding: 8px 16px;
width: calc(100% - 8px);
border-radius: 8px;
background-color: var(--bg-dark-color);
color: var(--fg-color);
height: 256px;
overflow: auto;
&,
span {
font-size: 16px;
font-family: "Roboto Mono", monospace;
font-weight: 400;
}
span {
display: block;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-all;
}
}
</style>
<script>
import { wsValid, sseValid } from "~/functions/utils/valid"
import realtimeLog from "~/components/realtime/log"
export default {
components: {
"pw-section": () => import("../components/layout/section"),
socketio: () => import("../components/realtime/socketio"),
realtimeLog,
},
data() {
return {
@@ -190,24 +150,10 @@ export default {
},
computed: {
urlValid() {
const protocol = "^(wss?:\\/\\/)?"
const validIP = new RegExp(
`${protocol}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
)
const validHostname = new RegExp(
`${protocol}(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$`
)
return validIP.test(this.url) || validHostname.test(this.url)
return wsValid(this.url)
},
serverValid() {
const protocol = "^(https?:\\/\\/)?"
const validIP = new RegExp(
`${protocol}(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`
)
const validHostname = new RegExp(
`${protocol}(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$`
)
return validIP.test(this.server) || validHostname.test(this.server)
return sseValid(this.server)
},
},
methods: {
@@ -304,18 +250,6 @@ export default {
const el = target.parentNode.className
document.getElementsByClassName(el)[0].classList.toggle("hidden")
},
getSourcePrefix(source) {
const sourceEmojis = {
// Source used for info messages.
info: "\t [INFO]:\t",
// Source used for client to server messages.
client: "\t👽 [SENT]:\t",
// Source used for server to client messages.
server: "\t📥 [RECEIVED]:\t",
}
if (Object.keys(sourceEmojis).includes(source)) return sourceEmojis[source]
return ""
},
toggleSSEConnection() {
// If it is connecting:
if (!this.connectionSSEState) return this.start()
@@ -408,11 +342,5 @@ export default {
this.sse.close()
},
},
updated: function() {
this.$nextTick(function() {
const divLog = document.getElementById("log")
divLog.scrollBy(0, divLog.scrollHeight + 100)
})
},
}
</script>