Refactored the Socket connection and callbacks to work properly
This commit is contained in:
parent
4068822489
commit
dbf6763a99
|
@ -9,6 +9,7 @@ import React from "react";
|
||||||
import { createMessageConnection } from "vscode-jsonrpc";
|
import { createMessageConnection } from "vscode-jsonrpc";
|
||||||
import RijuMessageReader from "../services/RijuMessageReader";
|
import RijuMessageReader from "../services/RijuMessageReader";
|
||||||
import RijuMessageWriter from "../services/RijuMessageWriter";
|
import RijuMessageWriter from "../services/RijuMessageWriter";
|
||||||
|
import { SocketManager } from "../services/WS";
|
||||||
import { EventEmitter } from "../utils/EventEmitter";
|
import { EventEmitter } from "../utils/EventEmitter";
|
||||||
|
|
||||||
let clientDisposable = null;
|
let clientDisposable = null;
|
||||||
|
@ -20,11 +21,11 @@ const RijuEditor = (props) => {
|
||||||
const monacoRef = React.useRef();
|
const monacoRef = React.useRef();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
EventEmitter.subscribe("lspStarted", (data) => {
|
const token1 = EventEmitter.subscribe("lspStarted", (data) => {
|
||||||
const { message, socket } = data;
|
const { message } = data;
|
||||||
initLSP(socket, message, monacoRef.current, editorRef.current);
|
initLSP(message, monacoRef.current, editorRef.current);
|
||||||
});
|
});
|
||||||
EventEmitter.subscribe("lspStopped", () => {
|
const token2 = EventEmitter.subscribe("lspStopped", () => {
|
||||||
if (clientDisposable) {
|
if (clientDisposable) {
|
||||||
clientDisposable.dispose();
|
clientDisposable.dispose();
|
||||||
clientDisposable = null;
|
clientDisposable = null;
|
||||||
|
@ -34,9 +35,11 @@ const RijuEditor = (props) => {
|
||||||
servicesDisposable = null;
|
servicesDisposable = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
() => EventEmitter.unsubcribe(token1, token2);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const initLSP = (socket, message, monaco, editor) => {
|
const initLSP = (message, monaco, editor) => {
|
||||||
|
const socket = SocketManager.socket;
|
||||||
const services = MonacoServices.create(editor, {
|
const services = MonacoServices.create(editor, {
|
||||||
rootUri: `file://${message.root}`,
|
rootUri: `file://${message.root}`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,11 +19,11 @@ function RijuTerminal() {
|
||||||
term.write("Connecting to server...");
|
term.write("Connecting to server...");
|
||||||
|
|
||||||
window.addEventListener("resize", () => fitAddon.fit());
|
window.addEventListener("resize", () => fitAddon.fit());
|
||||||
EventEmitter.subscribe("resize", () => {
|
const token1 = EventEmitter.subscribe("resize", () => {
|
||||||
const event = new Event("resize");
|
const event = new Event("resize");
|
||||||
window.dispatchEvent(event);
|
window.dispatchEvent(event);
|
||||||
});
|
});
|
||||||
EventEmitter.subscribe("terminal", (payload) => {
|
const token2 = EventEmitter.subscribe("terminal", (payload) => {
|
||||||
if (!payload) return;
|
if (!payload) return;
|
||||||
const { type, data } = payload;
|
const { type, data } = payload;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -41,6 +41,8 @@ function RijuTerminal() {
|
||||||
term.onData((data) => {
|
term.onData((data) => {
|
||||||
EventEmitter.dispatch("send", { event: "terminalInput", input: data });
|
EventEmitter.dispatch("send", { event: "terminalInput", input: data });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
() => EventEmitter.unsubcribe(token1, token2);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -24,6 +24,7 @@ import React, { useEffect, useRef, useState } from "react";
|
||||||
import Layouts from "../../components/Layouts";
|
import Layouts from "../../components/Layouts";
|
||||||
import langs from "../../assets/langs.json";
|
import langs from "../../assets/langs.json";
|
||||||
import { EventEmitter } from "../../utils/EventEmitter";
|
import { EventEmitter } from "../../utils/EventEmitter";
|
||||||
|
import { SocketManager } from "../../services/WS";
|
||||||
ansi.rgb = {
|
ansi.rgb = {
|
||||||
green: "#00FD61",
|
green: "#00FD61",
|
||||||
};
|
};
|
||||||
|
@ -42,7 +43,7 @@ const CodeRunner = (props) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { langConfig } = props;
|
const { langConfig } = props;
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
const [config, setConfig] = useState(langConfig);
|
const [config] = useState(langConfig);
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
const [isRunning, setRunning] = useState(false);
|
const [isRunning, setRunning] = useState(false);
|
||||||
const [isFormatting, setFormatting] = useState(false);
|
const [isFormatting, setFormatting] = useState(false);
|
||||||
|
@ -56,179 +57,162 @@ const CodeRunner = (props) => {
|
||||||
EventEmitter.dispatch("terminal", { type, data });
|
EventEmitter.dispatch("terminal", { type, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
function connect() {
|
const handleWsOpen = (event) => {
|
||||||
serviceLogBuffers = {};
|
setStatus("connected");
|
||||||
serviceLogLines = {};
|
};
|
||||||
setStatus("connecting");
|
|
||||||
const socket = new WebSocket(
|
const handleWsMessage = (event) => {
|
||||||
// (document.location.protocol === "http:" ? "ws://" : "wss://") +
|
let message;
|
||||||
"wss://" +
|
try {
|
||||||
"riju.codes" +
|
message = JSON.parse(event.data);
|
||||||
`/api/v1/ws?lang=${encodeURIComponent(config.id)}`
|
} catch (err) {
|
||||||
);
|
console.error("Malformed message from server:", event.data);
|
||||||
socket.addEventListener("open", () => {
|
return;
|
||||||
console.log("Successfully connected to server playground");
|
}
|
||||||
setStatus("connected");
|
if (
|
||||||
});
|
DEBUG &&
|
||||||
EventEmitter.subscribe("send", (payload) => {
|
message &&
|
||||||
if (DEBUG) {
|
message.event !== "lspOutput" &&
|
||||||
console.log("SEND:", payload);
|
message.event !== "serviceLog"
|
||||||
}
|
) {
|
||||||
if (socket) {
|
console.log("RECEIVE:", message);
|
||||||
socket.send(JSON.stringify(payload));
|
}
|
||||||
}
|
if (message && message.event && message.event !== "error") {
|
||||||
});
|
// retryDelayMs = initialRetryDelayMs;
|
||||||
socket.addEventListener("message", async (event) => {
|
}
|
||||||
let message;
|
switch (message && message.event) {
|
||||||
try {
|
case "terminalClear":
|
||||||
message = JSON.parse(event.data);
|
// term.reset();
|
||||||
} catch (err) {
|
sendToTerminal("terminalClear");
|
||||||
console.error("Malformed message from server:", event.data);
|
|
||||||
return;
|
return;
|
||||||
}
|
case "terminalOutput":
|
||||||
if (
|
if (typeof message.output !== "string") {
|
||||||
DEBUG &&
|
|
||||||
message &&
|
|
||||||
message.event !== "lspOutput" &&
|
|
||||||
message.event !== "serviceLog"
|
|
||||||
) {
|
|
||||||
console.log("RECEIVE:", message);
|
|
||||||
}
|
|
||||||
if (message && message.event && message.event !== "error") {
|
|
||||||
// retryDelayMs = initialRetryDelayMs;
|
|
||||||
}
|
|
||||||
switch (message && message.event) {
|
|
||||||
case "terminalClear":
|
|
||||||
// term.reset();
|
|
||||||
sendToTerminal("terminalClear");
|
|
||||||
return;
|
|
||||||
case "terminalOutput":
|
|
||||||
if (typeof message.output !== "string") {
|
|
||||||
console.error("Unexpected message from server:", message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendToTerminal("terminalOutput", ansi.white(message.output));
|
|
||||||
setRunning(false);
|
|
||||||
return;
|
|
||||||
case "formattedCode":
|
|
||||||
setFormatting(false);
|
|
||||||
if (
|
|
||||||
typeof message.code !== "string" ||
|
|
||||||
typeof message.originalCode !== "string"
|
|
||||||
) {
|
|
||||||
console.error("Unexpected message from server:", message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (editorRef.current?.getValue() === message.originalCode) {
|
|
||||||
editorRef.current?.setValue(message.code);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case "lspStopped":
|
|
||||||
setIsLspRequested(false);
|
|
||||||
setLspStarted(false);
|
|
||||||
EventEmitter.dispatch("lspStopped");
|
|
||||||
break;
|
|
||||||
case "lspStarted":
|
|
||||||
setLspStarted(true);
|
|
||||||
setIsLspRequested(false);
|
|
||||||
if (typeof message.root !== "string") {
|
|
||||||
console.error("Unexpected message from server:", message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EventEmitter.dispatch("lspStarted", { message, socket });
|
|
||||||
|
|
||||||
return;
|
|
||||||
case "lspOutput":
|
|
||||||
// Should be handled by RijuMessageReader
|
|
||||||
return;
|
|
||||||
case "serviceLog":
|
|
||||||
if (
|
|
||||||
typeof message.service !== "string" ||
|
|
||||||
typeof message.output !== "string"
|
|
||||||
) {
|
|
||||||
console.error("Unexpected message from server:", message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let buffer = serviceLogBuffers[message.service] || "";
|
|
||||||
let lines = serviceLogLines[message.service] || [];
|
|
||||||
buffer += message.output;
|
|
||||||
while (buffer.includes("\n")) {
|
|
||||||
const idx = buffer.indexOf("\n");
|
|
||||||
const line = buffer.slice(0, idx);
|
|
||||||
buffer = buffer.slice(idx + 1);
|
|
||||||
lines.push(line);
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log(`${message.service.toUpperCase()} || ${line}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
serviceLogBuffers[message.service] = buffer;
|
|
||||||
serviceLogLines[message.service] = lines;
|
|
||||||
return;
|
|
||||||
case "serviceFailed":
|
|
||||||
if (
|
|
||||||
typeof message.service !== "string" ||
|
|
||||||
typeof message.error !== "string"
|
|
||||||
) {
|
|
||||||
console.error("Unexpected message from server:", message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (message.service) {
|
|
||||||
case "formatter":
|
|
||||||
setFormatting(false);
|
|
||||||
// showError({
|
|
||||||
// message: "Could not prettify code!",
|
|
||||||
// data: serviceLogLines["formatter"].join("\n"),
|
|
||||||
// });
|
|
||||||
break;
|
|
||||||
case "lsp":
|
|
||||||
setLspStarted(false);
|
|
||||||
setIsLspRequested(false);
|
|
||||||
EventEmitter.dispatch("lspStopped");
|
|
||||||
break;
|
|
||||||
case "terminal":
|
|
||||||
sendToTerminal(
|
|
||||||
"terminalOutput",
|
|
||||||
ansi.red(`\r\n[${message.error}]`)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case "langConfig":
|
|
||||||
console.log("Lang Config", message);
|
|
||||||
// We could use this message instead of hardcoding the
|
|
||||||
// language config into the HTML page returned from the
|
|
||||||
// server, but for now we just ignore it.
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
console.error("Unexpected message from server:", message);
|
console.error("Unexpected message from server:", message);
|
||||||
}
|
return;
|
||||||
});
|
}
|
||||||
socket.addEventListener("close", (event) => {
|
sendToTerminal("terminalOutput", ansi.white(message.output));
|
||||||
if (event.wasClean) {
|
setRunning(false);
|
||||||
console.log("Connection closed cleanly");
|
return;
|
||||||
} else {
|
case "formattedCode":
|
||||||
console.error("Connection died");
|
setFormatting(false);
|
||||||
}
|
if (
|
||||||
EventEmitter.dispatch("lspStopped");
|
typeof message.code !== "string" ||
|
||||||
setRunning(false);
|
typeof message.originalCode !== "string"
|
||||||
setLspStarted(false);
|
) {
|
||||||
setIsLspRequested(false);
|
console.error("Unexpected message from server:", message);
|
||||||
setStatus("idle");
|
return;
|
||||||
});
|
}
|
||||||
|
if (editorRef.current?.getValue() === message.originalCode) {
|
||||||
|
editorRef.current?.setValue(message.code);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case "lspStopped":
|
||||||
|
setIsLspRequested(false);
|
||||||
|
setLspStarted(false);
|
||||||
|
EventEmitter.dispatch("lspStopped");
|
||||||
|
break;
|
||||||
|
case "lspStarted":
|
||||||
|
setLspStarted(true);
|
||||||
|
setIsLspRequested(false);
|
||||||
|
if (typeof message.root !== "string") {
|
||||||
|
console.error("Unexpected message from server:", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return socket;
|
EventEmitter.dispatch("lspStarted", { message });
|
||||||
}
|
|
||||||
|
return;
|
||||||
|
case "lspOutput":
|
||||||
|
// Should be handled by RijuMessageReader
|
||||||
|
return;
|
||||||
|
case "serviceLog":
|
||||||
|
if (
|
||||||
|
typeof message.service !== "string" ||
|
||||||
|
typeof message.output !== "string"
|
||||||
|
) {
|
||||||
|
console.error("Unexpected message from server:", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let buffer = serviceLogBuffers[message.service] || "";
|
||||||
|
let lines = serviceLogLines[message.service] || [];
|
||||||
|
buffer += message.output;
|
||||||
|
while (buffer.includes("\n")) {
|
||||||
|
const idx = buffer.indexOf("\n");
|
||||||
|
const line = buffer.slice(0, idx);
|
||||||
|
buffer = buffer.slice(idx + 1);
|
||||||
|
lines.push(line);
|
||||||
|
if (DEBUG) {
|
||||||
|
console.log(`${message.service.toUpperCase()} || ${line}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serviceLogBuffers[message.service] = buffer;
|
||||||
|
serviceLogLines[message.service] = lines;
|
||||||
|
return;
|
||||||
|
case "serviceFailed":
|
||||||
|
if (
|
||||||
|
typeof message.service !== "string" ||
|
||||||
|
typeof message.error !== "string"
|
||||||
|
) {
|
||||||
|
console.error("Unexpected message from server:", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (message.service) {
|
||||||
|
case "formatter":
|
||||||
|
setFormatting(false);
|
||||||
|
// showError({
|
||||||
|
// message: "Could not prettify code!",
|
||||||
|
// data: serviceLogLines["formatter"].join("\n"),
|
||||||
|
// });
|
||||||
|
break;
|
||||||
|
case "lsp":
|
||||||
|
setLspStarted(false);
|
||||||
|
setIsLspRequested(false);
|
||||||
|
EventEmitter.dispatch("lspStopped");
|
||||||
|
break;
|
||||||
|
case "terminal":
|
||||||
|
sendToTerminal(
|
||||||
|
"terminalOutput",
|
||||||
|
ansi.red(`\r\n[${message.error}]`)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case "langConfig":
|
||||||
|
console.log("Lang Config", message);
|
||||||
|
// We could use this message instead of hardcoding the
|
||||||
|
// language config into the HTML page returned from the
|
||||||
|
// server, but for now we just ignore it.
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
console.error("Unexpected message from server:", message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleWsClose = (event) => {
|
||||||
|
if (event.wasClean) {
|
||||||
|
console.log("Connection closed cleanly");
|
||||||
|
} else {
|
||||||
|
console.error("Connection died");
|
||||||
|
}
|
||||||
|
EventEmitter.dispatch("lspStopped");
|
||||||
|
setRunning(false);
|
||||||
|
setLspStarted(false);
|
||||||
|
setIsLspRequested(false);
|
||||||
|
setStatus("idle");
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!config || !mounted) return;
|
if (!config || !mounted) return;
|
||||||
const socket = connect();
|
serviceLogBuffers = {};
|
||||||
return () => socket && socket.close();
|
serviceLogLines = {};
|
||||||
|
setStatus("connecting");
|
||||||
|
SocketManager.connect(config, handleWsOpen, handleWsMessage, handleWsClose);
|
||||||
|
return () => SocketManager.disconnect();
|
||||||
}, [config, mounted]);
|
}, [config, mounted]);
|
||||||
|
|
||||||
function showValue() {
|
function showValue() {
|
||||||
setRunning(true);
|
setRunning(true);
|
||||||
EventEmitter.dispatch("send", {
|
SocketManager.send({
|
||||||
event: "runCode",
|
event: "runCode",
|
||||||
code: editorRef.current.getValue(),
|
code: editorRef.current.getValue(),
|
||||||
});
|
});
|
||||||
|
@ -238,7 +222,7 @@ const CodeRunner = (props) => {
|
||||||
setFormatting(true);
|
setFormatting(true);
|
||||||
serviceLogBuffers["formatter"] = "";
|
serviceLogBuffers["formatter"] = "";
|
||||||
serviceLogLines["formatter"] = [];
|
serviceLogLines["formatter"] = [];
|
||||||
EventEmitter.dispatch("send", {
|
SocketManager.send({
|
||||||
event: "formatCode",
|
event: "formatCode",
|
||||||
code: editorRef.current.getValue(),
|
code: editorRef.current.getValue(),
|
||||||
});
|
});
|
||||||
|
@ -261,21 +245,28 @@ const CodeRunner = (props) => {
|
||||||
const handleLspClick = () => {
|
const handleLspClick = () => {
|
||||||
setIsLspRequested(true);
|
setIsLspRequested(true);
|
||||||
if (isLspStarted) {
|
if (isLspStarted) {
|
||||||
EventEmitter.dispatch("send", {
|
SocketManager.send({
|
||||||
event: "lspStop",
|
event: "lspStop",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
EventEmitter.dispatch("send", {
|
SocketManager.send({
|
||||||
event: "lspStart",
|
event: "lspStart",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = () => {
|
const handleChange = () => {
|
||||||
if (status != "idle") {
|
if (SocketManager.isConnected) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
connect();
|
if (!SocketManager.isConnected) {
|
||||||
|
SocketManager.connect(
|
||||||
|
config,
|
||||||
|
handleWsOpen,
|
||||||
|
handleWsMessage,
|
||||||
|
handleWsClose
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -285,7 +276,6 @@ const CodeRunner = (props) => {
|
||||||
const es = document.querySelectorAll(".split .panel");
|
const es = document.querySelectorAll(".split .panel");
|
||||||
for (const e of es) {
|
for (const e of es) {
|
||||||
e.removeAttribute("style");
|
e.removeAttribute("style");
|
||||||
e.removeAttribute("style");
|
|
||||||
}
|
}
|
||||||
setSplitType(value);
|
setSplitType(value);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
const isFn = (callback) => {
|
||||||
|
return callback && typeof callback == "function";
|
||||||
|
};
|
||||||
|
|
||||||
|
const createSocket = (url) => {
|
||||||
|
const socket = new WebSocket(url);
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SocketManager = {
|
||||||
|
socket: null,
|
||||||
|
isConnected: false,
|
||||||
|
connect: function (config, onOpen, onMessage, onClose) {
|
||||||
|
let url =
|
||||||
|
"wss://" +
|
||||||
|
"riju.codes" +
|
||||||
|
`/api/v1/ws?lang=${encodeURIComponent(config.id)}`;
|
||||||
|
this.socket = createSocket(url);
|
||||||
|
this.socket.addEventListener("open", () => {
|
||||||
|
console.log("Successfully connected to server playground");
|
||||||
|
this.isConnected = true;
|
||||||
|
if (isFn(onOpen)) onOpen();
|
||||||
|
});
|
||||||
|
this.socket.addEventListener("message", async (event) => {
|
||||||
|
if (isFn(onMessage)) onMessage(event);
|
||||||
|
});
|
||||||
|
this.socket.addEventListener("close", (event) => {
|
||||||
|
if (isFn(onClose)) onClose(event);
|
||||||
|
this.isConnected = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
disconnect: function () {
|
||||||
|
if (this.socket) {
|
||||||
|
if (this.socket.readyState == WebSocket.OPEN) {
|
||||||
|
this.socket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
send: function (data) {
|
||||||
|
if (this.socket) {
|
||||||
|
if (this.socket.readyState == WebSocket.OPEN) {
|
||||||
|
this.socket.send(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,18 +1,25 @@
|
||||||
export const EventEmitter = {
|
export const EventEmitter = {
|
||||||
events: {},
|
events: {},
|
||||||
|
lastUid: -1,
|
||||||
dispatch: function (event, data) {
|
dispatch: function (event, data) {
|
||||||
if (!this.events[event]) return;
|
if (!this.events[event]) return;
|
||||||
this.events[event].forEach((callback) => callback(data));
|
for (let token of Object.keys(this.events[event])) {
|
||||||
|
const callback = this.events[event][token];
|
||||||
|
if (callback && typeof callback == "function") callback(data);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
subscribe: function (event, callback) {
|
subscribe: function (event, callback) {
|
||||||
if (!this.events[event]) this.events[event] = [];
|
if (!callback) return;
|
||||||
this.events[event].push(callback);
|
if (!this.events[event]) this.events[event] = {};
|
||||||
|
const token = "uID_" + String(++this.lastUid);
|
||||||
|
this.events[event][token] = callback;
|
||||||
},
|
},
|
||||||
isSubscribed: function (event) {
|
unsubcribe: function (...tokens) {
|
||||||
if (!Array.isArray(this.events[event])) return false;
|
for (let k of Object.keys(events)) {
|
||||||
else {
|
let toks = Object.keys(events[k]);
|
||||||
if (this.events[event].length == 0) return false;
|
for (let tok of toks) {
|
||||||
else return true;
|
if (tokens.includes(tok)) delete events[k][tok];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue