aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/client/helper.ts6
-rw-r--r--source/client/index.ts15
-rw-r--r--source/client/local_user.ts18
-rw-r--r--source/client/logger.ts1
-rw-r--r--source/client/remote_user.ts10
-rw-r--r--source/client/rnnoise.ts11
-rw-r--r--source/client/room.ts13
-rw-r--r--source/client/types.ts16
-rw-r--r--source/client/user.ts9
-rw-r--r--source/packets.ts31
-rw-r--r--source/server/index.ts142
-rw-r--r--source/server/room.ts56
12 files changed, 186 insertions, 142 deletions
diff --git a/source/client/helper.ts b/source/client/helper.ts
index 9fb4052..c46b169 100644
--- a/source/client/helper.ts
+++ b/source/client/helper.ts
@@ -1,4 +1,4 @@
-import { parameters } from "."
+import { parameters } from "./index.ts"
export function get_query_params(): { [key: string]: string } {
const q: { [key: string]: string } = {}
@@ -9,7 +9,7 @@ export function get_query_params(): { [key: string]: string } {
return q
}
-export function hex_id(len: number = 8): string {
+export function hex_id(len = 8): string {
if (len > 8) return hex_id() + hex_id(len - 8)
return Math.floor(Math.random() * 16 ** len).toString(16).padStart(len, "0")
}
@@ -21,7 +21,7 @@ export function parameter_bool(name: string, def: boolean): boolean {
if (v == "0" || v == "false" || v == "no") return false
if (v == "1" || v == "true" || v == "yes") return true
alert(`parameter ${name} is invalid`)
- return def
+ return def
}
export function parameter_number(name: string, def: number): number {
diff --git a/source/client/index.ts b/source/client/index.ts
index 313cd86..0c7e728 100644
--- a/source/client/index.ts
+++ b/source/client/index.ts
@@ -1,6 +1,8 @@
-import { get_query_params } from "./helper"
-import { log } from "./logger"
-import { Room } from "./room"
+/// <reference lib="dom" />
+
+import { get_query_params } from "./helper.ts"
+import { log } from "./logger.ts"
+import { Room } from "./room.ts"
export const servers = {
iceServers: [{ urls: ["stun:stun1.l.google.com:19302", "stun:stun2.l.google.com:19302"] }],
@@ -13,14 +15,15 @@ export interface User {
}
-export var parameters = get_query_params()
+export const parameters = get_query_params()
window.onload = () => main()
-export async function main() {
+export function main() {
+ log("*", "starting up")
if (window.location.pathname.startsWith("/room/")) {
const room_name = window.location.pathname.substr("/room/".length)
- let room = new Room(room_name)
+ const room = new Room(room_name)
document.body.append(room.el)
} else {
document.body.append(create_start_screen())
diff --git a/source/client/local_user.ts b/source/client/local_user.ts
index 7f2327e..540e311 100644
--- a/source/client/local_user.ts
+++ b/source/client/local_user.ts
@@ -1,9 +1,9 @@
-import { parameter_bool, parameter_number, parameter_string } from "./helper";
-import { log } from "./logger";
-import { RemoteUser } from "./remote_user";
-import { get_rnnoise_node } from "./rnnoise";
-import { Room } from "./room";
-import { User } from "./user";
+import { parameter_bool, parameter_number } from "./helper.ts";
+import { log } from "./logger.ts";
+import { RemoteUser } from "./remote_user.ts";
+import { get_rnnoise_node } from "./rnnoise.ts";
+import { Room } from "./room.ts";
+import { User } from "./user.ts";
export class LocalUser extends User {
@@ -74,7 +74,7 @@ export class LocalUser extends User {
else this.controls?.video.classList.remove("enabled")
}
- async add_initial_to_remote(ru: RemoteUser) {
+ add_initial_to_remote(ru: RemoteUser) {
if (this.audio_track) ru.peer.addTrack(this.audio_track)
if (this.video_track) ru.peer.addTrack(this.video_track)
}
@@ -133,7 +133,7 @@ export class LocalUser extends User {
this.update_view_w()
}
- async disable_video() {
+ disable_video() {
if (!this.video_track) return
this.room.remote_users.forEach(u => {
u.peer.getSenders().forEach(s => {
@@ -144,7 +144,7 @@ export class LocalUser extends User {
this.update_view_w()
this.video_track = undefined
}
- async disable_audio() {
+ disable_audio() {
if (!this.audio_track) return
if (this.audio_disable_cleanup) this.audio_disable_cleanup()
this.room.remote_users.forEach(u => {
diff --git a/source/client/logger.ts b/source/client/logger.ts
index 637f5c0..745ce88 100644
--- a/source/client/logger.ts
+++ b/source/client/logger.ts
@@ -9,6 +9,7 @@ const log_tag_color: { [key in LogTag]: string } = {
}
// TODO maybe log time aswell
+// deno-lint-ignore no-explicit-any
export function log(tag: LogTag, message: string, ...data: any[]) {
for (let i = 0; i < data.length; i++) {
const e = data[i];
diff --git a/source/client/remote_user.ts b/source/client/remote_user.ts
index 6986a11..9e33a09 100644
--- a/source/client/remote_user.ts
+++ b/source/client/remote_user.ts
@@ -1,13 +1,13 @@
-import { servers } from "."
-import { log } from "./logger"
-import { Room } from "./room"
-import { User } from "./user"
+import { servers } from "./index.ts"
+import { log } from "./logger.ts"
+import { Room } from "./room.ts"
+import { User } from "./user.ts"
export class RemoteUser extends User {
peer: RTCPeerConnection
- negotiation_busy: boolean = false
+ negotiation_busy = false
constructor(room: Room, name: string) {
super(room, name)
diff --git a/source/client/rnnoise.ts b/source/client/rnnoise.ts
index c9014ef..0d301c5 100644
--- a/source/client/rnnoise.ts
+++ b/source/client/rnnoise.ts
@@ -1,9 +1,10 @@
-import { log } from "./logger"
+import { log } from "./logger.ts"
declare global {
class RNNoiseNode extends AudioWorkletNode {
static register(context: AudioContext): Promise<void>
constructor(context: AudioContext)
+ // deno-lint-ignore no-explicit-any
onstatus: (data: any) => void
update(something: boolean): void
}
@@ -13,19 +14,19 @@ declare global {
// TODO fix leak
export async function get_rnnoise_node(context: AudioContext): Promise<RNNoiseNode> {
log("misc", "rnnoise enabled")
- //@ts-ignore
+ //@ts-ignore asfdasfd
let RNNoiseNode: typeof RNNoiseNode = window.RNNoiseNode;
let script: HTMLScriptElement;
if (!RNNoiseNode) {
log("misc", "loading rnnoise...")
script = document.createElement("script")
- script.src = "/static/rnnoise/rnnoise-runtime.js"
+ script.src = "/rnnoise/rnnoise-runtime.js"
script.defer = true
document.head.appendChild(script)
- //@ts-ignore
+ //@ts-ignore asdfsfad
while (!window.RNNoiseNode) await new Promise<void>(r => setTimeout(() => r(), 100))
- //@ts-ignore
+ //@ts-ignore asfdsadfsafd
RNNoiseNode = window.RNNoiseNode;
log("misc", "rnnoise loaded")
}
diff --git a/source/client/room.ts b/source/client/room.ts
index 6a53a45..de6bff7 100644
--- a/source/client/room.ts
+++ b/source/client/room.ts
@@ -1,10 +1,9 @@
-import { log } from "./logger";
-import { CSPacket, SCPacket } from "./types";
-import { RemoteUser } from "./remote_user";
-import { User } from "./user";
-import { LocalUser } from "./local_user";
-import { parameters } from ".";
-import { hex_id, parameter_string } from "./helper";
+import { log } from "./logger.ts";
+import { RemoteUser } from "./remote_user.ts";
+import { User } from "./user.ts";
+import { LocalUser } from "./local_user.ts";
+import { hex_id, parameter_string } from "./helper.ts";
+import { CSPacket, SCPacket } from "../packets.ts";
export class Room {
diff --git a/source/client/types.ts b/source/client/types.ts
deleted file mode 100644
index 7ce23ea..0000000
--- a/source/client/types.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-
-export interface SCPacket {
- sender: string,
- data?: CSPacket,
- join?: boolean, // user just joined
- leave?: boolean, // user left
- stable?: boolean // user "joined" because you joined aka. user was already there
-}
-export interface CSPacket {
- receiver?: string
- ice_candiate?: RTCIceCandidateInit
- offer?: RTCSessionDescriptionInit
- answer?: RTCSessionDescriptionInit
-}
-
-
diff --git a/source/client/user.ts b/source/client/user.ts
index f4f33e1..ef1449f 100644
--- a/source/client/user.ts
+++ b/source/client/user.ts
@@ -1,5 +1,6 @@
-import { log } from "./logger"
-import { Room } from "./room"
+
+import { log } from "./logger.ts"
+import { Room } from "./room.ts"
export abstract class User {
@@ -11,7 +12,7 @@ export abstract class User {
display?: { audio_status_el: HTMLElement, video_status_el: HTMLElement }
- local: boolean = false
+ local = false
stream: MediaStream = new MediaStream()
@@ -96,7 +97,7 @@ export abstract class User {
const pip_el = document.createElement("input")
pip_el.type = "button"
pip_el.addEventListener("click", () => {
- //@ts-ignore
+ // @ts-ignore firefox feature
media_el.requestPictureInPicture()
})
pip_el.value = "Picture-in-Picture"
diff --git a/source/packets.ts b/source/packets.ts
new file mode 100644
index 0000000..ef65ce7
--- /dev/null
+++ b/source/packets.ts
@@ -0,0 +1,31 @@
+
+
+type F_RTCSdpType = "answer" | "offer" | "pranswer" | "rollback";
+interface F_RTCSessionDescriptionInit {
+ sdp?: string;
+ type: F_RTCSdpType;
+}
+
+interface F_RTCIceCandidateInit {
+ candidate?: string;
+ sdpMLineIndex?: number | null;
+ sdpMid?: string | null;
+ usernameFragment?: string | null;
+}
+
+
+export interface SCPacket {
+ sender: string,
+ data?: CSPacket,
+ join?: boolean, // user just joined
+ leave?: boolean, // user left
+ stable?: boolean // user "joined" because you joined aka. user was already there
+}
+export interface CSPacket {
+ receiver?: string
+ ice_candiate?: F_RTCIceCandidateInit
+ offer?: F_RTCSessionDescriptionInit
+ answer?: F_RTCSessionDescriptionInit
+}
+
+
diff --git a/source/server/index.ts b/source/server/index.ts
index 88c3a66..1ee6bc9 100644
--- a/source/server/index.ts
+++ b/source/server/index.ts
@@ -1,103 +1,71 @@
-import Express, { static as estatic, json } from "express";
-import { join } from "path";
-import Webpack from "webpack"
-import WebpackDevMiddleware from "webpack-dev-middleware"
-import { existsSync, readFile, readFileSync } from "fs";
-import http from "http"
-import https from "https"
-import expressWs from "express-ws";
-import { CSPacket, SCPacket } from "../client/types";
-import * as ws from "ws"
+import { Application, Router, RouterContext, send } from "https://deno.land/x/oak/mod.ts";
+import { api } from "./room.ts";
-type Room = Map<string, ws>
-const rooms: Map<string, Room> = new Map()
+const app = new Application()
-function ws_send(ws: ws, data: SCPacket) {
- try { ws.send(JSON.stringify(data)) }
- catch (e) { console.warn("i hate express-ws") }
-}
+const root = new Router()
+
+let bundleFiles: Record<string, string> = {}
-async function main() {
- const app_e = Express();
- const app = expressWs(app_e).app
+root.get("/", async c => { await c.send({ path: "index.html", root: `${Deno.cwd()}/public` }) })
+root.get("/room/:id", async c => { await c.send({ path: "index.html", root: `${Deno.cwd()}/public` }) })
- if (process.env.ENV == "production") {
- console.log("PRODUCTION MODE!!!");
- app.use("/scripts", estatic(join(__dirname, "../../public/dist")))
- } else {
- console.log("DEVELOPMENT MODE!!!");
- const webpackConfig = require('../../webpack.dev');
- const compiler = Webpack(webpackConfig)
- const devMiddleware = WebpackDevMiddleware(compiler, {
- publicPath: webpackConfig.output.publicPath
- })
- app.use("/scripts", devMiddleware)
+// deno-lint-ignore no-explicit-any
+function respondWithType(mimeType: string, f: () => string): (c: RouterContext<any, any, any>) => void {
+ return c => {
+ c.response.headers.set("Content-Type", mimeType)
+ c.response.body = f()
}
+}
- app.disable("x-powered-by");
- app.use(json());
+root.get("/bundle.js", respondWithType("application/javascript", () => bundleFiles["deno:///bundle.js"]))
+root.get("/bundle.js.map", respondWithType("application/javascript", () => bundleFiles["deno:///bundle.js.map"]))
- app.get("/", (req, res) => {
- res.sendFile(join(__dirname, "../../public/index.html"));
- });
- app.get("/room/:id", (req, res) => {
- res.sendFile(join(__dirname, "../../public/index.html"));
- });
+function mountFilesystem(r: Router, route: string, path: string) {
+ r.get(route + "/(.*)", async (context) => {
+ await send(context, context.request.url.pathname, { root: Deno.cwd() + path });
+ })
- app.use("/static", estatic(join(__dirname, "../../public")));
+}
- app.ws("/signaling/:id", (ws, req) => {
- const room_name = req.params.id
- const room: Map<string, ws> = rooms.get(req.params.id) ?? new Map()
- let initialized = false
- let user_name = ""
+mountFilesystem(root, "/style", "/public")
+mountFilesystem(root, "/rnnoise", "/public")
- const init = (n: string) => {
- if (room.get(n)) return ws.close()
- initialized = true
- user_name = n
- rooms.set(req.params.id, room)
- room.forEach(uws => ws_send(uws, { sender: user_name, join: true }))
- room.forEach((_, uname) => ws_send(ws, { sender: uname, join: true, stable: true }))
- room.set(user_name, ws)
- console.log(`[${room_name}] ${user_name} joined`)
- }
- ws.onclose = () => {
- room.delete(user_name)
- room.forEach(uws => ws_send(uws, { sender: user_name, leave: true }))
- if (room.size == 0) rooms.delete(room_name)
- console.log(`[${room_name}] ${user_name} left`)
- }
- ws.onmessage = ev => {
- const message = ev.data.toString()
- if (!initialized) return init(message)
- let in_packet: CSPacket;
- try { in_packet = JSON.parse(message) }
- catch (e) { return }
+root.use(api.routes())
- console.log(`[${room_name}] ${user_name} -> ${in_packet.receiver ?? "*"}: ${message.substr(0, 100)}`)
- const out_packet: SCPacket = { sender: user_name, data: in_packet }
+app.use(root.routes())
+app.use(root.allowedMethods())
- if (in_packet.receiver) {
- const rws = room.get(in_packet.receiver)
- if (rws) ws_send(rws, out_packet)
- } else {
- room.forEach((uws, uname) => {
- if (uname != user_name) ws_send(uws, out_packet)
- })
- }
- }
- })
+app.addEventListener("listen", ({ hostname, port, secure }) => {
+ console.log(`listening on: ${secure ? "https://" : "http://"}${hostname}:${port}`);
+});
- app.use((req, res, next) => {
- res.status(404);
- res.send("This is an error page");
- });
+app.listen({
+ hostname: Deno.env.get("HOSTNAME") ?? "127.0.0.1",
+ port: parseInt(Deno.env.get("PORT") ?? "8080")
+});
- const port = parseInt(process.env.PORT ?? "8080")
- app.listen(port, process.env.HOST ?? "127.0.0.1", () => {
- console.log(`Server listening on ${process.env.HOST ?? "127.0.0.1"}:${port}`);
- })
+
+let refresh_needed = false
+let refresh_pending = false
+async function refresh() {
+ refresh_needed = true
+ if (refresh_pending) return
+ refresh_needed = false
+ refresh_pending = true
+
+ try {
+ const { files } = await Deno.emit("source/client/index.ts", { bundle: "module", check: false })
+ bundleFiles = files
+ } catch (e) { console.error(e) }
+
+ refresh_pending = false
+ if (refresh_needed) refresh()
}
-main(); \ No newline at end of file
+refresh()
+for await (const event of Deno.watchFs("source/client")) {
+ if (event.kind == "modify" || event.kind == "create") {
+ refresh()
+ }
+}
diff --git a/source/server/room.ts b/source/server/room.ts
new file mode 100644
index 0000000..34d847c
--- /dev/null
+++ b/source/server/room.ts
@@ -0,0 +1,56 @@
+import { Router } from "https://deno.land/x/oak@v10.1.0/router.ts";
+import { CSPacket, SCPacket } from "../packets.ts";
+
+export const api = new Router()
+
+type Room = Map<string, WebSocket>
+const rooms: Map<string, Room> = new Map()
+
+function send_packet(ws: WebSocket, packet: SCPacket) {
+ ws.send(JSON.stringify(packet))
+}
+
+api.get("/signaling/:id", c => {
+ const ws = c.upgrade()
+
+ const room_name = c.params.id
+ const room: Room = rooms.get(c.params.id) ?? new Map()
+ let initialized = false
+ let user_name = ""
+
+ const init = (n: string) => {
+ if (room.get(n)) return ws.close()
+ initialized = true
+ user_name = n
+ rooms.set(c.params.id, room)
+ room.forEach(uws => send_packet(uws, { sender: user_name, join: true }))
+ room.forEach((_, uname) => send_packet(ws, { sender: uname, join: true, stable: true }))
+ room.set(user_name, ws)
+ console.log(`[${room_name}] ${user_name} joined`)
+ }
+ ws.onclose = () => {
+ room.delete(user_name)
+ room.forEach(uws => send_packet(uws, { sender: user_name, leave: true }))
+ if (room.size == 0) rooms.delete(room_name)
+ console.log(`[${room_name}] ${user_name} left`)
+ }
+ ws.onmessage = ev => {
+ const message = ev.data.toString()
+ if (!initialized) return init(message)
+ let in_packet: CSPacket;
+ try { in_packet = JSON.parse(message) }
+ catch (_e) { return }
+
+ console.log(`[${room_name}] ${user_name} -> ${in_packet.receiver ?? "*"}: ${message.substr(0, 100)}`)
+ const out_packet: SCPacket = { sender: user_name, data: in_packet }
+
+ if (in_packet.receiver) {
+ const rws = room.get(in_packet.receiver)
+ if (rws) send_packet(rws, out_packet)
+ } else {
+ room.forEach((uws, uname) => {
+ if (uname != user_name) send_packet(uws, out_packet)
+ })
+ }
+ }
+})