Skip to content

Commit

Permalink
Merge pull request #59 from webxdc/sk/ephemeral_peer_chnnel
Browse files Browse the repository at this point in the history
feat: ephemeral peer channels
  • Loading branch information
Septias committed Jun 4, 2024
2 parents b0124cb + 6179446 commit d648feb
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 2 deletions.
25 changes: 25 additions & 0 deletions webxdc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,25 @@ type SendOptions =
text: string;
};

/**
* A listener for realtime data.
*/
export class RealtimeListener {
private listener: (data: Uint8Array) => void
private trashed: boolean

/* Whether the realtime channel was left */
is_trashed(): boolean
/* Receive data from the realtime channel */
receive(data: Uint8Array): void
/* Set a listener for the realtime channel */
setListener(listener: (data: Uint8Array) => void): void
/* Send data over the realtime channel */
send(data: Uint8Array): void
/* Leave the realtime channel */
leave(): void
}

interface Webxdc<T> {
/** Returns the peer's own address.
* This is esp. useful if you want to differ between different peers - just send the address along with the payload,
Expand All @@ -82,6 +101,12 @@ interface Webxdc<T> {
cb: (statusUpdate: ReceivedStatusUpdate<T>) => void,
serial?: number
): Promise<void>;

/**
* Join a realtime channel.
*/
joinRealtimeChannel(): RealtimeListener;

/**
* @deprecated See {@link setUpdateListener|`setUpdateListener()`}.
*/
Expand Down
65 changes: 63 additions & 2 deletions webxdc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,59 @@
// browsers. In an actual webxdc environment (e.g. Delta Chat messenger) this
// file is not used and will automatically be replaced with a real one.
// See https://docs.webxdc.org/spec.html#webxdc-api
let ephemeralUpdateKey = "__xdcEphemeralUpdateKey__";

/**
* @typedef {import('./webxdc.d.ts').RealtimeListener} RT
* @type {RT}
*/
class RealtimeListener {
constructor() {
this.listener = null;
this.trashed = false;
}

is_trashed() {
return this.trashed;
}

receive(data) {
if (this.trashed) {
throw new Error("realtime listener is trashed and can no longer be used");
}
if (this.listener) {
this.listener(data);
}
}

setListener(listener) {
this.listener = listener;
}

send(data) {
if (!data instanceof Uint8Array) {
throw new Error("realtime listener data must be a Uint8Array");
}
window.localStorage.setItem(
ephemeralUpdateKey,
JSON.stringify([window.webxdc.selfAddr, Array.from(data), Date.now()]) // Date.now() is needed to trigger the event
);
}

leave() {
this.trashed = true;
}
}

// debug friend: document.writeln(JSON.stringify(value));
//@ts-check
/** @type {import('./webxdc').Webxdc<any>} */
window.webxdc = (() => {
var updateListener = (_) => {};
/**
* @type {RT | null}
*/
var realtimeListener = null;
var updatesKey = "__xdcUpdatesKey__";
window.addEventListener("storage", (event) => {
if (event.key == null) {
Expand All @@ -20,6 +67,11 @@ window.webxdc = (() => {
update.max_serial = updates.length;
console.log("[Webxdc] " + JSON.stringify(update));
updateListener(update);
} else if (event.key === ephemeralUpdateKey) {
var [sender, update] = JSON.parse(event.newValue);
if (window.webxdc.selfAddr !== sender && realtimeListener && !realtimeListener.is_trashed()) {
realtimeListener.receive( Uint8Array.from(update));
}
}
});

Expand All @@ -44,6 +96,15 @@ window.webxdc = (() => {
updateListener = cb;
return Promise.resolve();
},
joinRealtimeChannel: (cb) => {
if (realtimeListener && realtimeListener.is_trashed()) {
return;
}
rt = new RealtimeListener();
// mimic connection establishment time
setTimeout(() => realtimeListener = rt, 500);
return rt;
},
getAllUpdates: () => {
console.log("[Webxdc] WARNING: getAllUpdates() is deprecated.");
return Promise.resolve([]);
Expand Down Expand Up @@ -245,8 +306,8 @@ window.alterXdcApp = () => {
root.innerHTML =
'<img src="' + name + '" style="' + styleAppIcon + '">';
controlPanel.insertBefore(root.firstChild, controlPanel.childNodes[1]);
var pageIcon = document.createElement('link');

var pageIcon = document.createElement("link");
pageIcon.rel = "icon";
pageIcon.href = name;
document.head.append(pageIcon);
Expand Down

0 comments on commit d648feb

Please sign in to comment.