aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client-web/source/chat.ts4
-rw-r--r--client-web/source/helper.ts4
-rw-r--r--client-web/source/keybinds.ts2
-rw-r--r--client-web/source/preferences/mod.ts2
-rw-r--r--client-web/source/resource/mod.ts2
-rw-r--r--client-web/source/resource/track.ts18
-rw-r--r--client-web/source/user/local.ts28
-rw-r--r--client-web/source/user/remote.ts8
-rw-r--r--readme.md10
9 files changed, 45 insertions, 33 deletions
diff --git a/client-web/source/chat.ts b/client-web/source/chat.ts
index 2ee08fc..d6aeb00 100644
--- a/client-web/source/chat.ts
+++ b/client-web/source/chat.ts
@@ -52,10 +52,8 @@ export class Chat extends OverlayUi {
}
}
}
- focus() {
- this.send_el.focus()
- }
+ focus() { this.send_el.focus() }
send(msg: ChatMessage) {
this.room.local_user.chat(msg)
this.add_message(this.room.local_user, msg)
diff --git a/client-web/source/helper.ts b/client-web/source/helper.ts
index e07fc7a..b05bea5 100644
--- a/client-web/source/helper.ts
+++ b/client-web/source/helper.ts
@@ -4,12 +4,12 @@ import { PREFS } from "./preferences/mod.ts";
const elem = (s: string) => document.createElement(s)
-interface Opts { class?: string[] | string, id?: string, src?: string, onclick?: () => void }
+interface Opts { class?: string[] | string, id?: string, src?: string, onclick?: (e: HTMLElement) => void }
function apply_opts(e: HTMLElement, o: Opts | undefined) {
if (!o) return
if (o.id) e.id = o.id
- if (o.onclick) e.onclick = o.onclick
+ if (o.onclick) e.onclick = () => o.onclick!(e)
if (typeof o?.class == "string") e.classList.add(o.class)
if (typeof o?.class == "object") e.classList.add(...o.class)
}
diff --git a/client-web/source/keybinds.ts b/client-web/source/keybinds.ts
index bbae1b8..028e119 100644
--- a/client-web/source/keybinds.ts
+++ b/client-web/source/keybinds.ts
@@ -21,7 +21,7 @@ export function setup_keybinds(room: Room) {
if (ev.code == "KeyM" || ev.code == "KeyR") room.local_user.await_add_resource(room.local_user.create_mic_res())
if (ev.code == "KeyS") room.local_user.await_add_resource(room.local_user.create_screencast_res())
if (ev.code == "KeyC" && !ev.ctrlKey) room.local_user.await_add_resource(room.local_user.create_camera_res())
- if (ev.code == "KeyC" && ev.ctrlKey) room.local_user.resources.forEach(t => t.end())
+ if (ev.code == "KeyC" && ev.ctrlKey) room.local_user.resources.forEach(t => t.destroy())
}
command_mode = false
})
diff --git a/client-web/source/preferences/mod.ts b/client-web/source/preferences/mod.ts
index ecff8fa..f4fa551 100644
--- a/client-web/source/preferences/mod.ts
+++ b/client-web/source/preferences/mod.ts
@@ -18,7 +18,7 @@ type TypeMapper = { "string": string, "number": number, "boolean": boolean }
type PrefMap<T extends { [key: string]: { type: unknown } }> = { [Key in keyof T]: T[Key]["type"] }
type Optional<T extends { [key: string]: unknown }> = { [Key in keyof T]?: T[Key] }
export const { prefs: PREFS, explicit: PREFS_EXPLICIT } = register_prefs(PREF_DECLS)
-const pref_change_handlers: Map<keyof typeof PREFS, Map<() => unknown>> = new Map()
+const pref_change_handlers: Map<keyof typeof PREFS, Set<() => unknown>> = new Map()
export const on_pref_changed = (key: keyof typeof PREFS, cb: () => unknown): (() => void) => {
const m = (pref_change_handlers.get(key)
?? (() => {
diff --git a/client-web/source/resource/mod.ts b/client-web/source/resource/mod.ts
index 3091a45..9583604 100644
--- a/client-web/source/resource/mod.ts
+++ b/client-web/source/resource/mod.ts
@@ -42,7 +42,7 @@ export abstract class Resource {
}
request_stop() {
if (!(this.user instanceof RemoteUser)) return
- this.user.send_to({ request: { id: this.info.id } })
+ this.user.send_to({ request_stop: { id: this.info.id } })
}
update_el() {
diff --git a/client-web/source/resource/track.ts b/client-web/source/resource/track.ts
index f58e020..bc26acc 100644
--- a/client-web/source/resource/track.ts
+++ b/client-web/source/resource/track.ts
@@ -24,12 +24,28 @@ export class TrackResource extends Resource {
this.update_el()
}
+ destroy() {
+ this.track?.end()
+ super.destroy()
+ }
+
create_preview(): HTMLElement {
- return ebutton("Enable", { onclick: () => this.request() })
+ return ebutton("Enable", {
+ onclick: (e) => {
+ (e as HTMLButtonElement).disabled = true;
+ this.request()
+ }
+ })
}
create_element() {
if (!this.track) { return this.create_preview() }
const el = document.createElement("div")
+ el.append(ebutton("Disable", {
+ onclick: (e) => {
+ (e as HTMLButtonElement).disabled = true;
+ this.request_stop()
+ }
+ }))
const is_video = this.track.kind == "video"
const media_el = is_video ? document.createElement("video") : document.createElement("audio")
diff --git a/client-web/source/user/local.ts b/client-web/source/user/local.ts
index e5d22e5..571295d 100644
--- a/client-web/source/user/local.ts
+++ b/client-web/source/user/local.ts
@@ -31,19 +31,19 @@ export class LocalUser extends User {
}
provide_initial_to_remote(u: RemoteUser) {
- this.resources.forEach(t => {
- if (t instanceof TrackResource && t.track)
- u.peer.addTrack(t.track.track)
+ this.resources.forEach(r => {
+ this.room.signaling.send_relay({ provide: r.info }, u.id)
})
}
+
identify(recipient?: number) {
if (this.name) this.room.signaling.send_relay({ identify: { username: this.name } }, recipient)
}
+
chat(message: ChatMessage) {
this.room.signaling.send_relay({ chat: message })
}
-
create_controls() {
const mic_toggle = document.createElement("input")
const camera_toggle = document.createElement("input")
@@ -78,16 +78,16 @@ export class LocalUser extends User {
}
}
- send_track(t: TrackHandle) {
- this.room.remote_users.forEach(u => u.peer.addTrack(t.track))
- t.addEventListener("ended", () => {
- this.room.remote_users.forEach(u => {
- u.peer.getSenders().forEach(s => {
- if (s.track == t.track) u.peer.removeTrack(s)
- })
- })
- })
- }
+ // send_track(t: TrackHandle) {
+ // this.room.remote_users.forEach(u => u.peer.addTrack(t.track))
+ // t.addEventListener("ended", () => {
+ // this.room.remote_users.forEach(u => {
+ // u.peer.getSenders().forEach(s => {
+ // if (s.track == t.track) u.peer.removeTrack(s)
+ // })
+ // })
+ // })
+ // }
async create_camera_res() {
log("media", "requesting user media (camera)")
diff --git a/client-web/source/user/remote.ts b/client-web/source/user/remote.ts
index 59d811a..8921b04 100644
--- a/client-web/source/user/remote.ts
+++ b/client-web/source/user/remote.ts
@@ -33,12 +33,12 @@ export class RemoteUser extends User {
this.peer.ontrack = ev => {
console.log(ev)
const t = ev.track
- const id = ev.streams[0].id
- if (!id) return log({ scope: "media", warn: true }, "got a track without stream")
+ const id = ev.streams[0]?.id
+ if (!id) { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got a track without stream") }
const r = this.resources.get(id)
- if (!r) return log({ scope: "media", warn: true }, "got an unassociated track")
+ if (!r) { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got an unassociated track") }
if (r instanceof TrackResource) r.track = new TrackHandle(t);
- else log({ scope: "media", warn: true }, "got a track for a resource that should use data channel")
+ else { ev.transceiver.stop(); return log({ scope: "media", warn: true }, "got a track for a resource that should use data channel") }
log("media", `remote track: ${this.display_name}`, t)
this.update_stats()
}
diff --git a/readme.md b/readme.md
index 06b90c4..ca3bddf 100644
--- a/readme.md
+++ b/readme.md
@@ -101,21 +101,19 @@ keks-meet _tries_ to be secure. However I am not a security expert. The current
## Todo-List
-- Optionally enable video streams
+- Make the optional streams UI prettier
+- Maybe group tracks in streams to make sure everything is in sync
+- How do we implement global hotkeys?
+- Dont use websocket to send images to not block anything else
- Native client
-- Prevent server from changing message sender
- Have a security professional look at the code
- Test some options like `camera_facing_mode`
- Signing key for each user
- Built-in storage for known keys
- Relay RTC when there are a lot of clients
-- Save permissions to locale storage
- Prevent join notification bypass by not identifying
-- Dont use websocket to send images to not block anything else
-- How do we implement global hotkeys?
- Tray icon for native
- Pin js by bookmarking data:text/html loader page
-- Maybe group tracks in streams to make sure everything is in sync
## Protocol