adrift/frontend/src/App.svelte
2023-08-15 21:07:49 -04:00

345 lines
9.2 KiB
Svelte

<script lang="ts">
import {
BareClient,
registerRemoteListener,
setBareClientImplementation,
} from "bare-client-custom";
import {
AdriftBareClient,
Connection,
DevWsTransport,
RTCTransport,
SignalFirebase,
} from "client";
import {
Button,
Card,
CircularProgressIndeterminate,
StyleFromScheme,
TextField,
} from "m3-svelte";
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
import { getDatabase, onValue, ref, set } from "firebase/database";
import type { Transport } from "protocol";
import Proxy from "./Proxy.svelte";
import { initializeApp } from "firebase/app";
import TrackerList from "tracker-list";
let transport: Transport;
let rtctransport: RTCTransport | undefined;
let email = "test@test.com";
let password = "123456";
let connectionState = "";
if (!import.meta.env.VITE_ADRIFT_SINGLEFILE) {
console.log("registering bare-client-custom");
registerRemoteListener();
}
function onTransportOpen() {
console.log("Transport opened");
let connection = new Connection(transport);
let bare = new AdriftBareClient(connection);
console.log(setBareClientImplementation);
setBareClientImplementation(bare);
state = ReadyState.Connected;
}
function onTransportClose() {
console.warn("Transport closed");
}
function createRTCTransport() {
let transport = new RTCTransport(
onTransportOpen,
onTransportClose,
() => {
connectionState = `Connection ${transport.peer.connectionState}`;
},
() => {
connectionState = `Signaling ${transport.peer.connectionState}`;
},
() => {
connectionState = `Gathering ${transport.peer.connectionState}`;
}
);
return transport;
}
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, async (snapshot) => {
const str = snapshot.val();
if (str) {
console.log(str);
let data = JSON.parse(str);
console.log(data);
if (data && data.answer && data.candidates) {
set(peer, null);
const { answer, candidates } = data;
connectionState = "Linking to node...";
await new Promise((r) => {
setTimeout(r, 1000);
});
rtctransport?.answer(answer, candidates);
}
}
});
}
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);
}
async function connectDevHttp() {
rtctransport = transport = createRTCTransport();
let offer = await rtctransport.createOffer();
console.log("offer created", offer);
console.log(JSON.stringify(offer));
const r = await fetch("http://localhost:3000/connect", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(offer),
});
if (r.status != 200) {
throw new Error("connect: " + r.status + " " + r.statusText);
}
const { answer, candidates } = await r.json();
await rtctransport.answer(answer, candidates);
}
async function connectDevWS() {
transport = new DevWsTransport(onTransportOpen, () =>
console.log("onclose")
);
}
(window as any).bare = new BareClient();
(window as any).myWsTest = () => {
// const url = "wss://ws.postman-echo.com/raw";
const url = "ws://127.0.0.1:3002/";
const ws = ((window as any).ws = (
(window as any).bare as BareClient
).createWebSocket(url, ["a", "b"], {}));
ws.onopen = () => console.log("onopen");
ws.addEventListener("open", () => console.log("open listener"));
ws.onclose = () => console.error(new Error("onclose"));
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;
</script>
{#if state == ReadyState.Connected}
<Proxy />
{:else if state == ReadyState.Connecting}
<CircularProgressIndeterminate />
<h2>
{connectionState}
</h2>
{:else if !import.meta.env.VITE_ADRIFT_DEV}
<div id="loginpage">
<div class="bigcard">
<h1>Adrift</h1>
</div>
<div class="flex justify-evenly">
<Card type="filled">basically aero 2</Card>
<div />
<Card type="elevated">
<TextField name="email" bind:value={email} />
<TextField
name="password"
bind:value={password}
extraOptions={{ type: "password" }}
/>
<Button type="outlined" on:click={connectAccount}
>Connect with firebase</Button
>
<Button type="filled" on:click={connectSwarm}
>Connect with the swarm (firebase, webrtc, insecure)
</Button>
</Card>
</div>
</div>
{:else}
<div class="flex items-center justify-center h-full">
<Card type="elevated">
<div class="flex flex-col h-full">
<h2 class="m3-font-headline-large m-3">Adrift DEV</h2>
<div class="flex space-evenly pad-children">
<Button type="filled" on:click={connectDevHttp}
>Connect with WebRTC transport over localhost HTTP signaling</Button
>
<Button type="filled" on:click={connectDevWS}
>Connect with localhost websocket transport</Button
>
</div>
</div>
</Card>
</div>
{/if}
<StyleFromScheme
lightScheme={{
primary: 1284831119,
onPrimary: 4294967295,
primaryContainer: 4293516799,
onPrimaryContainer: 4280291399,
inversePrimary: 4291804670,
secondary: 4284636017,
onSecondary: 4294967295,
secondaryContainer: 4293451512,
onSecondaryContainer: 4280162603,
tertiary: 4286468704,
onTertiary: 4294967295,
tertiaryContainer: 4294957539,
onTertiaryContainer: 4281405469,
error: 4290386458,
onError: 4294967295,
errorContainer: 4294957782,
onErrorContainer: 4282449922,
background: 4294834175,
onBackground: 4280097568,
surface: 4294834175,
onSurface: 4280097568,
surfaceVariant: 4293386475,
onSurfaceVariant: 4282991950,
inverseSurface: 4281478965,
inverseOnSurface: 4294307831,
outline: 4286215551,
outlineVariant: 4291478735,
shadow: 4278190080,
scrim: 4278190080,
surfaceDim: 4292794592,
surfaceBright: 4294834175,
surfaceContainerLowest: 4294967295,
surfaceContainerLow: 4294505210,
surfaceContainer: 4294110452,
surfaceContainerHigh: 4293715694,
surfaceContainerHighest: 4293320937,
surfaceTint: 4284831119,
}}
darkScheme={{
primary: 1291804670,
onPrimary: 4281739101,
primaryContainer: 4283252085,
onPrimaryContainer: 4293516799,
inversePrimary: 4284831119,
secondary: 4291543771,
onSecondary: 4281544001,
secondaryContainer: 4283057240,
onSecondaryContainer: 4293451512,
tertiary: 4293900488,
onTertiary: 4283049266,
tertiaryContainer: 4284693320,
onTertiaryContainer: 4294957539,
error: 4294948011,
onError: 4285071365,
errorContainer: 4287823882,
onErrorContainer: 4294957782,
background: 4279505432,
onBackground: 4293320937,
surface: 4279505432,
onSurface: 4293320937,
surfaceVariant: 4282991950,
onSurfaceVariant: 4291478735,
inverseSurface: 4293320937,
inverseOnSurface: 4281478965,
outline: 4287926169,
outlineVariant: 4282991950,
shadow: 4278190080,
scrim: 4278190080,
surfaceDim: 4279505432,
surfaceBright: 4282071102,
surfaceContainerLowest: 4279176467,
surfaceContainerLow: 4280097568,
surfaceContainer: 4280360740,
surfaceContainerHigh: 4281018671,
surfaceContainerHighest: 4281742394,
surfaceTint: 4291804670,
}}
/>
<style>
:global(.pad-children > *) {
margin: 2rem;
}
#loginpage {
padding: 2.5em;
}
.bigcard {
background-color: rgb(var(--m3-scheme-primary-container));
color: rgb(var(--m3-scheme-on-primary-container));
border-radius: 2rem;
display: flex;
flex-direction: column;
gap: 2rem;
text-align: center;
padding: 8rem 0 6rem 0;
margin-bottom: 2rem;
}
:global(body, html, #app) {
width: 100vw;
height: 100vh;
padding: 0;
margin: 0;
background-color: rgb(var(--m3-scheme-background));
color: rgb(var(--m3-scheme-on-background));
}
iframe {
outline: none;
border: none;
}
</style>