add.. something.....
This commit is contained in:
parent
fea27f9fa9
commit
4fbdace446
5 changed files with 360 additions and 0 deletions
105
out/_/jd3ymgfg3gk6vrlaxhbn/GatewayClient.js
Normal file
105
out/_/jd3ymgfg3gk6vrlaxhbn/GatewayClient.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
window.modules.register("GatewayClient", () => {
|
||||||
|
const messageSchema = { t: "number", d: "object" };
|
||||||
|
const messageTypes = {
|
||||||
|
HELLO: 0,
|
||||||
|
YOO: 1,
|
||||||
|
READY: 2,
|
||||||
|
EVENT: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
class GatewayClient {
|
||||||
|
constructor(gatewayPath) {
|
||||||
|
this.gatewayPath = gatewayPath;
|
||||||
|
this.ws = null;
|
||||||
|
this.token = null;
|
||||||
|
this.user = null;
|
||||||
|
this.onEvent = (e) => {};
|
||||||
|
this.onConnected = () => {};
|
||||||
|
this.onDisconnected = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(token) {
|
||||||
|
if (!token)
|
||||||
|
token = this.token;
|
||||||
|
|
||||||
|
console.log("gateway: connecting");
|
||||||
|
|
||||||
|
this.ws = new WebSocket(this.gatewayPath);
|
||||||
|
|
||||||
|
this.ws.addEventListener("message", ({ data }) => {
|
||||||
|
if (typeof data !== "string") {
|
||||||
|
console.warn("gateway: got non-string data from server, ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
message = JSON.parse(data);
|
||||||
|
} catch(e) {
|
||||||
|
console.warn("gateway: got invalid JSON from server (failed to parse), ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._checkMessageSchema(message)) {
|
||||||
|
console.warn("gateway: got invalid JSON from server (does not match schema), ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message.t) {
|
||||||
|
case messageTypes.HELLO: {
|
||||||
|
console.log("gateway: HELLO");
|
||||||
|
this.ws.send(JSON.stringify({
|
||||||
|
t: messageTypes.YOO,
|
||||||
|
d: {
|
||||||
|
token
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case messageTypes.READY: {
|
||||||
|
console.log("gateway: READY");
|
||||||
|
this.user = message.d.user;
|
||||||
|
this.onConnected();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case messageTypes.EVENT: {
|
||||||
|
this.onEvent(message.d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.warn("gateway: got invalid JSON from server (invalid type), ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.ws.addEventListener("open", () => {
|
||||||
|
console.log("gateway: open");
|
||||||
|
});
|
||||||
|
this.ws.addEventListener("close", ({ code }) => {
|
||||||
|
console.log("gateway: closed");
|
||||||
|
this.onDisconnected(code);
|
||||||
|
if (code === 4001) {
|
||||||
|
console.log(`gateway: disconnect code is ${code} (bad auth), will not attempt reconnect`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("gateway: reconnecting");
|
||||||
|
this.connect(token);
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkMessageSchema(message) {
|
||||||
|
for (const [key, value] of Object.entries(message)) {
|
||||||
|
if (!messageSchema[key])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (typeof value !== messageSchema[key])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GatewayClient;
|
||||||
|
});
|
21
out/_/jd3ymgfg3gk6vrlaxhbn/app.js
Normal file
21
out/_/jd3ymgfg3gk6vrlaxhbn/app.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
window.modules.register("$app", () => {
|
||||||
|
const App = window.modules.require("App");
|
||||||
|
|
||||||
|
if (!window._APP_ENV)
|
||||||
|
throw new Error("$app: could not find window._APP_ENV");
|
||||||
|
if (!App)
|
||||||
|
throw new Error("$app: require('App') returned undefined");
|
||||||
|
|
||||||
|
const initialLoading = document.getElementById("initial-loading");
|
||||||
|
if (initialLoading) {
|
||||||
|
initialLoading.parentElement.removeChild(initialLoading);
|
||||||
|
}
|
||||||
|
|
||||||
|
const appMountElement = document.createElement("div");
|
||||||
|
document.body.appendChild(appMountElement);
|
||||||
|
|
||||||
|
const app = new App(appMountElement);
|
||||||
|
app.mount();
|
||||||
|
|
||||||
|
return app;
|
||||||
|
});
|
185
out/_/jd3ymgfg3gk6vrlaxhbn/components.js
Normal file
185
out/_/jd3ymgfg3gk6vrlaxhbn/components.js
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
window.modules.register("AuthPromptRoute", () => {
|
||||||
|
class AuthPromptRoute {
|
||||||
|
constructor() {
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mountOn(target) {
|
||||||
|
if (this.element)
|
||||||
|
return; // Already mounted
|
||||||
|
|
||||||
|
this.element = document.createRange().createContextualFragment(`
|
||||||
|
<div>
|
||||||
|
<input type="password" id="code-input">
|
||||||
|
<button id="continue-button">enter</button>
|
||||||
|
</div>
|
||||||
|
`).children[0];
|
||||||
|
|
||||||
|
this.element.querySelector("#continue-button").addEventListener("click", () => {
|
||||||
|
if (this.onPasswordSubmitted)
|
||||||
|
this.onPasswordSubmitted(this.element.querySelector("#code-input").value);
|
||||||
|
});
|
||||||
|
|
||||||
|
target.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
unmount() {
|
||||||
|
if (!this.element)
|
||||||
|
return; // Already unmounted
|
||||||
|
this.element.parentElement.removeChild(this.element);
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AuthPromptRoute;
|
||||||
|
});
|
||||||
|
|
||||||
|
window.modules.register("MainChatView", () => {
|
||||||
|
class MainChatView {
|
||||||
|
constructor() {
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
mountOn(target) {
|
||||||
|
if (this.element)
|
||||||
|
return; // Already mounted
|
||||||
|
|
||||||
|
this.element = document.createRange().createContextualFragment(`
|
||||||
|
<div>
|
||||||
|
<div id="messages-container" style="width: 300px; height: 250px; overflow: auto;"></div>
|
||||||
|
<br>
|
||||||
|
<input type="text" id="message-input">
|
||||||
|
<button id="message-submit">send</button>
|
||||||
|
</div>
|
||||||
|
`).children[0];
|
||||||
|
|
||||||
|
const textInput = this.element.querySelector("#message-input");
|
||||||
|
this.element.querySelector("#message-submit").addEventListener("click", () => {
|
||||||
|
const message = textInput.value;
|
||||||
|
if (this.onSendMessage)
|
||||||
|
this.onSendMessage(message);
|
||||||
|
|
||||||
|
textInput.value = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
target.appendChild(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendMessage(messageObject) {
|
||||||
|
const { author, content } = messageObject;
|
||||||
|
if (!this.element)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const usernameLetters = author.username
|
||||||
|
.split("");
|
||||||
|
let authorUsernameNumber = 150;
|
||||||
|
usernameLetters.forEach(l => {
|
||||||
|
authorUsernameNumber += l.charCodeAt(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const messageElement = document.createRange().createContextualFragment(`
|
||||||
|
<div>
|
||||||
|
<b>[author could not be loaded] </b>
|
||||||
|
<span>[content could not be loaded]</span>
|
||||||
|
</div>
|
||||||
|
`).children[0];
|
||||||
|
|
||||||
|
messageElement.querySelector("b").innerText = `User ${authorUsernameNumber} `;
|
||||||
|
messageElement.querySelector("span").innerText = content;
|
||||||
|
|
||||||
|
const container = this.element.querySelector("#messages-container");
|
||||||
|
container.appendChild(messageElement);
|
||||||
|
container.scrollTop = container.scrollHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
unmount() {
|
||||||
|
if (!this.element)
|
||||||
|
return; // Already unmounted
|
||||||
|
this.element.parentElement.removeChild(this.element);
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MainChatView;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
window.modules.register("App", () => {
|
||||||
|
const AuthPromptRoute = window.modules.require("AuthPromptRoute");
|
||||||
|
const MainChatView = window.modules.require("MainChatView");
|
||||||
|
const GatewayClient = window.modules.require("GatewayClient");
|
||||||
|
|
||||||
|
|
||||||
|
class App {
|
||||||
|
constructor(mountElement) {
|
||||||
|
this.mountElement = mountElement;
|
||||||
|
this.currentMountedElement = null;
|
||||||
|
|
||||||
|
this.authPromptRoute = new AuthPromptRoute();
|
||||||
|
this.mainChatView = new MainChatView();
|
||||||
|
this.gatewayClient = new GatewayClient(window._APP_ENV.gatewayBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
_mountElement(element) {
|
||||||
|
if (this.currentMountedElement) {
|
||||||
|
this.currentMountedElement.unmount();
|
||||||
|
}
|
||||||
|
this.currentMountedElement = element;
|
||||||
|
this.currentMountedElement.mountOn(this.mountElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unmountAll() {
|
||||||
|
if (this.currentMountedElement) {
|
||||||
|
this.currentMountedElement.unmount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mount() {
|
||||||
|
let serverId;
|
||||||
|
let channelId;
|
||||||
|
let token;
|
||||||
|
|
||||||
|
this._mountElement(this.authPromptRoute);
|
||||||
|
|
||||||
|
this.gatewayClient.onEvent = (e) => {
|
||||||
|
if (e.eventType === "MESSAGE_CREATE" && e.message && e.message.guild_id === serverId && e.message.channel_id === channelId) {
|
||||||
|
this.mainChatView.appendMessage(e.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.gatewayClient.onConnected = () => {
|
||||||
|
this._mountElement(this.mainChatView);
|
||||||
|
};
|
||||||
|
this.gatewayClient.onDisconnected = () => {
|
||||||
|
this._mountElement(this.authPromptRoute);
|
||||||
|
};
|
||||||
|
this.authPromptRoute.onPasswordSubmitted = (auth) => {
|
||||||
|
const parts = auth.split(",,");
|
||||||
|
if (parts.length !== 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const [userToken, userServerId, userChannelId] = parts;
|
||||||
|
serverId = userServerId;
|
||||||
|
channelId = userChannelId;
|
||||||
|
token = userToken
|
||||||
|
this.gatewayClient.connect(token);
|
||||||
|
};
|
||||||
|
this.mainChatView.onSendMessage = async (message) => {
|
||||||
|
if (typeof message === "string" && message.trim() === "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await fetch(`${window._APP_ENV.apiBase}/guilds/${serverId}/channels/${channelId}/messages/create`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
content: message
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json",
|
||||||
|
"authorization": token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return App;
|
||||||
|
});
|
23
out/_/jd3ymgfg3gk6vrlaxhbn/index.html
Normal file
23
out/_/jd3ymgfg3gk6vrlaxhbn/index.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>.</title>
|
||||||
|
<script>
|
||||||
|
window._APP_ENV = {
|
||||||
|
gatewayBase: "wss://kittycatnetwork.hippoz.xyz/services/thebridge/gateway/",
|
||||||
|
apiBase: "https://kittycatnetwork.hippoz.xyz/services/thebridge/api/v1"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p id="initial-loading">loading</p>
|
||||||
|
|
||||||
|
<script src="moduleruntime.js"></script>
|
||||||
|
<script src="GatewayClient.js"></script>
|
||||||
|
<script src="components.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
out/_/jd3ymgfg3gk6vrlaxhbn/moduleruntime.js
Normal file
26
out/_/jd3ymgfg3gk6vrlaxhbn/moduleruntime.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const modules = {
|
||||||
|
_cache: {},
|
||||||
|
_registry: {},
|
||||||
|
require(moduleName) {
|
||||||
|
if (this._cache[moduleName]) {
|
||||||
|
return this._cache[moduleName];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._registry[moduleName]) {
|
||||||
|
const loaderFunction = this._registry[moduleName];
|
||||||
|
this._cache[moduleName] = loaderFunction(1);
|
||||||
|
return this._cache[moduleName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
register(moduleName, loaderFunction) {
|
||||||
|
this._registry[moduleName] = loaderFunction;
|
||||||
|
this._cache[moduleName] = loaderFunction(0);
|
||||||
|
},
|
||||||
|
registerLazy(moduleName, loaderFunction) {
|
||||||
|
this._registry[moduleName] = loaderFunction;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.modules = modules;
|
Loading…
Reference in a new issue