a "little" refactoring

This commit is contained in:
Kendell R 2023-09-09 11:17:35 -07:00
parent 95895056ef
commit a6c8804552
No known key found for this signature in database
GPG key ID: 64314E306EEF6109
11 changed files with 585 additions and 617 deletions

View file

@ -1,32 +1,31 @@
import { getDatabase, onValue, ref, set, remove, goOffline } from "firebase/database";
import {
getDatabase,
onValue,
ref,
set,
remove,
goOffline,
} from "firebase/database";
// import "firebase-config";
import { v4 as uuid } from "uuid";
import { Answer } from "./RTCTransport";
import { browserLocalPersistence, getAuth, setPersistence, signInWithEmailAndPassword } from "firebase/auth";
import { getAuth } from "firebase/auth";
export async function signalSwarm(offer: string): Promise<Answer> {
let id = uuid();
const db = getDatabase();
let reff = ref(db, `/swarm/${id}`);
set(reff, offer);
return new Promise((resolve, reject) => {
onValue(reff, (snapshot) => {
const text = snapshot.val();
if (!text)
return;
if (!text) return;
let data = JSON.parse(text);
console.log(data);
console.log("<", data);
if (data.error) {
reject(new Error(data.error));
@ -37,26 +36,18 @@ export async function signalSwarm(offer: string): Promise<Answer> {
resolve(data);
});
});
}
export async function signalAccount(offer: string): Promise<Answer> {
let auth = getAuth();
if (!auth.currentUser)
throw new Error("not signed in");
if (!auth.currentUser) throw new Error("not signed in");
const db = getDatabase();
let peer = ref(db, `/peers/${auth.currentUser!.uid}`);
set(peer, offer);
return new Promise((resolve, reject) => {
onValue(peer, async (snapshot) => {
const str = snapshot.val();
if (str) {
@ -65,9 +56,8 @@ export async function signalAccount(offer: string): Promise<Answer> {
remove(peer);
resolve(data);
goOffline(db);
}
}
});
});
}
}

View file

@ -1,19 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Cabin:wght@400;500;700&display=swap"
/>
<script type="module" src="src/entry.ts"></script>
<script src="uv/uv.bundle.js"></script>
<script src="uv.config.js"></script>
</head>
<head>
<title></title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Cabin">
<script type="module" src="src/entry.ts"></script>
<script src="uv/uv.bundle.js"></script>
<script src="uv.config.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
<body>
<div id="app" class="m3-font-body-large"></div>
</body>
</html>

View file

@ -18,16 +18,17 @@
"@iconify-icons/ic": "^1.2.13",
"@iconify-icons/maki": "^1.2.18",
"@iconify/svelte": "^3.1.4",
"@mercuryworkshop/bare-client-custom": "workspace:*",
"@rollup/browser": "^3.28.0",
"@sveltejs/vite-plugin-svelte": "^2.4.5",
"autoprefixer": "^10.4.15",
"@mercuryworkshop/bare-client-custom": "workspace:*",
"client": "workspace:*",
"corium": "file:../corium",
"esbuild": "^0.19.1",
"esbuild-plugin-inline-import": "^1.0.1",
"firebase": "^10.1.0",
"m3-svelte": "^2.0.3",
"micromatch": "^4.0.5",
"postcss": "^8.4.27",
"postcss-load-config": "^4.0.1",
"protocol": "workspace:*",
@ -37,7 +38,6 @@
"tracker-list": "workspace:*",
"typescript": "^5.1.6",
"uuid": "^9.0.0",
"vite": "^4.4.9",
"vite-plugin-svelte": "^3.0.1"
"vite": "^4.4.9"
}
}

View file

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Before After
Before After

View file

@ -1,9 +0,0 @@
<script lang="ts">
import { Card } from "m3-svelte";
</script>
<div class="h-full w-full p-5">
<Card type="elevated">
<h1>Step 1</h1>
</Card>
</div>

View file

@ -1,165 +1,61 @@
<script lang="ts">
import Icon from "@iconify/svelte";
import { setBareClientImplementation } from "@mercuryworkshop/bare-client-custom";
import {
Button,
Card,
CircularProgressIndeterminate,
StyleFromScheme,
} from "m3-svelte";
import {
AdriftBareClient,
Connection,
DevWsTransport,
RTCTransport,
SignalFirebase,
downloadShortcut,
} from "client";
import {
Button,
Card,
CircularProgressIndeterminate,
Dialog,
RadioAnim3,
SnackbarAnim,
StyleFromScheme,
TextField,
} from "m3-svelte";
import iconDiscord from "@iconify-icons/ic/outline-discord";
import iconGithub from "@iconify-icons/bi/github";
import Icon from "@iconify/svelte";
import type { Transport } from "protocol";
import Proxy from "./Proxy.svelte";
import { initializeApp } from "firebase/app";
import ConnectionCmp from "./Connection.svelte";
import { UIState } from "./state";
import TrackerList from "tracker-list";
import {
browserLocalPersistence,
createUserWithEmailAndPassword,
getAuth,
setPersistence,
signInWithEmailAndPassword,
} from "firebase/auth";
let state = UIState.Idle;
let stateStr = "";
import { getAnalytics } from "firebase/analytics";
let dialogConnection = false;
import logo from "./logo.png";
import AccountCreation from "./AccountCreation.svelte";
import { goOffline } from "firebase/database";
let devTransport: Transport;
async function onOpen() {
console.log("[TRANSPORT DEV] opened");
enum ReadyState {
Idle,
Connecting,
Connected,
AccountCreation,
}
let state = ReadyState.Idle;
let transport: Transport;
let rtctransport: RTCTransport | undefined;
let email = "";
let password = "";
let connectionState = "";
let showSwarmWarning = false;
let showLogin = false;
type TrackerID = keyof typeof TrackerList;
type Tracker = (typeof TrackerList)[TrackerID];
let chosenTracker: TrackerID | undefined;
let showTrackerList = false;
let createaccount = false;
let snackbar: (data: any) => void;
async function onTransportOpen() {
console.log("Transport opened");
let connection = new Connection(transport);
// TODO: error handling here
const connection = new Connection(devTransport);
await connection.initialize();
let bare = new AdriftBareClient(connection);
const bare = new AdriftBareClient(connection);
setBareClientImplementation(bare);
state = ReadyState.Connected;
state = UIState.Connected;
}
function onTransportClose() {
console.warn("Transport closed");
}
function createRTCTransport() {
let transport = new RTCTransport(
onTransportOpen,
onTransportClose,
async function connectDevHttp() {
state = UIState.Connecting;
const transport = new RTCTransport(
onOpen,
() => console.warn("[TRANSPORT] closed"),
() => {
connectionState = `Connection ${transport.peer.connectionState}...`;
stateStr = `Connection ${transport.peer.connectionState}...`;
},
() => {
connectionState = `Signaling ${transport.peer.connectionState}...`;
stateStr = `Signaling ${transport.peer.connectionState}...`;
},
() => {
if (transport.peer.connectionState == "new") {
connectionState = `Creating an offer...`;
stateStr = `Creating an offer...`;
} else {
connectionState = `Gathering ${transport.peer.connectionState}...`;
stateStr = `Gathering ${transport.peer.connectionState}...`;
}
}
);
return transport;
}
async function initFirebase() {
if (!chosenTracker) return;
let tracker = TrackerList[chosenTracker];
let app = initializeApp(tracker.firebase);
getAnalytics(app);
}
async function connectAccount() {
rtctransport = transport = createRTCTransport();
state = ReadyState.Connecting;
let offer = await rtctransport.createOffer();
connectionState = "Finding your node...";
let answer = await SignalFirebase.signalAccount(JSON.stringify(offer));
connectionState = "Linking to node...";
await new Promise((r) => {
setTimeout(r, 1000);
});
rtctransport.answer(answer.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...";
try {
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);
} catch (e) {
console.error(e);
connectionState = e;
}
}
async function connectDevHttp() {
rtctransport = transport = createRTCTransport();
let offer = await rtctransport.createOffer();
console.log("offer created", offer);
console.log(JSON.stringify(offer));
devTransport = transport;
let offer = await transport.createOffer();
console.log("offer", offer);
const r = await fetch("http://localhost:3000/connect", {
method: "POST",
@ -170,394 +66,181 @@
throw new Error("connect: " + r.status + " " + r.statusText);
}
const { answer, candidates } = await r.json();
await rtctransport.answer(answer, candidates);
await transport.answer(answer, candidates);
}
async function connectDevWS() {
transport = new DevWsTransport(onTransportOpen, () =>
console.log("onclose")
state = UIState.Connecting;
devTransport = new DevWsTransport(onOpen, () =>
console.log("[TRANSPORT DEV] closed")
);
}
let trackerstatuses: Partial<Record<TrackerID, object | null>> = {};
for (let id in TrackerList) {
let tracker = TrackerList[id as TrackerID];
trackerstatuses[id as TrackerID] = null;
let url = new URL(`${tracker.tracker}/stats`);
url.protocol = "https://";
fetch(url).then(async (data) => {
trackerstatuses[id as TrackerID] = await data.json();
console.log(trackerstatuses);
});
}
</script>
{#if state == ReadyState.Connected}
<svelte:head>
<title>Adrift</title>
</svelte:head>
{#if state == UIState.Connected}
<Proxy />
{:else if state == ReadyState.Connecting}
<div class="h-full w-full flex justify-center items-center">
{:else if state == UIState.Connecting}
<div class="h-full flex justify-center items-center">
<Card type="outlined">
<div class="flex items-center p-2">
<div class="flex items-center mb-4 gap-4">
<CircularProgressIndeterminate />
<div class="p-5" />
<h2 class="text-xl">
{connectionState}
</h2>
<h2 class="text-xl">{stateStr}</h2>
</div>
<br />
<p class="text-sm opacity-70">
<p class="text-sm text-on-surface-variant">
Adrift is routing you to a server available to take your requests.<br
/>The initial connection may take several minutes depending on server
load
</p>
</Card>
</div>
{:else if !import.meta.env.VITE_ADRIFT_DEV}
<div class="flex flex-col h-full">
<div id="topbar" class="flex justify-between items-center p-4">
<div id="logo">
<Card type="">
<div class="flex items-center text-3xl">
<Icon icon="material-symbols:sailing" />
<p class="text-2xl ml-3">Adrift</p>
</div>
</Card>
</div>
<div id="nav" />
<div id="links">
<Card type="elevated">
<div class="flex">
<a href="https://discord.gg/bAgNyGpXSx">
<Icon icon={iconDiscord} class="icon" />
</a>
<spacer />
<a href="https://github.com/MercuryWorkshop/adrift">
<Icon icon={iconGithub} class="icon" />
</a>
</div>
</Card>
</div>
</div>
<div class="flex flex-col flex-1">
<div class="flex m-4">
<Card
type="elevated"
extraOptions={{ class: "m3-container type-elevated w-9/12" }}
>
<div class="w-full">
<h2 class="text-6xl">Surf the web, Adrift</h2>
<h2 class="text-2xl">
A fast and modern decentralized proxy network
</h2>
</div>
<div class="mt-5 flex justify-between">
<Button type="filled" on:click={() => (showTrackerList = true)}
>Start Browsing</Button
>
{#if !import.meta.env.VITE_ADRIFT_SINGLEFILE}
<Button
type="text"
on:click={() => {
downloadShortcut("adrift.html", "Homework");
}}>Get Shortcut</Button
>
{/if}
</div>
</Card>
</div>
<div
class="flex h-full justify-end m-4 transition-all"
class:opacity-0={!showTrackerList}
>
<Card
type="elevated"
extraOptions={{
class: "m3-container type-elevated w-9/12 flex flex-col",
}}
>
<h2 class="text-4xl">Select a Tracker</h2>
<h2 class="text-1xl">Trackers allow you to connect to Adrift</h2>
<div class="mt-5 space-y-3">
{#each Object.keys(TrackerList) as tracker}
<Card type="outlined">
<label>
<div class="flex items-center">
<svelte:component this={RadioAnim3}>
<input
type="radio"
id={tracker}
name="tabs"
value={tracker}
bind:group={chosenTracker}
/>
</svelte:component>
<p class="ml-3 text-xl">
{tracker}
</p>
</div>
<p>
{TrackerList[tracker].description}
</p>
<p class="opacity-50">
{trackerstatuses[tracker]
? trackerstatuses[tracker]?.members?.length
: "loading"} swarm members
</p>
</label>
</Card>
{/each}
</div>
<div class="flex-1" />
<div class="mt-5 flex">
{#if chosenTracker}
<Button type="elevated" on:click={() => (showSwarmWarning = true)}
>Connect to the swarm</Button
>
<Button
type="filled"
on:click={async () => {
await initFirebase();
let auth = getAuth();
await setPersistence(auth, browserLocalPersistence);
if (!auth.currentUser) {
showLogin = true;
} else {
await connectAccount();
}
}}>Connect with login</Button
>
{/if}
</div>
<Dialog headline="WARNING" bind:open={showSwarmWarning}>
<h2 class="text-2xl">
TLS has not currently been implemented for the Adrift Swarm. It
will later, but until then your data will not be private, and you
should not enter any sensitive information on any page
</h2>
<br />
<Button type="filled" on:click={() => (showLogin = false)}
>Cancel</Button
>
<Button type="outlined" on:click={connectSwarm}
>I understand, Connect</Button
>
</Dialog>
<Dialog headline="Log in to connect" bind:open={showLogin}>
<button
class="text-primary my-3"
on:click={() => ((createaccount = true), (showLogin = false))}
>New here? Create an account</button
>
<br />
<TextField name="email" bind:value={email} />
<TextField
name="password"
bind:value={password}
extraOptions={{ type: "password" }}
/>
<div class="flex mt-5">
<Button type="outlined" on:click={() => (showLogin = false)}
>Cancel</Button
>
<Button
type="filled"
on:click={async () => {
try {
await signInWithEmailAndPassword(
getAuth(),
email,
password
);
connectAccount();
} catch (e) {
snackbar({ message: e, closable: true });
}
}}>Connect</Button
>
</div>
</Dialog>
<Dialog bind:open={createaccount} headline="Create an account">
<TextField name="email" bind:value={email} />
<TextField
name="password"
bind:value={password}
extraOptions={{ type: "password" }}
/>
<p>
Note: to be able to connect, you'll need to download an exit node
and run it on a computer with an uncensored internet connection
</p>
<div class="flex mt-5">
<Button
type="filled"
on:click={async () => {
try {
await createUserWithEmailAndPassword(
getAuth(),
email,
password
);
createaccount = false;
} catch (e) {
snackbar({ message: e, closable: true });
}
}}>Create Account</Button
>
</div></Dialog
>
</Card>
</div>
<div class="flex m-4">
<Card
type="elevated"
extraOptions={{ class: "m3-container type-elevated w-full" }}
>
<div class="flex space-x-10">
<a class="text-1xl" href="https://mercurywork.shop"
>© 2023 Mercury Workshop</a
>
<div class="space-x-3">
<a class="text-1xl" href="https://discord.gg/bAgNyGpXSx"
>discord</a
>
<a class="text-1xl" href="https://github.com/MercuryWorkshop"
>github</a
>
</div>
<div />
</div>
</Card>
</div>
</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>
{:else if import.meta.env.VITE_ADRIFT_DEV}
<div class="h-full flex justify-center items-center">
<Card type="outlined">
<h2 class="m3-font-headline-large mb-4">Adrift DEV</h2>
<div class="flex gap-4">
<Button type="filled" on:click={connectDevHttp}>
Connect with localhost WebRTC transport over HTTP signaling
</Button>
<Button type="filled" on:click={connectDevWS}>
Connect with localhost websocket transport
</Button>
</div>
</Card>
</div>
{:else}
<div class="h-full flex flex-col p-4 gap-6">
<div class="flex items-center text-3xl">
<Icon icon="material-symbols:sailing" />
<p class="text-2xl ml-3">Adrift</p>
</div>
<Card
type="elevated"
extraOptions={{ class: "m3-container type-elevated lg:w-3/4" }}
>
<h2 class="text-6xl">Surf the web, Adrift</h2>
<h2 class="text-2xl">A fast and modern decentralized proxy network</h2>
<div class="mt-6 flex gap-4">
<Button type="filled" on:click={() => (dialogConnection = true)}>
Start browsing
</Button>
{#if !import.meta.env.VITE_ADRIFT_SINGLEFILE}
<Button
type="text"
on:click={() => downloadShortcut("adrift.html", "Homework")}
>
Get shortcut
</Button>
{/if}
</div>
</Card>
<Card
type="elevated"
extraOptions={{ class: "m3-container type-elevated mt-auto" }}
>
<div class="flex gap-8 items-center">
<a class="mr-auto" href="https://mercurywork.shop">
© 2023 Mercury Workshop
</a>
<a href="https://discord.gg/bAgNyGpXSx" class="text-2xl">
<Icon icon="ic:round-discord" />
</a>
<a href="https://github.com/MercuryWorkshop/adrift" class="text-2xl">
<Icon icon="mdi:github" />
</a>
</div>
</Card>
</div>
<ConnectionCmp bind:dialogConnection bind:state bind:stateStr />
{/if}
<svelte:component this={SnackbarAnim} bind:show={snackbar} />
<StyleFromScheme
lightScheme={{
primary: 1284831119,
primary: 4282411062,
onPrimary: 4294967295,
primaryContainer: 4293516799,
onPrimaryContainer: 4280291399,
inversePrimary: 4291804670,
secondary: 4284636017,
primaryContainer: 4290834352,
onPrimaryContainer: 4278198784,
inversePrimary: 4289057685,
secondary: 4283720525,
onSecondary: 4294967295,
secondaryContainer: 4293451512,
onSecondaryContainer: 4280162603,
tertiary: 4286468704,
secondaryContainer: 4292339917,
onSecondaryContainer: 4279377678,
tertiary: 4281886056,
onTertiary: 4294967295,
tertiaryContainer: 4294957539,
onTertiaryContainer: 4281405469,
tertiaryContainer: 4290571246,
onTertiaryContainer: 4278198306,
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,
background: 4294507505,
onBackground: 4279835927,
surface: 4294507505,
onSurface: 4279835927,
surfaceVariant: 4292863191,
onSurfaceVariant: 4282599487,
inverseSurface: 4281217579,
inverseOnSurface: 4293915368,
outline: 4285757806,
outlineVariant: 4291020988,
shadow: 4278190080,
scrim: 4278190080,
surfaceDim: 4292794592,
surfaceBright: 4294834175,
surfaceDim: 4292402130,
surfaceBright: 4294507505,
surfaceContainerLowest: 4294967295,
surfaceContainerLow: 4294505210,
surfaceContainer: 4294110452,
surfaceContainerHigh: 4293715694,
surfaceContainerHighest: 4293320937,
surfaceTint: 4284831119,
surfaceContainerLow: 4294112747,
surfaceContainer: 4293717989,
surfaceContainerHigh: 4293323232,
surfaceContainerHighest: 4292994266,
surfaceTint: 4282411062,
}}
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,
primary: 4294945779,
onPrimary: 4284153947,
primaryContainer: 4291690702,
onPrimaryContainer: 4294967295,
inversePrimary: 4289265833,
secondary: 4294945779,
onSecondary: 4284153947,
secondaryContainer: 4286709890,
onSecondaryContainer: 4294956533,
tertiary: 4294947764,
onTertiary: 4285005846,
tertiaryContainer: 4292294218,
onTertiaryContainer: 4294967295,
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,
background: 4279702038,
onBackground: 4293713893,
surface: 4279702038,
onSurface: 4293713893,
surfaceVariant: 4283319371,
onSurfaceVariant: 4291936971,
inverseSurface: 4293713893,
inverseOnSurface: 4281675315,
outline: 4288318869,
outlineVariant: 4283319371,
shadow: 4278190080,
scrim: 4278190080,
surfaceDim: 4279505432,
surfaceBright: 4282071102,
surfaceContainerLowest: 4279176467,
surfaceContainerLow: 4280097568,
surfaceContainer: 4280360740,
surfaceContainerHigh: 4281018671,
surfaceContainerHighest: 4281742394,
surfaceTint: 4291804670,
surfaceDim: 4279702038,
surfaceBright: 4282267452,
surfaceContainerLowest: 4279373073,
surfaceContainerLow: 4280293918,
surfaceContainer: 4280557090,
surfaceContainerHigh: 4281280557,
surfaceContainerHighest: 4282004280,
surfaceTint: 4294030310,
}}
/>
<style>
:global(.icon) {
font-size: 2em;
}
:global(.pad-children > *) {
margin: 2rem;
}
:global(#nav > *) {
padding: 0.5em;
}
spacer {
margin: 1em;
}
:global(body, html, #app) {
width: 100vw;
:global(body, html) {
height: 100vh;
padding: 0;
margin: 0;
background-color: rgb(var(--m3-scheme-background));
color: rgb(var(--m3-scheme-on-background));
}
</style>

View file

@ -0,0 +1,234 @@
<script lang="ts">
import { initializeApp } from "firebase/app";
import {
Auth,
browserLocalPersistence,
createUserWithEmailAndPassword,
getAuth,
setPersistence,
signInWithEmailAndPassword,
} from "firebase/auth";
import {
Button,
Dialog,
Divider,
ListItemLabel,
RadioAnim2,
SnackbarAnim,
TextField,
} from "m3-svelte";
import { setBareClientImplementation } from "@mercuryworkshop/bare-client-custom";
import {
AdriftBareClient,
Connection,
RTCTransport,
SignalFirebase,
} from "client";
import trackerList from "tracker-list";
import { UIState } from "./state";
type valueof<T> = T[keyof T];
export let dialogConnection: boolean;
let tlsWarningShown = false;
let selectedTracker = Object.keys(trackerList)[0] as keyof typeof trackerList;
let trackerStats: Record<string, any> = {};
const getStats = async (tracker: valueof<typeof trackerList>) => {
const url = new URL(`${tracker.tracker}/stats`);
url.protocol = "https://";
const resp = await fetch(url);
return await resp.json();
};
Object.entries(trackerList).map(async ([trackerId, tracker]) => {
const stats = await getStats(tracker);
trackerStats[trackerId] = stats;
});
export let state: UIState;
export let stateStr: string;
let auth: Auth;
let transport: RTCTransport;
function createRTCTransport() {
return new RTCTransport(
async () => {
stateStr = "Transport opened";
console.log("[TRANSPORT] opened");
const connection = new Connection(transport);
await connection.initialize();
const bare = new AdriftBareClient(connection);
setBareClientImplementation(bare);
state = UIState.Connected;
},
() => console.warn("[TRANSPORT] closed"),
() => {
stateStr = `Connection ${transport.peer.connectionState}...`;
},
() => {
stateStr = `Signaling ${transport.peer.connectionState}...`;
},
() => {
if (transport.peer.connectionState == "new") {
stateStr = `Creating an offer...`;
} else {
stateStr = `Gathering ${transport.peer.connectionState}...`;
}
}
);
}
function connectToApp(tracker: valueof<typeof trackerList>) {
initializeApp(tracker.firebase);
auth = getAuth();
}
async function connectSwarm() {
connectToApp(trackerList[selectedTracker]);
state = UIState.Connecting;
transport = createRTCTransport();
const offer = await transport.createOffer();
stateStr = "Finding a node...";
try {
const answer = await SignalFirebase.signalSwarm(JSON.stringify(offer));
stateStr = "Linking to the node...";
transport.answer(answer.answer, answer.candidates);
} catch (e) {
console.error("While connecting to swarm", e);
stateStr = e;
}
}
let dialogAccount = false;
let email = "";
let password = "";
let snackbar: (data: any) => void;
async function connectNode() {
state = UIState.Connecting;
transport = createRTCTransport();
const offer = await transport.createOffer();
stateStr = "Finding your node...";
let answer = await SignalFirebase.signalAccount(JSON.stringify(offer));
stateStr = "Linking to the node...";
transport.answer(answer.answer, answer.candidates);
}
</script>
<Dialog bind:open={dialogConnection} headline="Connect to a tracker">
<div class="flex flex-col -mx-4">
{#each Object.entries(trackerList) as [trackerId, tracker], i}
{#if i != 0}
<Divider />
{/if}
<ListItemLabel
headline={trackerId}
supporting={trackerStats[trackerId]
? `${tracker.description} - ${
trackerStats[trackerId].members.length
} ${trackerStats[trackerId].members.length == 1 ? "node" : "nodes"}`
: tracker.description}
>
<RadioAnim2 slot="leading">
<input
type="radio"
name="tracker"
bind:group={selectedTracker}
value={trackerId}
/>
</RadioAnim2>
</ListItemLabel>
{/each}
</div>
<p class="font-bold mt-4" class:hide-warning={!tlsWarningShown}>
Your data is not end-to-end encrypted, and will not be private. While TLS
will be implemented later, for now do not enter any private information.
Click connect again to continue.
</p>
<svelte:fragment slot="buttons">
<Button type="text" on:click={() => (dialogConnection = false)}>
Cancel
</Button>
<Button
type="text"
on:click={() => {
connectToApp(trackerList[selectedTracker]);
setPersistence(auth, browserLocalPersistence);
console.log(browserLocalPersistence, auth.currentUser);
if (auth.currentUser) {
connectNode();
} else {
dialogConnection = false;
dialogAccount = true;
}
}}
>
Connect to your node
</Button>
<Button
type="tonal"
on:click={() => {
if (tlsWarningShown) {
connectSwarm();
dialogConnection = false;
}
tlsWarningShown = true;
}}
>
Connect
</Button>
</svelte:fragment>
</Dialog>
<Dialog bind:open={dialogAccount} headline="Sign in">
<div class="flex gap-4 flex-col">
<TextField name="Email" bind:value={email} />
<TextField
name="Password"
bind:value={password}
extraOptions={{ type: "password" }}
/>
</div>
<svelte:fragment slot="buttons">
<Button type="text" on:click={() => (dialogAccount = false)}>Cancel</Button>
<Button
type="text"
on:click={async () => {
try {
await createUserWithEmailAndPassword(auth, email, password);
await connectNode();
} catch (e) {
snackbar({ message: e.message, closable: true });
}
}}
>
Sign up
</Button>
<Button
type="text"
on:click={async () => {
try {
await signInWithEmailAndPassword(auth, email, password);
await connectNode();
} catch (e) {
snackbar({ message: e.message, closable: true });
}
}}
>
Log in
</Button>
</svelte:fragment>
</Dialog>
<SnackbarAnim bind:show={snackbar} />
<style>
.hide-warning {
margin: 0;
height: 0;
visibility: hidden;
}
</style>

View file

@ -3,9 +3,6 @@
import { Win, openWindow } from "../../corium";
import Icon from "@iconify/svelte";
let selectedProxy = "ultraviolet";
let url: string = "http://google.com";
import { onMount } from "svelte";
import {
Dialog,
@ -14,10 +11,14 @@
TextField,
} from "m3-svelte";
let url = "http://google.com";
let proxyIframe: HTMLIFrameElement;
let settingsenabled: boolean = false;
let selectedProxy = "ultraviolet";
let searchengine = "https://google.com/search?q=";
function frameLoad() {
@ -59,96 +60,92 @@
});
</script>
<div class="h-full w-full flex flex-col">
<div class="h-full flex flex-col">
<div class="flex p-2">
<div class="flex text-xl items-center w-full">
<button
class="text-2xl p-2 hover:text-primary"
on:click={() => {
proxyIframe.contentWindow?.history.back();
}}
>
<Icon icon="ic:round-arrow-back" />
</button>
<button
class="text-2xl p-2 hover:text-primary"
on:click={() => {
proxyIframe.contentWindow?.history.forward();
}}
>
<Icon icon="ic:round-arrow-forward" />
</button>
<button
class="text-2xl p-2 hover:text-primary"
on:click={() => {
visitURL(url);
}}
>
<Icon icon="ic:round-refresh" />
</button>
<div class="flex flex-1 mx-2 border border-outline rounded-xl">
<button
on:click={() => {
proxyIframe.contentWindow?.history.back();
}}
>
<Icon icon="fluent-mdl2:back" />
</button>
<div class="p-2" />
<button
on:click={() => {
proxyIframe.contentWindow?.history.forward();
}}
>
<Icon icon="fluent-mdl2:forward" />
</button>
<button
class="text-2xl px-4"
class="text-2xl px-2 hover:text-primary"
on:click={() => {
visitURL(url);
}}
>
<Icon icon="tabler:reload" />
<Icon icon="ic:round-search" />
</button>
<div class="urlbar flex items-center flex-1">
<button
class="text-2xl px-2"
on:click={() => {
<input
bind:value={url}
type="text"
class="flex-1 w-0 pr-2 text-xl"
on:keydown={(e) => {
if (e.key === "Enter") {
visitURL(url);
}}
>
<Icon icon="ic:round-search" />
</button>
<input
bind:value={url}
type="text"
class="flex-1"
on:keydown={(e) => {
if (e.key === "Enter") {
visitURL(url);
}
}}
/>
</div>
<button class="text-2xl pl-3" on:click={() => (settingsenabled = true)}>
<Icon icon="ic:round-settings" />
</button>
}
}}
/>
</div>
<Dialog bind:open={settingsenabled} headline="Proxy Settings">
{#if !import.meta.env.VITE_ADRIFT_SINGLEFILE}
<div>
<SegmentedButtonContainer>
<input
type="radio"
name="selectedProxy"
bind:group={selectedProxy}
value="ultraviolet"
id="ultraviolet"
/>
<SegmentedButtonItem input="ultraviolet"
>Ultraviolet</SegmentedButtonItem
>
<input
type="radio"
name="selectedProxy"
bind:group={selectedProxy}
value="dynamic"
id="dynamic"
/>
<SegmentedButtonItem input="dynamic">Dynamic</SegmentedButtonItem>
</SegmentedButtonContainer>
</div>
<br />
<TextField name="Default Search Engine" bind:value={searchengine} />
{/if}
</Dialog>
<button
class="text-2xl p-2 hover:text-primary"
on:click={() => (settingsenabled = true)}
>
<Icon icon="ic:round-settings" />
</button>
</div>
<iframe class="flex-1" bind:this={proxyIframe} on:load={frameLoad} />
</div>
<Dialog bind:open={settingsenabled} headline="Proxy Settings">
{#if !import.meta.env.VITE_ADRIFT_SINGLEFILE}
<div>
<SegmentedButtonContainer>
<input
type="radio"
name="selectedProxy"
bind:group={selectedProxy}
value="ultraviolet"
id="ultraviolet"
/>
<SegmentedButtonItem input="ultraviolet">
Ultraviolet
</SegmentedButtonItem>
<input
type="radio"
name="selectedProxy"
bind:group={selectedProxy}
value="dynamic"
id="dynamic"
/>
<SegmentedButtonItem input="dynamic">Dynamic</SegmentedButtonItem>
</SegmentedButtonContainer>
</div>
<br />
<TextField name="Default Search Engine" bind:value={searchengine} />
{/if}
</Dialog>
<style>
.urlbar {
border: solid 0.0625rem rgb(var(--m3-scheme-outline));
padding: 0.25rem;
border-radius: 0.75rem;
}
input {
background-color: transparent;
outline: none;

View file

@ -1,6 +1,18 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
*{
font-family: "Cabin";
}
html {
background-color: rgb(var(--m3-scheme-background));
color: rgb(var(--m3-scheme-on-background));
--m3-font-display: Cabin, system-ui, sans-serif;
--m3-font-headline: Cabin, system-ui, sans-serif;
--m3-font-title: Cabin, system-ui, sans-serif;
--m3-font-label: Cabin, system-ui, sans-serif;
--m3-font-label-large-tracking: 0.25px;
--m3-font-label-medium-tracking: 1px;
--m3-font-label-small-tracking: 1px;
--m3-font-body: Cabin, system-ui, sans-serif;
}
#app {
display: contents;
}

5
frontend/src/state.ts Normal file
View file

@ -0,0 +1,5 @@
export enum UIState {
Idle,
Connecting,
Connected,
}

View file

@ -1,11 +1,68 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,svelte,html}",
],
theme: {
extend: {},
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,svelte,html}"],
theme: {
extend: {
colors: {
primary: "rgb(var(--m3-scheme-primary) / <alpha-value>)",
"on-primary": "rgb(var(--m3-scheme-on-primary) / <alpha-value>)",
"primary-container":
"rgb(var(--m3-scheme-primary-container) / <alpha-value>)",
"on-primary-container":
"rgb(var(--m3-scheme-on-primary-container) / <alpha-value>)",
secondary: "rgb(var(--m3-scheme-secondary) / <alpha-value>)",
"on-secondary": "rgb(var(--m3-scheme-on-secondary) / <alpha-value>)",
"secondary-container":
"rgb(var(--m3-scheme-secondary-container) / <alpha-value>)",
"on-secondary-container":
"rgb(var(--m3-scheme-on-secondary-container) / <alpha-value>)",
tertiary: "rgb(var(--m3-scheme-tertiary) / <alpha-value>)",
"on-tertiary": "rgb(var(--m3-scheme-on-tertiary) / <alpha-value>)",
"tertiary-container":
"rgb(var(--m3-scheme-tertiary-container) / <alpha-value>)",
"on-tertiary-container":
"rgb(var(--m3-scheme-on-tertiary-container) / <alpha-value>)",
error: "rgb(var(--m3-scheme-error) / <alpha-value>)",
"on-error": "rgb(var(--m3-scheme-on-error) / <alpha-value>)",
"error-container":
"rgb(var(--m3-scheme-error-container) / <alpha-value>)",
"on-error-container":
"rgb(var(--m3-scheme-on-error-container) / <alpha-value>)",
background: "rgb(var(--m3-scheme-background) / <alpha-value>)",
"on-background": "rgb(var(--m3-scheme-on-background) / <alpha-value>)",
surface: "rgb(var(--m3-scheme-surface) / <alpha-value>)",
"on-surface": "rgb(var(--m3-scheme-on-surface) / <alpha-value>)",
"surface-variant":
"rgb(var(--m3-scheme-surface-variant) / <alpha-value>)",
"on-surface-variant":
"rgb(var(--m3-scheme-on-surface-variant) / <alpha-value>)",
outline: "rgb(var(--m3-scheme-outline) / <alpha-value>)",
"outline-variant":
"rgb(var(--m3-scheme-outline-variant) / <alpha-value>)",
shadow: "rgb(var(--m3-scheme-shadow) / <alpha-value>)",
scrim: "rgb(var(--m3-scheme-scrim) / <alpha-value>)",
"inverse-surface":
"rgb(var(--m3-scheme-inverse-surface) / <alpha-value>)",
"inverse-on-surface":
"rgb(var(--m3-scheme-inverse-on-surface) / <alpha-value>)",
"inverse-primary":
"rgb(var(--m3-scheme-inverse-primary) / <alpha-value>)",
"surface-bright":
"rgb(var(--m3-scheme-surface-bright) / <alpha-value>)",
"surface-container":
"rgb(var(--m3-scheme-surface-container) / <alpha-value>)",
"surface-container-high":
"rgb(var(--m3-scheme-surface-container-high) / <alpha-value>)",
"surface-container-highest":
"rgb(var(--m3-scheme-surface-container-highest) / <alpha-value>)",
"surface-container-low":
"rgb(var(--m3-scheme-surface-container-low) / <alpha-value>)",
"surface-container-lowest":
"rgb(var(--m3-scheme-surface-container-lowest) / <alpha-value>)",
"surface-dim": "rgb(var(--m3-scheme-surface-dim) / <alpha-value>)",
"surface-tint": "rgb(var(--m3-scheme-surface-tint) / <alpha-value>)",
},
},
plugins: [],
}
},
plugins: [],
};