summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2024-03-29 22:05:24 +0100
committerRaindropsSys <raindrops@equestria.dev>2024-03-29 22:05:24 +0100
commita79cf1bd000da84111ac839cfada1f8d867211fd (patch)
treea9fb8ae189c0e7176a32ac0078f1fce845d231a2
parent231489c7f2c2b2b93eb23db1b28eaefca4d219ec (diff)
downloadchatroom-a79cf1bd000da84111ac839cfada1f8d867211fd.tar.gz
chatroom-a79cf1bd000da84111ac839cfada1f8d867211fd.tar.bz2
chatroom-a79cf1bd000da84111ac839cfada1f8d867211fd.zip
Updated 7 files and added 4 files (automated)
-rw-r--r--.gitignore4
-rw-r--r--client/assets/icons2/questions.svg1
-rw-r--r--client/dom/new.html8
-rw-r--r--client/fragments/home.html9
-rw-r--r--client/fragments/questions.html57
-rw-r--r--client/fragments/settings/experiments.html2
-rwxr-xr-xclient/main.js11
-rw-r--r--client/src/platforms.js99
-rw-r--r--client/src/plugin.js4
-rw-r--r--client/src/spyglass.js21
-rw-r--r--server/platforms.js75
11 files changed, 279 insertions, 12 deletions
diff --git a/.gitignore b/.gitignore
index 637cb9f..59fcf91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,6 @@ debug
build
bot/tokens.json
vpn/keys.json
-vpn/requests.json \ No newline at end of file
+vpn/requests.json
+server/data
+server/secrets.json
diff --git a/client/assets/icons2/questions.svg b/client/assets/icons2/questions.svg
new file mode 100644
index 0000000..ebe64e3
--- /dev/null
+++ b/client/assets/icons2/questions.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M80-40v-80h800v80H80Zm80-120v-240q-33-54-51-114.5T91-638q0-61 15.5-120T143-874q8-21 26-33.5t40-12.5q31 0 53 21t18 50l-11 91q-6 48 8.5 91t43.5 75.5q29 32.5 70 52t89 19.5q60 0 120.5 12.5T706-472q45 23 69.5 58.5T800-326v166H160Zm80-80h480v-86q0-24-12-42.5T674-398q-41-20-95-31t-99-11q-66 0-122.5-27t-96-72.5Q222-585 202-644.5T190-768q-10 30-14.5 64t-4.5 66q0 58 20.5 111.5T240-422v182Zm240-320q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 66-47 113t-113 47Zm0-80q33 0 56.5-23.5T560-720q0-33-23.5-56.5T480-800q-33 0-56.5 23.5T400-720q0 33 23.5 56.5T480-640ZM320-160v-37q0-67 46.5-115T480-360h160v80H480q-34 0-57 24.5T400-197v37h-80Zm160-80Zm0-480Z"/></svg> \ No newline at end of file
diff --git a/client/dom/new.html b/client/dom/new.html
index 22a9988..76d478c 100644
--- a/client/dom/new.html
+++ b/client/dom/new.html
@@ -11,6 +11,7 @@
<meta charset="UTF-8">
<title>Chatroom</title>
<script src="../src/spyglass.js"></script>
+ <script src="../src/platforms.js"></script>
<style>
html, body {
margin: 0;
@@ -422,8 +423,9 @@
}
window.addEventListener('load', () => {
- openTab("https://school.equestria.dev");
openTab("../fragments/settings.html", false, true, false, true);
+ openTab("https://school.equestria.dev");
+ openTab("../fragments/questions.html", false, true, false, true);
openHome();
tabs[0].fixed = false;
@@ -433,14 +435,16 @@
switchToTab(1);
}
+ window.isNewUI = true;
if (startSpyglass) startSpyglass();
+ startPlatforms();
});
async function getToken() {
let token;
try {
- token = await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("matrixChat.stores.client.http.opts.accessToken");
+ token = await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("matrixChat.stores.client.http.opts.accessToken");
} catch (e) {
token = null;
}
diff --git a/client/fragments/home.html b/client/fragments/home.html
index 13bf453..7941d68 100644
--- a/client/fragments/home.html
+++ b/client/fragments/home.html
@@ -44,6 +44,12 @@
<h3>What's new in Chatroom?</h3>
<div id="m3-changelog" style="display: none;">
+ <h5>Chatroom Codename "Heeler" (Developer Preview 3)</h5>
+ <p>Welcome to the third Developer Preview release of Chatroom 3. We are slowly bringing new features as we initially planned.</p>
+ <ul>
+ <li>The new UI gets a new "Questions" tab, where you can use the power of online knowledge to instantly ask any questions and get verified answers. Powered by Wolfram Alpha.</li>
+ </ul>
+
<h5>Chatroom Codename "Heeler" (Developer Preview 2, Developer Preview 2 Revision 1)</h5>
<p>Welcome to the second Developer Preview release of Chatroom 3. We are slowly bringing new features as we initially planned.</p>
<ul>
@@ -63,9 +69,10 @@
}
</script>
- <h5>Chatroom 2.8.2 (Long Term Support)</h5>
+ <h5>Chatroom 2.8.3 (Long Term Support)</h5>
<p>Chatroom 3 (Codename "Heeler") is now under development (it can be enabled with a few secret options)! While regular Chatroom features will continue to function normally, select people will be able to test new features. Contact your administrator for details. This does mean that Chatroom 2.8 is the last version of Chatroom 2 before the release of Chatroom 3. This old version of Chatroom will only contain bug fixes and no new features will be added.</p>
<ul>
+ <li><b>2.8.3 Fix:</b> Chatroom no longer gets stuck on connecting with the Spyglass server.</li>
<li><b>2.8.2 Fix:</b> Chatroom no longer uses a lot of CPU resources and creates a lot of processes (about 60).</li>
<li><b>2.8.1 Fix:</b> Links can now open in new tabs if indicated by the website or if you hold down Cmd/Ctrl while clicking it.</li>
<li><b>2.8.0 Fix:</b> Clicking on the search bar on the home page now focuses the search bar on top.</li>
diff --git a/client/fragments/questions.html b/client/fragments/questions.html
new file mode 100644
index 0000000..84285ef
--- /dev/null
+++ b/client/fragments/questions.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Questions</title>
+ <link rel="icon" href="../assets/icons2/questions.svg">
+ <style>
+ * {
+ font-family: system-ui, -apple-system, sans-serif;
+ user-select: none;
+ -webkit-user-drag: none;
+ }
+ </style>
+</head>
+<body style="background-color: #fff;">
+ <main style="background-color: #fff; position: fixed; inset: 20px; display: grid; grid-template-columns: 1fr 1fr; grid-gap: 10px;">
+ <div>
+ <h4 style="margin-top: 0; margin-bottom: 10px;">Chatroom Questions</h4>
+ <p>Ask any question here, and get an instant, reliable and trustworthy answer from the internet.</p>
+
+ <form id="form">
+ <input type="text" id="question" placeholder="Enter your question here" autofocus autocomplete="false" style="width: 100%; max-width: 256px;">
+ </form>
+ </div>
+ <div id="response" style="overflow: hidden;">
+ <div id="response-empty" style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center;">Enter a question and press Enter to see an answer here.</div>
+ <div id="response-loader" style="display: none; width: 100%; height: 100%; align-items: center; justify-content: center;">Generating answer, please wait...</div>
+ <img id="response-image" style="width: 100%;">
+ </div>
+ </main>
+
+ <script>
+ document.getElementById("form").onsubmit = async (e) => {
+ e.preventDefault();
+ document.getElementById("question").disabled = true;
+ let prompt = document.getElementById("question").value.trim();
+
+ document.getElementById("response").style.overflow = "hidden";
+ document.getElementById("response-empty").style.display = "none";
+ document.getElementById("response-image").style.display = "none";
+ document.getElementById("response-loader").style.display = "flex";
+
+ let response = await chatroom.executePlatformsRequest({ method: "wolfram", query: prompt });
+ document.getElementById("response-image").src = "data:image/jpg;base64," + response.data;
+
+ document.getElementById("response").style.overflow = "auto";
+ document.getElementById("response-image").style.display = "";
+ document.getElementById("response-loader").style.display = "none";
+ document.getElementById("response-empty").style.display = "none";
+
+ document.getElementById("question").value = "";
+ document.getElementById("question").disabled = false;
+ document.getElementById("question").focus();
+ }
+ </script>
+</body>
+</html>
diff --git a/client/fragments/settings/experiments.html b/client/fragments/settings/experiments.html
index cb344ed..e5dcb02 100644
--- a/client/fragments/settings/experiments.html
+++ b/client/fragments/settings/experiments.html
@@ -55,7 +55,7 @@
}
},
{
- name: "m2spyglassdialogbehavior",
+ name: "m2spyglassdialogbehavior2",
treatments: {
"false": "Treatment 1: Display Spyglass dialog in M2",
"true": "Treatment 2: Hide Spyglass dialog in M2"
diff --git a/client/main.js b/client/main.js
index c2f40cf..77d67f5 100755
--- a/client/main.js
+++ b/client/main.js
@@ -2,8 +2,8 @@
const buildNumber = "main";
// --- >FINAL< @BUILDNUMBER@ >FINAL< --- //
-const version_stable = "2.8.2-LTS";
-const version_beta = "3.0.0-DP.2-rv1";
+const version_stable = "2.8.3-LTS";
+const version_beta = "3.0.0-DP.3";
let version = version_stable;
const { desktopCapturer, protocol, app, BrowserWindow, webContents, globalShortcut, nativeTheme, ipcMain, session, dialog, Menu } = require('electron');
@@ -429,6 +429,13 @@ ipcMain.handle('reload', (_) => {
});
});
+ipcMain.handle('platforms', (_, req) => {
+ return new Promise(async (res) => {
+ if (!global.mainWindow) return;
+ res(await global.mainWindow.webContents.executeJavaScript("platformsRequest(JSON.parse(atob(\"" + Buffer.from(JSON.stringify(req)).toString("base64") + "\")));"));
+ });
+});
+
ipcMain.on('menu', (_, params) => {
console.log(params);
diff --git a/client/src/platforms.js b/client/src/platforms.js
new file mode 100644
index 0000000..31c5c5c
--- /dev/null
+++ b/client/src/platforms.js
@@ -0,0 +1,99 @@
+const PLATFORMS_SERVER = "wss://school.equestria.dev/platforms";
+
+let PLATFORMS_STATE = false;
+let PLATFORMS_INITIALIZED = false;
+let PLATFORMS_SOCKET = null;
+const PLATFORMS_CALLBACKS = {};
+
+function platformsSend(d) {
+ return PLATFORMS_SOCKET.send(JSON.stringify(d));
+}
+
+function startPlatforms() {
+ PLATFORMS_INITIALIZED = true;
+ PLATFORMS_SOCKET = new WebSocket(PLATFORMS_SERVER);
+
+ PLATFORMS_SOCKET.onmessage = (e) => {
+ let data;
+ try {
+ data = JSON.parse(e.data)
+ } catch (e) {
+ console.error("Platforms", e);
+ }
+ if (!data) return;
+
+ console.log("Platforms", data);
+
+ if (data.state) {
+ switch (data.state) {
+ case "NEEDS_AUTHENTICATION":
+ let authInterval = setInterval(async () => {
+ try {
+ if (await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("!!document.getElementsByClassName('mx_ConfirmSessionLockTheftView_body')[0]")) {
+ await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("document.querySelector('.mx_ConfirmSessionLockTheftView_body .mx_AccessibleButton.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_primary').click()")
+ }
+
+ let token = await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("matrixChat.stores.client.http.opts.accessToken");
+ clearInterval(authInterval);
+
+ platformsSend({
+ state: "AUTHENTICATION_RESPONSE",
+ token: token
+ });
+ } catch (e) {
+ console.error(e);
+ }
+ }, 50);
+
+ break;
+
+ case "AUTHENTICATION_OK":
+ PLATFORMS_STATE = true;
+ break;
+
+ case "REQUEST_RESPONSE":
+ console.log(data);
+
+ if (data.data._id && PLATFORMS_CALLBACKS[data.data._id]) {
+ PLATFORMS_CALLBACKS[data.data._id](data);
+ }
+ break;
+ }
+ }
+ }
+
+ PLATFORMS_SOCKET.onopen = (e) => {
+ console.log("Platforms", e);
+ }
+
+ PLATFORMS_SOCKET.onerror = (e) => {
+ console.log("Platforms", e);
+
+ PLATFORMS_SOCKET.close();
+ clearInterval(window.spyglassInterval);
+ }
+
+ PLATFORMS_SOCKET.onclose = (e) => {
+ console.log("Platforms", e);
+
+ PLATFORMS_SOCKET = false;
+
+ setTimeout(() => {
+ startPlatforms();
+ }, 1000);
+ }
+}
+
+function platformsRequest(req) {
+ return new Promise((res, rej) => {
+ let id = crypto.randomUUID();
+ req["_id"] = id;
+
+ PLATFORMS_CALLBACKS[id] = (data) => {
+ res(data.data);
+ delete PLATFORMS_CALLBACKS[id];
+ }
+
+ platformsSend(req);
+ });
+}
diff --git a/client/src/plugin.js b/client/src/plugin.js
index 7324672..8ff022f 100644
--- a/client/src/plugin.js
+++ b/client/src/plugin.js
@@ -17,6 +17,10 @@ const crObj = {
reloadHost: async () => {
if (location.protocol !== "file:") throw new Error("reloadHost is only available from local pages.");
return await ipcRenderer.invoke("reload");
+ },
+ executePlatformsRequest: async (req) => {
+ if (location.protocol !== "file:") throw new Error("reloadHost is only available from local pages.");
+ return await ipcRenderer.invoke("platforms", req);
}
};
diff --git a/client/src/spyglass.js b/client/src/spyglass.js
index bff90af..e719d44 100644
--- a/client/src/spyglass.js
+++ b/client/src/spyglass.js
@@ -38,13 +38,13 @@ if ((process.env.USERDNSDOMAIN && process.env.USERDNSDOMAIN.endsWith(".AC-ORLEAN
function startSpyglass() {
SPYGLASS_INITIALIZED = true;
- if (localStorage.getItem("cr3-trial-m2spyglassdialogbehavior") === "true") {
+ if (localStorage.getItem("cr3-trial-m2spyglassdialogbehavior2") === "true") {
SPYGLASS_INITIALIZED = false;
}
if (window.bootstrap) {
if (!modal) modal = new bootstrap.Modal(document.getElementById("loading-modal"));
- if (localStorage.getItem("cr3-trial-m2spyglassdialogbehavior") !== "true") modal.show();
+ if (localStorage.getItem("cr3-trial-m2spyglassdialogbehavior2") !== "true") modal.show();
}
SPYGLASS_SOCKET = new WebSocket(SPYGLASS_SERVER);
@@ -65,11 +65,22 @@ if ((process.env.USERDNSDOMAIN && process.env.USERDNSDOMAIN.endsWith(".AC-ORLEAN
case "NEEDS_AUTHENTICATION":
let authInterval = setInterval(async () => {
try {
- if (await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("!!document.getElementsByClassName('mx_ConfirmSessionLockTheftView_body')[0]")) {
- await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("document.querySelector('.mx_ConfirmSessionLockTheftView_body .mx_AccessibleButton.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_primary').click()")
+ let token;
+
+ if (!window.isNewUI) {
+ if (await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("!!document.getElementsByClassName('mx_ConfirmSessionLockTheftView_body')[0]")) {
+ await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("document.querySelector('.mx_ConfirmSessionLockTheftView_body .mx_AccessibleButton.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_primary').click()")
+ }
+
+ token = await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("matrixChat.stores.client.http.opts.accessToken");
+ } else {
+ if (await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("!!document.getElementsByClassName('mx_ConfirmSessionLockTheftView_body')[0]")) {
+ await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("document.querySelector('.mx_ConfirmSessionLockTheftView_body .mx_AccessibleButton.mx_AccessibleButton_hasKind.mx_AccessibleButton_kind_primary').click()")
+ }
+
+ token = await tabs.filter(i => i.small)[1].webview.children[1].executeJavaScript("matrixChat.stores.client.http.opts.accessToken");
}
- let token = await tabs.filter(i => i.small)[0].webview.children[1].executeJavaScript("matrixChat.stores.client.http.opts.accessToken");
clearInterval(authInterval);
spyglassSend({
diff --git a/server/platforms.js b/server/platforms.js
new file mode 100644
index 0000000..01773ed
--- /dev/null
+++ b/server/platforms.js
@@ -0,0 +1,75 @@
+const secrets = require('./secrets.json');
+const WebSocketServer = require('ws').WebSocketServer;
+const wss = new WebSocketServer({ port: 19219 });
+
+async function processRequest(ws, data) {
+ if (data.method === "wolfram") {
+ let query = "https://api.wolframalpha.com/v1/simple?appid=" + secrets.wolfram + "&i=" + encodeURIComponent(data.query ?? "");
+
+ ws.send({
+ state: "REQUEST_RESPONSE",
+ data: {
+ _id: data._id ?? null,
+ data: Buffer.from(await (await fetch(query)).arrayBuffer()).toString("base64")
+ }
+ });
+
+ return;
+ }
+
+ ws.send({
+ state: "REQUEST_RESPONSE",
+ data: null
+ });
+}
+
+wss.on('connection', function connection(ws) {
+ ws.authenticated = false;
+ ws.token = null;
+ ws.auth = null;
+
+ ws._send = ws.send;
+ ws.send = (d) => {
+ return ws._send(JSON.stringify(d));
+ }
+
+ ws.on('error', console.error);
+
+ ws.on('message', async (_data) => {
+ try {
+ let data = JSON.parse(_data);
+
+ if (data.state) {
+ switch (data.state) {
+ case "AUTHENTICATION_RESPONSE":
+ if (data.token) {
+ let userInfo = (await (await fetch("https://school.equestria.dev/_matrix/client/v3/account/whoami", { headers: { 'Authorization': 'Bearer ' + data.token } })).json());
+ console.log(userInfo);
+
+ if (userInfo['user_id']) {
+ ws.auth = userInfo;
+ ws.token = data.token;
+ ws.authenticated = true;
+
+ ws.send({
+ state: "AUTHENTICATION_OK"
+ });
+ } else {
+ ws.close();
+ }
+ }
+ break;
+ }
+ }
+
+ if (!ws.authenticated) ws.close();
+ if (!data.state || data.state !== "AUTHENTICATION_RESPONSE") processRequest(ws, data);
+ } catch (e) {
+ console.error(e);
+ }
+ });
+
+ ws.send({
+ state: "NEEDS_AUTHENTICATION"
+ });
+});