diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte
index ea6a3f0..0c114d8 100644
--- a/frontend/src/App.svelte
+++ b/frontend/src/App.svelte
@@ -14,19 +14,19 @@
import {
Button,
Card,
- SegmentedButtonContainer,
- SegmentedButtonItem,
+ CircularProgressIndeterminate,
StyleFromScheme,
TextField,
} from "m3-svelte";
- // note: even though we import firebase, due to the tree shaking, it will only run if we use "auth" so if ADRIFT_DEV is set it won't import
- // import { auth } from "firebase-config";
- import { signInWithEmailAndPassword } from "firebase/auth";
+
+ import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
import { getDatabase, onValue, ref, set } from "firebase/database";
import type { Transport } from "protocol";
- import { Win, openWindow } from "../../corium";
+ import Proxy from "./Proxy.svelte";
+ import { initializeApp } from "firebase/app";
+ import TrackerList from "tracker-list";
let transport: Transport;
let rtctransport: RTCTransport | undefined;
@@ -34,26 +34,7 @@
let email = "test@test.com";
let password = "123456";
- let ready = false;
-
- let selectedProxy = "ultraviolet";
-
- let url: string = "http://google.com";
- let proxyIframe: HTMLIFrameElement;
-
- let rtcState = "";
-
- if (import.meta.env.VITE_ADRIFT_DEV) {
- console.log(
- "%cADRIFT RUNNING IN DEVELOPMENT MODE",
- "background: blue; color: white; font-size: x-large"
- );
- } else {
- console.log(
- "%cADRIFT RUNNING IN PRODUCTION MODE",
- "background: blue; color: white; font-size: x-large"
- );
- }
+ let connectionState = "";
if (!import.meta.env.VITE_ADRIFT_SINGLEFILE) {
console.log("registering bare-client-custom");
@@ -67,7 +48,7 @@
let bare = new AdriftBareClient(connection);
console.log(setBareClientImplementation);
setBareClientImplementation(bare);
- ready = true;
+ state = ReadyState.Connected;
}
function onTransportClose() {
@@ -79,31 +60,41 @@
onTransportOpen,
onTransportClose,
() => {
- rtcState = `Connection ${transport.peer.connectionState}`;
+ connectionState = `Connection ${transport.peer.connectionState}`;
},
() => {
- rtcState = `Signaling ${transport.peer.connectionState}`;
+ connectionState = `Signaling ${transport.peer.connectionState}`;
},
() => {
- rtcState = `Gathering ${transport.peer.connectionState}`;
+ connectionState = `Gathering ${transport.peer.connectionState}`;
}
);
return transport;
}
- async function connectFirebase() {
+ async function initFirebase() {
+ let tracker = TrackerList["us-central-1"];
+ initializeApp(tracker.firebase);
+ }
+
+ async function connectAccount() {
+ await initFirebase();
rtctransport = transport = createRTCTransport();
+ let auth = getAuth();
let creds = await signInWithEmailAndPassword(auth, email, password);
+ state = ReadyState.Connecting;
const db = getDatabase();
let peer = ref(db, `/peers/${creds.user.uid}`);
let offer = await rtctransport.createOffer();
+ connectionState = "Finding your node...";
+
set(peer, JSON.stringify(offer));
- onValue(peer, (snapshot) => {
+ onValue(peer, async (snapshot) => {
const str = snapshot.val();
if (str) {
console.log(str);
@@ -112,6 +103,10 @@
if (data && data.answer && data.candidates) {
set(peer, null);
const { answer, candidates } = data;
+ connectionState = "Linking to node...";
+ await new Promise((r) => {
+ setTimeout(r, 500);
+ });
rtctransport?.answer(answer, candidates);
}
}
@@ -119,10 +114,20 @@
}
async function connectSwarm() {
+ await initFirebase();
+
+ state = ReadyState.Connecting;
+
rtctransport = transport = createRTCTransport();
let offer = await rtctransport.createOffer();
+ connectionState = "Routing you to an available node...";
+
let answer = await SignalFirebase.signalSwarm(JSON.stringify(offer));
+ connectionState = "Linking to node...";
+ await new Promise((r) => {
+ setTimeout(r, 500);
+ });
rtctransport.answer(answer.answer, answer.candidates);
}
@@ -151,36 +156,6 @@
);
}
- function visitURL(url: string) {
- if (!import.meta.env.VITE_ADRIFT_SINGLEFILE) {
- let path =
- selectedProxy == "dynamic"
- ? `/service/route?url=${url}`
- : `${__uv$config.prefix}${__uv$config.encodeUrl(url)}`;
-
- proxyIframe.src = path;
- } else {
- let bare = new BareClient();
- openWindow(
- new Request(url),
- "_self",
- proxyIframe.contentWindow! as unknown as Win,
- bare as any,
- "replace"
- );
- }
- }
- function frameLoad() {
- if (!import.meta.env.VITE_ADRIFT_SINGLEFILE) {
- const location = proxyIframe.contentDocument?.location.href;
- if (location && location != "about:blank") {
- url = __uv$config.decodeUrl(
- proxyIframe.contentDocument?.location.href.replace(/.*\//g, "")
- );
- }
- }
- }
-
(window as any).bare = new BareClient();
(window as any).myWsTest = () => {
// const url = "wss://ws.postman-echo.com/raw";
@@ -194,42 +169,22 @@
ws.addEventListener("close", (e) => console.log("close listener", e));
ws.onmessage = (e) => console.log("message", e);
};
+
+ enum ReadyState {
+ Idle,
+ Connecting,
+ Connected,
+ }
+ let state = ReadyState.Idle;
-{#if ready}
-
+{#if state == ReadyState.Connected}
+
+{:else if state == ReadyState.Connecting}
+
+
+ {connectionState}
+
{:else if !import.meta.env.VITE_ADRIFT_DEV}
@@ -247,15 +202,15 @@
extraOptions={{ type: "password" }}
/>
-
+
+
-
-
- {rtcState}
-
{:else}
@@ -269,15 +224,7 @@
-
-
-
-
- {rtcState}
-
diff --git a/frontend/src/Proxy.svelte b/frontend/src/Proxy.svelte
new file mode 100644
index 0000000..7de9f21
--- /dev/null
+++ b/frontend/src/Proxy.svelte
@@ -0,0 +1,76 @@
+
+
+
diff --git a/frontend/src/entry.ts b/frontend/src/entry.ts
index 830daaa..d7e8ce1 100644
--- a/frontend/src/entry.ts
+++ b/frontend/src/entry.ts
@@ -1,5 +1,16 @@
import App from "./App.svelte";
import "./index.css";
+if (import.meta.env.VITE_ADRIFT_DEV) {
+ console.log(
+ "%cADRIFT RUNNING IN DEVELOPMENT MODE",
+ "background: blue; color: white; font-size: x-large"
+ );
+} else {
+ console.log(
+ "%cADRIFT RUNNING IN PRODUCTION MODE",
+ "background: blue; color: white; font-size: x-large"
+ );
+}
const app = new App({
target: document.getElementById("app")!,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 368d477..3aa251f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -286,12 +286,6 @@ importers:
specifier: ^5.0.1
version: 5.0.1(webpack@5.75.0)
- firebase-config:
- dependencies:
- firebase:
- specifier: ^10.1.0
- version: 10.1.0(react-native@0.72.3)
-
frontend:
dependencies:
'@rollup/browser':
@@ -321,9 +315,6 @@ importers:
firebase:
specifier: ^10.1.0
version: 10.1.0(react-native@0.72.3)
- firebase-config:
- specifier: workspace:*
- version: link:../firebase-config
m3-svelte:
specifier: ^2.0.3
version: 2.0.3
@@ -345,6 +336,9 @@ importers:
tailwindcss:
specifier: ^3.3.3
version: 3.3.3
+ tracker-list:
+ specifier: workspace:*
+ version: link:../tracker-list
typescript:
specifier: ^5.1.6
version: 5.1.6
@@ -377,9 +371,6 @@ importers:
firebase:
specifier: ^10.1.0
version: 10.1.0(react-native@0.72.3)
- firebase-config:
- specifier: workspace:*
- version: link:../firebase-config
ipaddr.js:
specifier: ^2.1.0
version: 2.1.0
@@ -389,6 +380,9 @@ importers:
protocol:
specifier: workspace:*
version: link:../protocol
+ tracker-list:
+ specifier: workspace:*
+ version: link:../tracker-list
ts-node:
specifier: ^10.9.1
version: 10.9.1(@types/node@20.4.10)(typescript@5.1.6)
@@ -435,9 +429,9 @@ importers:
firebase-admin:
specifier: ^11.10.1
version: 11.10.1
- firebase-config:
+ tracker-list:
specifier: workspace:*
- version: link:../firebase-config
+ version: link:../tracker-list
ts-node:
specifier: ^10.9.1
version: 10.9.1(@types/node@20.4.10)(typescript@5.1.6)
@@ -464,6 +458,8 @@ importers:
specifier: ^3.0.1
version: 3.0.1
+ tracker-list: {}
+
packages:
/@aashutoshrathi/word-wrap@1.2.6:
diff --git a/server/src/cli.ts b/server/src/cli.ts
index e69de29..6376c9f 100644
--- a/server/src/cli.ts
+++ b/server/src/cli.ts
@@ -0,0 +1,30 @@
+
+import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
+
+
+import { getDatabase, onValue, ref, set } from "firebase/database";
+import { answerRtc } from "./rtc";
+
+async function connectFirebase() {
+ let creds = await signInWithEmailAndPassword(getAuth(), "test@test.com", "123456");
+
+ const db = getDatabase();
+ let peer = ref(db, `/peers/${creds.user.uid}`);
+
+ set(peer, "");
+
+ onValue(peer, (snapshot) => {
+ const str = snapshot.val();
+
+ if (str) {
+ let data = JSON.parse(str);
+ if (data && data.offer && data.localCandidates) {
+ answerRtc(data, (answer) => {
+ console.log("answering");
+ set(peer, JSON.stringify(answer));
+ });
+ }
+ }
+ });
+}
+connectFirebase();
\ No newline at end of file
diff --git a/server/src/main.ts b/server/src/main.ts
index 4a2eb9d..41137a8 100644
--- a/server/src/main.ts
+++ b/server/src/main.ts
@@ -2,72 +2,13 @@ import dotenv from "dotenv";
import express from "express";
import expressWs from "express-ws";
-import { signInWithEmailAndPassword } from "firebase/auth";
-import wrtc from "wrtc";
-
-
-import { getDatabase, onValue, ref, set } from "firebase/database";
-import { AdriftServer } from "./server";
+import { AdriftServer, connectTracker } from "./server";
import WebSocket from "isomorphic-ws";
-const configuration = {
- iceServers: [
- {
- urls: "stun:stun.l.google.com:19302",
- },
- ],
-};
+import { answerRtc, bufferToArrayBuffer, connect } from "./rtc";
+
dotenv.config();
-async function connect(
- offer: RTCSessionDescriptionInit,
- candidates: RTCIceCandidateInit[],
- onAnswer: (answer: Record) => void
-): Promise {
- const localCandidates: any[] = [];
- let dataChannel;
- const peer: RTCPeerConnection = new wrtc.RTCPeerConnection(configuration);
- let promise = new Promise((resolve) => {
- peer.ondatachannel = (event) => {
- dataChannel = event.channel;
- resolve(dataChannel);
- };
- });
- peer.onconnectionstatechange = () => {
- console.log("Connection state:", peer.connectionState);
- };
- peer.onsignalingstatechange = () => {
- console.log("Signaling state:", peer.signalingState);
- };
- peer.oniceconnectionstatechange = () => {
- console.log("ICE connection state:", peer.iceConnectionState);
- };
- peer.onicegatheringstatechange = () => {
- console.log("ICE gathering state:", peer.iceGatheringState);
- };
- peer.onicecandidate = (event: any) => {
- console.log("onicecandidate");
- if (event.candidate) {
- localCandidates.push(event.candidate);
- return;
- }
- let payload = {
- answer: peer.localDescription,
- candidates: localCandidates,
- };
- onAnswer(payload);
- };
- await peer.setRemoteDescription(offer);
- let answer = await peer.createAnswer();
- await peer.setLocalDescription(answer);
- for (let candidate of candidates) {
- if (!candidate.candidate) continue;
- console.log({ candidate });
- await peer.addIceCandidate(candidate);
- }
-
- return promise as any;
-}
const app = express() as unknown as expressWs.Application;
expressWs(app);
@@ -82,48 +23,8 @@ app.use((_req, res, next) => {
next();
});
-function bufferToArrayBuffer(buf: Buffer): ArrayBuffer {
- return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
-}
-async function answerRtc(data: any, onrespond: (answer: any) => void) {
- if (data && data.offer && data.localCandidates) {
- const { offer, localCandidates } = data;
- let didAnswer = false;
- let dataChannel = await connect(offer, localCandidates, (answer) => {
- if (!didAnswer) {
- didAnswer = true;
- onrespond(answer);
- // res.json(answer);
- }
- });
- dataChannel.binaryType = "arraybuffer";
-
- let server: AdriftServer;
-
- dataChannel.onopen = () => {
- console.log("opened");
- server = new AdriftServer((msg) => dataChannel.send(msg));
- };
- dataChannel.onclose = () => {
- console.log("closed");
- server.onClose();
- };
- dataChannel.onmessage = (event) => {
- console.log("messaged");
- if (event.data instanceof ArrayBuffer) {
- server.onMsg(event.data);
- return;
- }
- if (event.data instanceof Buffer) {
- server.onMsg(bufferToArrayBuffer(event.data));
- return;
- }
- throw new Error("Unexpected datachannel message type");
- };
- }
-}
app.post("/connect", (req, res) => {
const data = req.body;
@@ -149,42 +50,12 @@ app.ws("/dev-ws", (ws, _req) => {
});
});
-async function connectFirebase() {
- let creds = await signInWithEmailAndPassword(auth, "test@test.com", "123456");
+try {
- const db = getDatabase();
- let peer = ref(db, `/peers/${creds.user.uid}`);
+ let tracker = new WebSocket("ws://localhost:17776/join");
+ connectTracker(tracker);
+} catch (_) {
- set(peer, "");
-
- onValue(peer, (snapshot) => {
- const str = snapshot.val();
-
- if (str) {
- let data = JSON.parse(str);
- if (data && data.offer && data.localCandidates) {
- answerRtc(data, (answer) => {
- console.log("answering");
- set(peer, JSON.stringify(answer));
- });
- }
- }
- });
}
-connectFirebase();
-
-let tracker = new WebSocket("ws://localhost:17776/join");
-tracker.on("message", (str: string) => {
- if (!str) return;
- let data = JSON.parse(str);
- if (!(data && data.offer && data.localCandidates)) return;
- console.log("got offer");
-
- answerRtc(data, (answer) => {
- console.log("have an answer");
- tracker.send(JSON.stringify(answer));
- })
-
-});
app.listen(3000, () => console.log("listening"));
diff --git a/server/src/rtc.ts b/server/src/rtc.ts
index e69de29..3b16fdf 100644
--- a/server/src/rtc.ts
+++ b/server/src/rtc.ts
@@ -0,0 +1,100 @@
+const configuration = {
+ iceServers: [
+ {
+ urls: "stun:stun.l.google.com:19302",
+ },
+ ],
+};
+import wrtc from "wrtc";
+import { AdriftServer } from "./server";
+
+export async function connect(
+ offer: RTCSessionDescriptionInit,
+ candidates: RTCIceCandidateInit[],
+ onAnswer: (answer: Record) => void
+): Promise {
+ const localCandidates: any[] = [];
+ let dataChannel;
+ const peer: RTCPeerConnection = new wrtc.RTCPeerConnection(configuration);
+ let promise = new Promise((resolve) => {
+ peer.ondatachannel = (event) => {
+ dataChannel = event.channel;
+ resolve(dataChannel);
+ };
+ });
+ peer.onconnectionstatechange = () => {
+ console.log("Connection state:", peer.connectionState);
+ };
+ peer.onsignalingstatechange = () => {
+ console.log("Signaling state:", peer.signalingState);
+ };
+ peer.oniceconnectionstatechange = () => {
+ console.log("ICE connection state:", peer.iceConnectionState);
+ };
+ peer.onicegatheringstatechange = () => {
+ console.log("ICE gathering state:", peer.iceGatheringState);
+ };
+ peer.onicecandidate = (event: any) => {
+ console.log("onicecandidate");
+ if (event.candidate) {
+ localCandidates.push(event.candidate);
+ return;
+ }
+ let payload = {
+ answer: peer.localDescription,
+ candidates: localCandidates,
+ };
+ onAnswer(payload);
+ };
+ await peer.setRemoteDescription(offer);
+ let answer = await peer.createAnswer();
+ await peer.setLocalDescription(answer);
+ for (let candidate of candidates) {
+ if (!candidate.candidate) continue;
+ console.log({ candidate });
+ await peer.addIceCandidate(candidate);
+ }
+
+ return promise as any;
+}
+export async function answerRtc(data: any, onrespond: (answer: any) => void) {
+ if (data && data.offer && data.localCandidates) {
+ const { offer, localCandidates } = data;
+ let didAnswer = false;
+
+ let dataChannel = await connect(offer, localCandidates, (answer) => {
+ if (!didAnswer) {
+ didAnswer = true;
+ onrespond(answer);
+ // res.json(answer);
+ }
+ });
+ dataChannel.binaryType = "arraybuffer";
+
+ let server: AdriftServer;
+
+ dataChannel.onopen = () => {
+ console.log("opened");
+ server = new AdriftServer((msg) => dataChannel.send(msg));
+ };
+ dataChannel.onclose = () => {
+ console.log("closed");
+ server.onClose();
+ };
+ dataChannel.onmessage = (event) => {
+ console.log("messaged");
+ if (event.data instanceof ArrayBuffer) {
+ server.onMsg(event.data);
+ return;
+ }
+ if (event.data instanceof Buffer) {
+ server.onMsg(bufferToArrayBuffer(event.data));
+ return;
+ }
+ throw new Error("Unexpected datachannel message type");
+ };
+ }
+}
+export function bufferToArrayBuffer(buf: Buffer): ArrayBuffer {
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
+}
diff --git a/server/src/server.ts b/server/src/server.ts
index 45c73eb..7ded816 100644
--- a/server/src/server.ts
+++ b/server/src/server.ts
@@ -14,6 +14,8 @@ import {
} from "protocol";
import { Readable, Writable } from "stream";
import { BareError, bareInitialFetch, fetchResponse, options } from "./http";
+import { answerRtc } from "./rtc";
+
function bareErrorToResponse(e: BareError): {
payload: HTTPResponsePayload;
@@ -369,3 +371,17 @@ export class AdriftServer {
this.events.emit("close");
}
}
+
+export function connectTracker(tracker: WebSocket) {
+ tracker.on("message", (str: string) => {
+ if (!str) return;
+ let data = JSON.parse(str);
+ if (!(data && data.offer && data.localCandidates)) return;
+ console.log("got offer");
+
+ answerRtc(data, (answer) => {
+ console.log("have an answer");
+ tracker.send(JSON.stringify(answer));
+ })
+ });
+}
\ No newline at end of file
diff --git a/server/tsconfig.json b/server/tsconfig.json
index b04c3f5..96a252f 100644
--- a/server/tsconfig.json
+++ b/server/tsconfig.json
@@ -12,7 +12,7 @@
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
- "noUnusedLocals": true,
+ "noUnusedLocals": false,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,