realtime persistence. (#1952)

* feat: websocket persistence

* feat: socketio persistence

* feat: sse persistence

* feat: mqtt persistence

* fix: added types

* fix: typescript issues

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
0xc0Der
2021-12-02 16:50:24 +02:00
committed by GitHub
parent a508909471
commit cc81242294
10 changed files with 1124 additions and 73 deletions

View File

@@ -161,6 +161,22 @@ import debounce from "lodash/debounce"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { useSetting } from "~/newstore/settings"
import useWindowSize from "~/helpers/utils/useWindowSize"
import {
MQTTEndpoint$,
setMQTTEndpoint,
MQTTConnectingState$,
MQTTConnectionState$,
setMQTTConnectingState,
setMQTTConnectionState,
MQTTSubscriptionState$,
setMQTTSubscriptionState,
MQTTSocket$,
setMQTTSocket,
MQTTLog$,
setMQTTLog,
addMQTTLogLine,
} from "~/newstore/MQTTSession"
import { useStream } from "~/helpers/utils/composables"
export default defineComponent({
components: { Splitpanes, Pane },
@@ -170,21 +186,33 @@ export default defineComponent({
SIDEBAR: useSetting("SIDEBAR"),
COLUMN_LAYOUT: useSetting("COLUMN_LAYOUT"),
SIDEBAR_ON_LEFT: useSetting("SIDEBAR_ON_LEFT"),
url: useStream(MQTTEndpoint$, "", setMQTTEndpoint),
connectionState: useStream(
MQTTConnectionState$,
false,
setMQTTConnectionState
),
connectingState: useStream(
MQTTConnectingState$,
false,
setMQTTConnectingState
),
subscriptionState: useStream(
MQTTSubscriptionState$,
false,
setMQTTSubscriptionState
),
log: useStream(MQTTLog$, null, setMQTTLog),
client: useStream(MQTTSocket$, null, setMQTTSocket),
}
},
data() {
return {
url: "wss://test.mosquitto.org:8081",
isUrlValid: true,
client: null,
pub_topic: "",
sub_topic: "",
msg: "",
connectionState: false,
connectingState: false,
log: null,
manualDisconnect: false,
subscriptionState: false,
username: "",
password: "",
}
@@ -261,7 +289,7 @@ export default defineComponent({
onConnectionFailure() {
this.connectingState = false
this.connectionState = false
this.log.push({
addMQTTLogLine({
payload: this.$t("error.something_went_wrong"),
source: "info",
color: "#ff5555",
@@ -271,7 +299,7 @@ export default defineComponent({
onConnectionSuccess() {
this.connectingState = false
this.connectionState = true
this.log.push({
addMQTTLogLine({
payload: this.$t("state.connected_to", { name: this.url }),
source: "info",
color: "var(--accent-color)",
@@ -280,7 +308,7 @@ export default defineComponent({
this.$toast.success(this.$t("state.connected"))
},
onMessageArrived({ payloadString, destinationName }) {
this.log.push({
addMQTTLogLine({
payload: `Message: ${payloadString} arrived on topic: ${destinationName}`,
source: "info",
color: "var(--accent-color)",
@@ -297,7 +325,7 @@ export default defineComponent({
disconnect() {
this.manualDisconnect = true
this.client.disconnect()
this.log.push({
addMQTTLogLine({
payload: this.$t("state.disconnected_from", { name: this.url }),
source: "info",
color: "#ff5555",
@@ -318,14 +346,14 @@ export default defineComponent({
publish() {
try {
this.client.publish(this.pub_topic, this.msg, 0, false)
this.log.push({
addMQTTLogLine({
payload: `Published message: ${this.msg} to topic: ${this.pub_topic}`,
ts: new Date().toLocaleTimeString(),
source: "info",
color: "var(--accent-color)",
})
} catch (e) {
this.log.push({
addMQTTLogLine({
payload:
this.$t("error.something_went_wrong") +
`while publishing msg: ${this.msg} to topic: ${this.pub_topic}`,
@@ -349,7 +377,7 @@ export default defineComponent({
onFailure: this.usubFailure,
})
} catch (e) {
this.log.push({
addMQTTLogLine({
payload:
this.$t("error.something_went_wrong") +
`while subscribing to topic: ${this.sub_topic}`,
@@ -361,7 +389,7 @@ export default defineComponent({
},
usubSuccess() {
this.subscriptionState = !this.subscriptionState
this.log.push({
addMQTTLogLine({
payload:
`Successfully ` +
(this.subscriptionState ? "subscribed" : "unsubscribed") +
@@ -372,7 +400,7 @@ export default defineComponent({
})
},
usubFailure() {
this.log.push({
addMQTTLogLine({
payload:
`Failed to ` +
(this.subscriptionState ? "unsubscribe" : "subscribe") +

View File

@@ -89,7 +89,7 @@
class="hide-scrollbar !overflow-auto"
>
<AppSection label="response">
<RealtimeLog :title="$t('socketio.log')" :log="communication.log" />
<RealtimeLog :title="$t('socketio.log')" :log="log" />
</AppSection>
</Pane>
</Splitpanes>
@@ -188,6 +188,24 @@ import debounce from "lodash/debounce"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { useSetting } from "~/newstore/settings"
import useWindowSize from "~/helpers/utils/useWindowSize"
import {
SIOEndpoint$,
setSIOEndpoint,
SIOVersion$,
setSIOVersion,
SIOPath$,
setSIOPath,
SIOConnectionState$,
SIOConnectingState$,
setSIOConnectionState,
setSIOConnectingState,
SIOSocket$,
setSIOSocket,
SIOLog$,
setSIOLog,
addSIOLogLine,
} from "~/newstore/SocketIOSession"
import { useStream } from "~/helpers/utils/composables"
const socketIoClients = {
v4: ClientV4,
@@ -204,20 +222,27 @@ export default defineComponent({
COLUMN_LAYOUT: useSetting("COLUMN_LAYOUT"),
SIDEBAR_ON_LEFT: useSetting("SIDEBAR_ON_LEFT"),
socketIoClients,
url: useStream(SIOEndpoint$, "", setSIOEndpoint),
clientVersion: useStream(SIOVersion$, "", setSIOVersion),
path: useStream(SIOPath$, "", setSIOPath),
connectingState: useStream(
SIOConnectingState$,
false,
setSIOConnectingState
),
connectionState: useStream(
SIOConnectionState$,
false,
setSIOConnectionState
),
io: useStream(SIOSocket$, null, setSIOSocket),
log: useStream(SIOLog$, [], setSIOLog),
}
},
data() {
return {
// default version is set to v4
clientVersion: "v4",
url: "wss://hoppscotch-socketio.herokuapp.com",
path: "/socket.io",
isUrlValid: true,
connectingState: false,
connectionState: false,
io: null,
communication: {
log: null,
eventName: "",
inputs: [""],
},
@@ -267,7 +292,7 @@ export default defineComponent({
},
connect() {
this.connectingState = true
this.communication.log = [
this.log = [
{
payload: this.$t("state.connecting_to", { name: this.url }),
source: "info",
@@ -286,7 +311,7 @@ export default defineComponent({
this.io.on("connect", () => {
this.connectingState = false
this.connectionState = true
this.communication.log = [
this.log = [
{
payload: this.$t("state.connected_to", { name: this.url }),
source: "info",
@@ -298,7 +323,7 @@ export default defineComponent({
})
this.io.on("*", ({ data }) => {
const [eventName, message] = data
this.communication.log.push({
addSIOLogLine({
payload: `[${eventName}] ${message ? JSON.stringify(message) : ""}`,
source: "server",
ts: new Date().toLocaleTimeString(),
@@ -316,7 +341,7 @@ export default defineComponent({
this.io.on("disconnect", () => {
this.connectingState = false
this.connectionState = false
this.communication.log.push({
addSIOLogLine({
payload: this.$t("state.disconnected_from", { name: this.url }),
source: "info",
color: "#ff5555",
@@ -340,14 +365,14 @@ export default defineComponent({
this.disconnect()
this.connectingState = false
this.connectionState = false
this.communication.log.push({
addSIOLogLine({
payload: this.$t("error.something_went_wrong"),
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString(),
})
if (error !== null)
this.communication.log.push({
addSIOLogLine({
payload: error,
source: "info",
color: "#ff5555",
@@ -369,14 +394,14 @@ export default defineComponent({
if (this.io) {
this.io.emit(eventName, ...messages, (data) => {
// receive response from server
this.communication.log.push({
addSIOLogLine({
payload: `[${eventName}] ${JSON.stringify(data)}`,
source: "server",
ts: new Date().toLocaleTimeString(),
})
})
this.communication.log.push({
addSIOLogLine({
payload: `[${eventName}] ${JSON.stringify(messages)}`,
source: "client",
ts: new Date().toLocaleTimeString(),

View File

@@ -48,7 +48,7 @@
<AppSection label="response">
<ul>
<li>
<RealtimeLog :title="$t('sse.log')" :log="events.log" />
<RealtimeLog :title="$t('sse.log')" :log="log" />
<div id="result"></div>
</li>
</ul>
@@ -64,26 +64,47 @@ import "splitpanes/dist/splitpanes.css"
import debounce from "lodash/debounce"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import { useSetting } from "~/newstore/settings"
import {
SSEEndpoint$,
setSSEEndpoint,
SSEEventType$,
setSSEEventType,
SSESocket$,
setSSESocket,
SSEConnectingState$,
SSEConnectionState$,
setSSEConnectionState,
setSSEConnectingState,
SSELog$,
setSSELog,
addSSELogLine,
} from "~/newstore/SSESession"
import { useStream } from "~/helpers/utils/composables"
export default defineComponent({
components: { Splitpanes, Pane },
setup() {
return {
COLUMN_LAYOUT: useSetting("COLUMN_LAYOUT"),
connectionSSEState: useStream(
SSEConnectionState$,
false,
setSSEConnectionState
),
connectingState: useStream(
SSEConnectingState$,
false,
setSSEConnectingState
),
server: useStream(SSEEndpoint$, "", setSSEEndpoint),
eventType: useStream(SSEEventType$, "", setSSEEventType),
sse: useStream(SSESocket$, null, setSSESocket),
log: useStream(SSELog$, [], setSSELog),
}
},
data() {
return {
connectionSSEState: false,
connectingState: false,
server: "https://express-eventsource.herokuapp.com/events",
isUrlValid: true,
sse: null,
events: {
log: null,
input: "",
},
eventType: "data",
}
},
computed: {
@@ -120,7 +141,7 @@ export default defineComponent({
},
start() {
this.connectingState = true
this.events.log = [
this.log = [
{
payload: this.$t("state.connecting_to", { name: this.server }),
source: "info",
@@ -133,7 +154,7 @@ export default defineComponent({
this.sse.onopen = () => {
this.connectingState = false
this.connectionSSEState = true
this.events.log = [
this.log = [
{
payload: this.$t("state.connected_to", { name: this.server }),
source: "info",
@@ -148,7 +169,7 @@ export default defineComponent({
}
this.sse.onclose = () => {
this.connectionSSEState = false
this.events.log.push({
addSSELogLine({
payload: this.$t("state.disconnected_from", {
name: this.server,
}),
@@ -159,7 +180,7 @@ export default defineComponent({
this.$toast.error(this.$t("state.disconnected"))
}
this.sse.addEventListener(this.eventType, ({ data }) => {
this.events.log.push({
addSSELogLine({
payload: data,
source: "server",
ts: new Date().toLocaleTimeString(),
@@ -170,7 +191,7 @@ export default defineComponent({
this.$toast.error(this.$t("error.something_went_wrong"))
}
} else {
this.events.log = [
this.log = [
{
payload: this.$t("error.browser_support_sse"),
source: "info",
@@ -187,14 +208,14 @@ export default defineComponent({
handleSSEError(error) {
this.stop()
this.connectionSSEState = false
this.events.log.push({
addSSELogLine({
payload: this.$t("error.something_went_wrong"),
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString(),
})
if (error !== null)
this.events.log.push({
addSSELogLine({
payload: error,
source: "info",
color: "#ff5555",

View File

@@ -76,6 +76,12 @@
name="message"
type="text"
autocomplete="off"
@change="
updateProtocol(index, {
value: $event.target.value,
active: protocol.active,
})
"
/>
<span>
<ButtonSecondary
@@ -96,9 +102,10 @@
"
color="green"
@click.native="
protocol.active = protocol.hasOwnProperty('active')
? !protocol.active
: false
updateProtocol(index, {
value: protocol.value,
active: !protocol.active,
})
"
/>
</span>
@@ -133,10 +140,7 @@
class="hide-scrollbar !overflow-auto"
>
<AppSection label="response">
<RealtimeLog
:title="$t('websocket.log')"
:log="communication.log"
/>
<RealtimeLog :title="$t('websocket.log')" :log="log" />
</AppSection>
</Pane>
</Splitpanes>
@@ -191,6 +195,26 @@ import debounce from "lodash/debounce"
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
import useWindowSize from "~/helpers/utils/useWindowSize"
import { useSetting } from "~/newstore/settings"
import {
setWSEndpoint,
WSEndpoint$,
WSProtocols$,
setWSProtocols,
addWSProtocol,
deleteWSProtocol,
updateWSProtocol,
deleteAllWSProtocols,
WSSocket$,
setWSSocket,
setWSConnectionState,
setWSConnectingState,
WSConnectionState$,
WSConnectingState$,
addWSLogLine,
WSLog$,
setWSLog,
} from "~/newstore/WebSocketSession"
import { useStream } from "~/helpers/utils/composables"
export default defineComponent({
components: { Splitpanes, Pane },
@@ -200,21 +224,29 @@ export default defineComponent({
SIDEBAR: useSetting("SIDEBAR"),
COLUMN_LAYOUT: useSetting("COLUMN_LAYOUT"),
SIDEBAR_ON_LEFT: useSetting("SIDEBAR_ON_LEFT"),
url: useStream(WSEndpoint$, "", setWSEndpoint),
protocols: useStream(WSProtocols$, [], setWSProtocols),
connectionState: useStream(
WSConnectionState$,
false,
setWSConnectionState
),
connectingState: useStream(
WSConnectingState$,
false,
setWSConnectingState
),
socket: useStream(WSSocket$, null, setWSSocket),
log: useStream(WSLog$, [], setWSLog),
}
},
data() {
return {
connectionState: false,
connectingState: false,
url: "wss://hoppscotch-websocket.herokuapp.com",
isUrlValid: true,
socket: null,
communication: {
log: null,
input: "",
},
currentIndex: -1, // index of the message log array to put in input box
protocols: [],
activeProtocols: [],
}
},
@@ -251,7 +283,7 @@ export default defineComponent({
},
methods: {
clearContent() {
this.protocols = []
deleteAllWSProtocols()
},
debouncer: debounce(function () {
this.worker.postMessage({ type: "ws", url: this.url })
@@ -266,7 +298,7 @@ export default defineComponent({
else return this.disconnect()
},
connect() {
this.communication.log = [
this.log = [
{
payload: this.$t("state.connecting_to", { name: this.url }),
source: "info",
@@ -279,7 +311,7 @@ export default defineComponent({
this.socket.onopen = () => {
this.connectingState = false
this.connectionState = true
this.communication.log = [
this.log = [
{
payload: this.$t("state.connected_to", { name: this.url }),
source: "info",
@@ -294,7 +326,7 @@ export default defineComponent({
}
this.socket.onclose = () => {
this.connectionState = false
this.communication.log.push({
addWSLogLine({
payload: this.$t("state.disconnected_from", { name: this.url }),
source: "info",
color: "#ff5555",
@@ -303,7 +335,7 @@ export default defineComponent({
this.$toast.error(this.$t("state.disconnected"))
}
this.socket.onmessage = ({ data }) => {
this.communication.log.push({
addWSLogLine({
payload: data,
source: "server",
ts: new Date().toLocaleTimeString(),
@@ -328,14 +360,14 @@ export default defineComponent({
handleError(error) {
this.disconnect()
this.connectionState = false
this.communication.log.push({
addWSLogLine({
payload: this.$t("error.something_went_wrong"),
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString(),
})
if (error !== null)
this.communication.log.push({
addWSLogLine({
payload: error,
source: "info",
color: "#ff5555",
@@ -345,7 +377,7 @@ export default defineComponent({
sendMessage() {
const message = this.communication.input
this.socket.send(message)
this.communication.log.push({
addWSLogLine({
payload: message,
source: "client",
ts: new Date().toLocaleTimeString(),
@@ -353,7 +385,7 @@ export default defineComponent({
this.communication.input = ""
},
walkHistory(direction) {
const clientMessages = this.communication.log.filter(
const clientMessages = this.log.filter(
({ source }) => source === "client"
)
const length = clientMessages.length
@@ -389,11 +421,11 @@ export default defineComponent({
}
},
addProtocol() {
this.protocols.push({ value: "", active: true })
addWSProtocol({ value: "", active: true })
},
deleteProtocol({ index }) {
const oldProtocols = this.protocols.slice()
this.$delete(this.protocols, index)
deleteWSProtocol(index)
this.$toast.success(this.$t("state.deleted"), {
action: {
text: this.$t("action.undo"),
@@ -405,6 +437,9 @@ export default defineComponent({
},
})
},
updateProtocol(index, updated) {
updateWSProtocol(index, updated)
},
},
})
</script>