From b4dcb61301feb867c490faef3183304ea42fd6e7 Mon Sep 17 00:00:00 2001 From: jerl Date: Sat, 7 Sep 2024 20:55:03 -0500 Subject: [PATCH] call --- README.md | 15 ++-- client/call.js | 139 +++++++++++++++++++++++++++++++++++++ client/index.html | 5 +- client/stream.js | 3 +- client/thread.js | 16 ++--- package.json | 1 + server.js | 13 +++- src/check_permission.js | 25 ++++--- src/db.js | 3 +- src/events/call.js | 147 ++++++++++++++++++++++++++++++++++++++++ src/events/stream.js | 9 +-- src/events/thread.js | 86 ++++++++++++++--------- 12 files changed, 389 insertions(+), 73 deletions(-) create mode 100644 client/call.js create mode 100644 src/events/call.js diff --git a/README.md b/README.md index 673943b..68f73fd 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ a vybe instance (server) features user accounts and **threads**. user accounts are owned by PGP keys stored in users' clients. -each thread features a chatroom, a **space**, and audio streams. +each thread features a chatroom, a call, a **space**, and audio streams. a space is like a text blackboard, basically. you can write text and move it around and resize it with your mouse. @@ -21,21 +21,24 @@ then > `node .` -it will run on port 1312 by default; you can change this by setting PORT on first-run: +it will run on port 1312 by default; on first run, you can change this by setting PORT: > `PORT=1234 node .` -after first-run, the port is configured in instance.json. +after first run, the port is configured in instance.json. **currently, you'll need to proxy it through a webserver like nginx or Caddy, which needs to have https enabled** for things to work correctly. if you want the easy option, i recommend Caddy. example Caddy config: > ``` -> vybe.my.domain { +> vybe.example.domain { > reverse_proxy localhost:1312 +> header Access-Control-Allow-Origin "*" > } -> ``` +> ``` -then go to `https://vybe.my.domain` to start using vybe! +(the allow-origin header isn't required normally unless websockets don't work for whatever reason) + +then go to `https://vybe.example.domain` to start using vybe! ## todo diff --git a/client/call.js b/client/call.js new file mode 100644 index 0000000..d9576ef --- /dev/null +++ b/client/call.js @@ -0,0 +1,139 @@ +import { render, html } from '/uhtml.js'; +import loadStreams from '/stream.js'; + +let instance; +let thread; +let connection; +let mediaStream; + +function loadCall() { + let div = document.getElementById('call'); + render(div, html` +
+

no one is in call

+ +
+
`); + if (Object.keys(currentThread.call).length) + div.children['noone'].classList.add('hidden'); + for (let id in currentThread.call) { + let p = document.createElement('p'); + p.append(window.makeUser(currentThread.call[id], id.split?.('@')[1] || currentInstance.url)); + div.children['users'].append(p); + } + if (!currentInstance.called) { + currentInstance.socket.on('call', msg => { + if (msg.thread !== currentThread.id) + return; + if (Object.keys(msg.call).length) + div.children['noone'].classList.add('hidden'); + else + div.children['noone'].classList.remove('hidden'); + currentThread.call = msg.call; + div.children['users'].replaceChildren(...Object.values(msg.call).map(user => { + let p = document.createElement('p'); + p.append(window.makeUser(user, user.id.split?.('@')[1] || currentInstance.url)); + return p; + })); + }); + currentInstance.socket.on('offer', async (msg, respond) => { + if (!connection) + return; + await connection.setRemoteDescription(msg.sdp); + await connection.setLocalDescription(await connection.createAnswer()); + respond({ + success: true, + sdp: connection.localDescription + }); + }); + currentInstance.socket.on('ice', msg => { + if (!connection) + return; + connection.addIceCandidate(new RTCIceCandidate(msg.candidate)); + }); + currentInstance.called = true; + } + loadStreams(); +} + +export default loadCall; diff --git a/client/index.html b/client/index.html index 61f2147..63d93ff 100644 --- a/client/index.html +++ b/client/index.html @@ -272,9 +272,9 @@ } .tabcontent { flex: 1; + margin: 0 2px; } #message { - margin: 2px; display: flex; flex-direction: column; min-height: 0; /* flex makes this auto so it can't shrink */ @@ -323,9 +323,6 @@ position: absolute; white-space: nowrap; } - #stream { - margin: 4px 2px; - } #play { line-height: 1.4; font-family: 'Segoe UI Symbol', math; diff --git a/client/stream.js b/client/stream.js index 35cb3a9..a6fe70a 100644 --- a/client/stream.js +++ b/client/stream.js @@ -78,8 +78,7 @@ function loadStreams() { let div = document.getElementById('stream'); div.innerHTML = ''; if (window.currentThread?.permissions.post) { - // why doesn't html` work here? html.node` does - render(div, html.node` + render(div, html` diff --git a/client/thread.js b/client/thread.js index 1220b4d..816b7ee 100644 --- a/client/thread.js +++ b/client/thread.js @@ -1,7 +1,7 @@ import { render, html } from '/uhtml.js'; import loadMessages from '/message.js'; import loadSpace from '/space.js'; -import loadStreams from '/stream.js'; +import loadCall from '/call.js'; function setVisibility() { document.getElementById('visibility').innerText = `${ @@ -77,9 +77,9 @@ function chooseThread() { return p; })) ); - loadStreams(); + loadCall(); let tab = url.searchParams.get('tab'); - if (!['message', 'space', 'stream'].includes(tab)) + if (!['message', 'space', 'call'].includes(tab)) tab = null; if (tab || this.tab) { if (tab) @@ -101,11 +101,11 @@ function chooseThread() { if (spans.length) switchTab(document.getElementById(div.tab = 'spacetab')); else if (window.currentThread.streams.length) - switchTab(document.getElementById(div.tab = 'streamtab')); + switchTab(document.getElementById(div.tab = 'calltab')); else switchTab(document.getElementById( div.tab = spans.length ? 'spacetab' : - window.currentThread.streams.length ? 'streamtab' : 'messagetab')); + window.currentThread.streams.length ? 'calltab' : 'messagetab')); resolve(); }); }); @@ -142,7 +142,7 @@ function newThread(instance) { let members = [{ id: String(window.id), name: window.name, - permissions: { admin: 'true' } + permissions: { admin: true } }]; if (instance !== window.instancelist[0]) { members[0].id += '@' + location.host; @@ -387,7 +387,7 @@ async function loadThreads(instancediv, select) {
+