- Rust axum signaling server with WebSocket support - Lit + TypeScript frontend with Vite - Redis session storage with TTL - WebRTC transport and crypto client stubs - Phase1 architecture plan in plans/ - Deploy directory structure prepared
71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
export class WebRTCTransport {
|
|
private pc: RTCPeerConnection | null = null;
|
|
private dc: RTCDataChannel | null = null;
|
|
private iceServers: RTCIceServer[];
|
|
|
|
constructor(iceServers: RTCIceServer[]) {
|
|
this.iceServers = iceServers;
|
|
}
|
|
|
|
async createOffer(): Promise<{ sdp: string; candidates: RTCIceCandidate[] }> {
|
|
this.pc = new RTCPeerConnection({ iceServers: this.iceServers });
|
|
this.dc = this.pc.createDataChannel('filedrop', { ordered: true });
|
|
|
|
const offer = await this.pc.createOffer();
|
|
await this.pc.setLocalDescription(offer);
|
|
|
|
const candidates = await this.waitForIceGathering();
|
|
return {
|
|
sdp: this.pc.localDescription?.sdp || '',
|
|
candidates,
|
|
};
|
|
}
|
|
|
|
async handleAnswer(answer: { sdp: string }) {
|
|
if (!this.pc) return;
|
|
await this.pc.setRemoteDescription(
|
|
new RTCSessionDescription({ type: 'answer', sdp: answer.sdp })
|
|
);
|
|
}
|
|
|
|
async handleCandidate(candidate: RTCIceCandidateInit) {
|
|
await this.pc?.addIceCandidate(candidate);
|
|
}
|
|
|
|
onDataChannel(callback: (dc: RTCDataChannel) => void) {
|
|
if (this.pc) {
|
|
this.pc.ondatachannel = (e) => callback(e.channel);
|
|
}
|
|
}
|
|
|
|
getDataChannel() {
|
|
return this.dc;
|
|
}
|
|
|
|
private waitForIceGathering(): Promise<RTCIceCandidate[]> {
|
|
return new Promise((resolve) => {
|
|
const candidates: RTCIceCandidate[] = [];
|
|
if (!this.pc) return resolve(candidates);
|
|
|
|
this.pc.onicecandidate = (e) => {
|
|
if (e.candidate) candidates.push(e.candidate);
|
|
};
|
|
|
|
this.pc.onicegatheringstatechange = () => {
|
|
if (this.pc?.iceGatheringState === 'complete') {
|
|
resolve(candidates);
|
|
}
|
|
};
|
|
|
|
setTimeout(() => resolve(candidates), 5000);
|
|
});
|
|
}
|
|
|
|
close() {
|
|
this.dc?.close();
|
|
this.pc?.close();
|
|
this.dc = null;
|
|
this.pc = null;
|
|
}
|
|
}
|