Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chat #31

Merged
merged 4 commits into from
Mar 10, 2025
Merged

Chat #31

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions 15_chat/.Rprofile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
source("renv/activate.R")
7 changes: 7 additions & 0 deletions 15_chat/chat/__init__.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#' @export
box::use(
./chat[
chat_get,
chat_ws,
],
)
16 changes: 16 additions & 0 deletions 15_chat/chat/chat.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
box::use(
.. / ui[page, ],
)

#' @export
chat_get <- function(req, res) {
res$send(page())
}

#' @export
chat_ws <- function(msg, ws) {
ambiorix::get_websocket_clients() |>
lapply(\(c) {
c$send("chat", msg)
})
}
18 changes: 18 additions & 0 deletions 15_chat/index.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
box::use(
ambiorix[Ambiorix],
. / chat[
chat_get,
chat_ws,
],
)

PORT <- 3000

app <- Ambiorix$new()

app$static("public", "static")

app$get("/", chat_get)
app$receive("chat", chat_ws)

app$start(port = PORT)
79 changes: 79 additions & 0 deletions 15_chat/public/ambiorix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// default insecure
let protocol = 'ws://';

// upgrade if secure
if (window.location.protocol == "https:")
protocol = 'wss://';

// get websocket
let ambiorixSocket = new WebSocket(protocol + window.location.host);

// ambiorix Websocket
class Ambiorix {
constructor() {
this.onOpen = () => { };
this.onClose = () => { };
this.onError = (error) => { console.error(error) };
this._handlers = new Map();
}
// send
static send(name, message) {

// build message
let msg = { name: name, message: message, isAmbiorix: true };

ambiorixSocket.send(JSON.stringify(msg));

}

onopen(fn) {
this.onOpen = fn;
}

onclose(fn) {
this.onClose = fn;
}

onerror(fn) {
this.onError = fn;
}

start() {
var that = this;
ambiorixSocket.onmessage = (msg) => {
let msgParsed = JSON.parse(msg.data);

if (!msgParsed.isAmbiorix)
return;

if (that._handlers.has(msgParsed.name)) {
that._handlers.get(msgParsed.name)(msgParsed.message);
}
}

ambiorixSocket.onopen = this.onOpen;
ambiorixSocket.onclose = this.onClose;
ambiorixSocket.onerror = this.onError;
}
// receiver
receive(name, fun) {
this._handlers.set(name, fun)
}
}

// helper function to parseCookies
// parseCookie(document.cookie);
const parseCookie = str => {
if (str == "")
return {};

return str
.split(';')
.map(v => v.split('='))
.reduce(
(acc, v) => {
acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim());
return acc;
},
{});
}
90 changes: 90 additions & 0 deletions 15_chat/public/chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const icon = (() => {
const x = [
"ash",
"bcrikko",
"bulbasaur",
"charmander",
"kirby",
"mario",
"logo",
"octocat",
"pokeball",
"squirtle",
];
return x[Math.floor(Math.random() * x.length)];
})();

document.addEventListener("DOMContentLoaded", function() {
const id = createId();

const wss = new Ambiorix();
wss.onopen(() => {
console.info("Connecting");
});

wss.receive("chat", (msg) => {
// it was sent by me
if (msg.id == id) return;
insertLeft(msg.text, msg.icon);
});

wss.onclose(() => {
console.error("Disconnected");
});

wss.start();

handleChat(id);
});

const createId = () => {
return Math.random().toString(16).slice(2);
}

const handleChat = (id) => {
const btn = document.querySelector("#send");
btn.addEventListener("click", (_event) => {
const tgt = document.querySelector("#message")
const text = tgt.value;
tgt.value = "";

if (!text || text == "") return;

insertRight(text);
Ambiorix.send("chat", { text: text, id: id, icon: icon });
});

const query = document.querySelector("#message");
query.addEventListener("keydown", (event) => {
if (event.key != "Enter") return;

const btn = document.querySelector("#send");
btn.click();
})
}

const insertLeft = (message, icon) => {
document.querySelector("#chat-list").insertAdjacentHTML("beforeend", chatLeft(message, icon))
}

const insertRight = (message) => {
document.querySelector("#chat-list").insertAdjacentHTML("beforeend", chatRight(message))
}

const chatLeft = (message, icon) => {
return `<section class="message -left">
<i class="nes-${icon}"></i>
<div class="nes-balloon from-left">
<p>${message}</p>
</div>
</section>`;
}

const chatRight = (message) => {
return `<section class="message -right">
<div class="nes-balloon from-right">
<p>${message}</p>
</div>
<i class="nes-${icon}"></i>
</section>`;
}
28 changes: 28 additions & 0 deletions 15_chat/public/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
body {
min-height: 100vh;
margin: 0 2rem;
}

.d-flex {
display: flex;
}

.d-shrink {
flex-shrink: 1;
}

.d-grow {
flex-grow: 1;
}

.mb-1 {
margin-bottom: 0.5rem;
}

.mr-1 {
margin-right: 0.5rem;
}

.nes-balloon {
min-width: 80%;
}
Loading