Skip to content

Commit 20ae451

Browse files
committed
bits
1 parent 38d2fdc commit 20ae451

File tree

5 files changed

+873
-48
lines changed

5 files changed

+873
-48
lines changed

package-lock.json

Lines changed: 37 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/labs/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
}
8484
},
8585
"dependencies": {
86+
"@automerge/vanillajs": "^2.5.0",
8687
"@codemirror/lang-javascript": "^6.2.3",
8788
"@codemirror/view": "^6.36.5",
8889
"@dimforge/rapier2d": "^0.15.0",
@@ -119,4 +120,4 @@
119120
"mitata": "^1.0.34",
120121
"typescript": "^5.8.2"
121122
}
122-
}
123+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import type { Message as AutomergeMessage, PeerId } from '@automerge/vanillajs';
2+
import { NetworkAdapter } from '@automerge/vanillajs';
3+
import { QRTPC } from './QRTP-C';
4+
5+
/**
6+
* Network adapter that syncs Automerge documents over QR codes using QRTPC
7+
*/
8+
export class AutomergeQRNetwork extends NetworkAdapter {
9+
#sender: QRTPC;
10+
#receiver: QRTPC;
11+
#senderIterator: AsyncIterableIterator<string> | null = null;
12+
#isReady = false;
13+
#whenReadyResolve?: () => void;
14+
#whenReadyPromise: Promise<void>;
15+
16+
// QR Update Callback
17+
#onQRUpdateCallback?: (qrData: string) => void;
18+
19+
constructor() {
20+
super();
21+
this.#sender = new QRTPC();
22+
this.#receiver = new QRTPC();
23+
24+
// Setup whenReady promise
25+
this.#whenReadyPromise = new Promise<void>((resolve) => {
26+
this.#whenReadyResolve = resolve;
27+
});
28+
}
29+
30+
isReady(): boolean {
31+
return this.#isReady;
32+
}
33+
34+
whenReady(): Promise<void> {
35+
return this.#whenReadyPromise;
36+
}
37+
38+
/**
39+
* Set callback for QR code updates (for rendering)
40+
*/
41+
onQRUpdate(callback: (qrData: string) => void) {
42+
this.#onQRUpdateCallback = callback;
43+
}
44+
45+
/**
46+
* Process incoming QR code data from camera
47+
*/
48+
receiveQRCode(qrData: string): boolean {
49+
try {
50+
const progress = this.#receiver.receive(qrData);
51+
52+
if (progress.complete && progress.data) {
53+
// Parse the received message
54+
const message = JSON.parse(progress.data) as AutomergeMessage;
55+
56+
// Emit message event for Automerge
57+
this.emit('message', message);
58+
59+
// Reset receiver for next message
60+
this.#receiver.reset();
61+
62+
return true;
63+
}
64+
65+
return false;
66+
} catch (error) {
67+
console.error('Error receiving QR code:', error);
68+
return false;
69+
}
70+
}
71+
72+
// NetworkAdapter interface implementation
73+
connect(peerId: PeerId, peerMetadata?: Record<string, any>) {
74+
this.peerId = peerId;
75+
this.peerMetadata = peerMetadata;
76+
this.#isReady = true;
77+
78+
// Resolve whenReady promise
79+
if (this.#whenReadyResolve) {
80+
this.#whenReadyResolve();
81+
}
82+
83+
// Simulate discovering a peer (in QR sync, we assume both devices are "connected")
84+
// Use a fixed peer ID for the "other" device
85+
const otherPeerId = 'qr-peer' as PeerId;
86+
this.emit('peer-candidate', { peerId: otherPeerId, peerMetadata: {} });
87+
}
88+
89+
disconnect() {
90+
this.#isReady = false;
91+
this.#senderIterator = null;
92+
}
93+
94+
send(message: AutomergeMessage) {
95+
if (!this.#isReady) return;
96+
97+
// Serialize the message
98+
const messageJson = JSON.stringify(message);
99+
100+
// Start sending through QRTPC
101+
this.#startSending(messageJson);
102+
}
103+
104+
async #startSending(data: string) {
105+
// Stop previous sending
106+
this.#senderIterator = null;
107+
108+
// Start new sending iterator
109+
this.#senderIterator = this.#sender.send(data, {
110+
blockSize: 400,
111+
frameRate: 20,
112+
});
113+
114+
// Start the sending loop
115+
this.#sendNextBlock();
116+
}
117+
118+
async #sendNextBlock() {
119+
if (!this.#senderIterator) return;
120+
121+
try {
122+
const result = await this.#senderIterator.next();
123+
if (!result.done && result.value) {
124+
// Notify callback with new QR data
125+
if (this.#onQRUpdateCallback) {
126+
this.#onQRUpdateCallback(result.value);
127+
}
128+
129+
// Schedule next block
130+
setTimeout(() => this.#sendNextBlock(), 0);
131+
}
132+
} catch (error) {
133+
console.error('Sending error:', error);
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)