summaryrefslogtreecommitdiff
path: root/static/src
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2021-09-02 17:02:20 -0600
committerBrian Picciano <mediocregopher@gmail.com>2021-09-02 17:02:20 -0600
commit34f44cb5d5d6316009f242d27d2f3d69f4d5b90e (patch)
tree116a6e2db06dac246e794d1bc7f9e8b0c04f22e9 /static/src
parent6bebc3fae73b5f5f68e5de9e083635cfab9037b1 (diff)
implementation of basic chat page which can show history and not much else
Diffstat (limited to 'static/src')
-rw-r--r--static/src/assets/api.js52
-rw-r--r--static/src/chat.md126
2 files changed, 175 insertions, 3 deletions
diff --git a/static/src/assets/api.js b/static/src/assets/api.js
index 7ce2e89..4447bb1 100644
--- a/static/src/assets/api.js
+++ b/static/src/assets/api.js
@@ -1,5 +1,7 @@
import * as utils from "/assets/utils.js";
+const csrfTokenCookie = "csrf_token";
+
const doFetch = async (req) => {
let res, jsonRes;
try {
@@ -53,13 +55,13 @@ const call = async (route, opts = {}) => {
requiresPow = false,
} = opts;
- if (!utils.cookies["csrf_token"])
- throw "csrf_token cookie not set, can't make api call";
+ if (!utils.cookies[csrfTokenCookie])
+ throw `${csrfTokenCookie} cookie not set, can't make api call`;
const reqOpts = {
method,
headers: {
- "X-CSRF-Token": utils.cookies["csrf_token"],
+ "X-CSRF-Token": utils.cookies[csrfTokenCookie],
},
};
@@ -80,6 +82,50 @@ const call = async (route, opts = {}) => {
return doFetch(req);
}
+const ws = async (route, opts = {}) => {
+ const {
+ requiresPow = false,
+ } = opts;
+
+ const docURL = new URL(document.URL);
+ const protocol = docURL.protocol == "http:" ? "ws:" : "wss:";
+
+ const params = new URLSearchParams();
+ const csrfToken = utils.cookies[csrfTokenCookie];
+
+ if (!csrfToken)
+ throw `${csrfTokenCookie} cookie not set, can't make api call`;
+
+ params.set("csrfToken", csrfToken);
+
+ if (requiresPow) {
+ const {seed, solution} = await solvePow();
+ params.set("powSeed", seed);
+ params.set("powSolution", solution);
+ }
+
+ const rawConn = new WebSocket(`${protocol}//${docURL.host}${route}?${params.toString()}`);
+
+ const conn = {
+ next: () => new Promise((resolve, reject) => {
+ rawConn.onmessage = (m) => {
+ const mj = JSON.parse(m.data);
+ resolve(mj);
+ };
+ rawConn.onerror = reject;
+ rawConn.onclose = reject;
+ }),
+
+ close: rawConn.close,
+ };
+
+ return new Promise((resolve, reject) => {
+ rawConn.onopen = () => resolve(conn);
+ rawConn.onerror = reject;
+ });
+}
+
export {
call,
+ ws
}
diff --git a/static/src/chat.md b/static/src/chat.md
new file mode 100644
index 0000000..c7471ef
--- /dev/null
+++ b/static/src/chat.md
@@ -0,0 +1,126 @@
+---
+layout: page
+---
+
+<script async type="module" src="/assets/api.js"></script>
+
+<style>
+ #messages {
+ max-height: 65vh;
+ overflow: auto;
+ }
+
+ #messages .message {
+ border: 1px solid #AAA;
+ border-radius: 10px;
+ margin-bottom: 1rem;
+ padding: 2rem;
+ overflow: auto;
+ }
+
+ #messages .message .title {
+ font-weight: bold;
+ font-size: 120%;
+ }
+
+ #messages .message .secondaryTitle {
+ font-family: monospace;
+ color: #CCC;
+ }
+
+ #messages .message p {
+ font-family: monospace;
+ margin: 1rem 0 0 0;
+ }
+
+</style>
+
+<div id="messages"></div>
+
+<span id="fail" style="color: red;"></span>
+
+<script>
+
+const messagesEl = document.getElementById("messages");
+
+function renderMessages(msgs) {
+
+ msgs = [...msgs].reverse();
+
+ messagesEl.innerHTML = '';
+
+ msgs.forEach((msg) => {
+ console.log(msg);
+ const el = document.createElement("div");
+ el.className = "row message"
+
+ const elWithTextContents = (tag, body) => {
+ const el = document.createElement(tag);
+ el.appendChild(document.createTextNode(body));
+ return el;
+ };
+
+ const titleEl = document.createElement("div");
+ titleEl.className = "title";
+ el.appendChild(titleEl);
+
+ const userNameEl = elWithTextContents("span", msg.userID.name);
+ titleEl.appendChild(userNameEl);
+
+ const secondaryTitleEl = document.createElement("div");
+ secondaryTitleEl.className = "secondaryTitle";
+ el.appendChild(secondaryTitleEl);
+
+ const dt = new Date(msg.createdAt*1000);
+ const dtStr
+ = `${dt.getFullYear()}-${dt.getMonth()+1}-${dt.getDate()}`
+ + ` ${dt.getHours()}:${dt.getMinutes()}:${dt.getSeconds()}`;
+
+ const userIDEl = elWithTextContents("span", `userID:${msg.userID.id} @ ${dtStr}`);
+ secondaryTitleEl.appendChild(userIDEl);
+
+ const bodyEl = document.createElement("p");
+
+ const bodyParts = msg.body.split("\n");
+ for (const i in bodyParts) {
+ if (i > 0) bodyEl.appendChild(document.createElement("br"));
+ bodyEl.appendChild(document.createTextNode(bodyParts[i]));
+ }
+
+ el.appendChild(bodyEl);
+
+ messagesEl.appendChild(el);
+ });
+}
+
+
+(async () => {
+
+ const failEl = document.getElementById("fail");
+
+ setErr = (msg) => failEl.innerHTML = `${msg} (please refresh the page to retry)`;
+
+ const api = await import("/assets/api.js");
+
+ try {
+
+ const history = await api.call("/api/chat/global/history");
+ renderMessages(history.messages);
+
+ } catch (e) {
+ e = `Failed to fetch message history: ${e}`
+ setErr(e);
+ console.error(e);
+ return;
+ }
+
+ //const ws = await api.ws("/api/chat/global/listen");
+
+ //while (true) {
+ // const msg = await ws.next();
+ // console.log("got msg", msg);
+ //}
+
+})()
+
+</script>