about summary refs log tree commit diff
path: root/assets/src
diff options
context:
space:
mode:
Diffstat (limited to 'assets/src')
-rw-r--r--assets/src/components/RequestPage.svelte (renamed from assets/src/components/Request.svelte)0
-rw-r--r--assets/src/components/SharePage.svelte (renamed from assets/src/components/Share.svelte)4
-rw-r--r--assets/src/components/share/DataPicker.svelte (renamed from assets/src/components/DataPicker.svelte)4
-rw-r--r--assets/src/components/share/Request.svelte31
-rw-r--r--assets/src/components/share/Requests.svelte (renamed from assets/src/components/IncomingRequests.svelte)7
-rw-r--r--assets/src/entries/request.ts4
-rw-r--r--assets/src/entries/share.ts4
-rw-r--r--assets/src/network/channel/connection.ts2
-rw-r--r--assets/src/network/channel/messages/handler.ts49
-rw-r--r--assets/src/network/channel/request.ts10
-rw-r--r--assets/src/network/channel/share.ts28
-rw-r--r--assets/src/network/transfer/transfer.ts82
-rw-r--r--assets/src/stores/requests.ts4
13 files changed, 194 insertions, 35 deletions
diff --git a/assets/src/components/Request.svelte b/assets/src/components/RequestPage.svelte
index 0c0b111..0c0b111 100644
--- a/assets/src/components/Request.svelte
+++ b/assets/src/components/RequestPage.svelte
diff --git a/assets/src/components/Share.svelte b/assets/src/components/SharePage.svelte
index 5ea55b2..d951288 100644
--- a/assets/src/components/Share.svelte
+++ b/assets/src/components/SharePage.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
     import data from "../stores/data";
-    import DataPicker from "./DataPicker.svelte";
-    import IncomingRequests from "./IncomingRequests.svelte";
+    import DataPicker from "./share/DataPicker.svelte";
+    import IncomingRequests from "./share/Requests.svelte";
 </script>
 
 <main>
diff --git a/assets/src/components/DataPicker.svelte b/assets/src/components/share/DataPicker.svelte
index 433018d..6e8dbd4 100644
--- a/assets/src/components/DataPicker.svelte
+++ b/assets/src/components/share/DataPicker.svelte
@@ -1,11 +1,13 @@
 <script lang="ts">
-    import data from "../stores/data";
+    import data from "../../stores/data";
 
     let value = "";
 
     const submit = () => {
         data.set(value);
     };
+
+    // TODO: Accept data other than text.
 </script>
 
 <form on:submit|preventDefault={submit}>
diff --git a/assets/src/components/share/Request.svelte b/assets/src/components/share/Request.svelte
new file mode 100644
index 0000000..26002ae
--- /dev/null
+++ b/assets/src/components/share/Request.svelte
@@ -0,0 +1,31 @@
+<script lang="ts">
+    import { offer } from "../../network/transfer/transfer";
+
+    export let token: string;
+
+    async function accept() {
+        const transfer = await offer(token);
+    }
+
+    function decline() {}
+</script>
+
+<div class="container">
+    <span>{token}</span>
+    <div class="buttons">
+        <button on:click={accept}>Accept</button>
+        <button on:click={decline}>X</button>
+    </div>
+</div>
+
+<style>
+    .container {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+    }
+
+    .buttons {
+        display: flex;
+    }
+</style>
diff --git a/assets/src/components/IncomingRequests.svelte b/assets/src/components/share/Requests.svelte
index bf08ffe..509d7be 100644
--- a/assets/src/components/IncomingRequests.svelte
+++ b/assets/src/components/share/Requests.svelte
@@ -1,7 +1,8 @@
 <script lang="ts">
-    import { getOwnToken, start, Type } from "../network/channel/connection";
+    import { getOwnToken, start, Type } from "../../network/channel/connection";
 
-    import requests from "../stores/requests";
+    import requests from "../../stores/requests";
+    import Request from "./Request.svelte";
 
     const startPromise = start(Type.SHARE);
 
@@ -14,6 +15,6 @@
     <h3>Your token is <b>{getOwnToken()}</b>.</h3>
 
     {#each $requests as request}
-        <p>{JSON.stringify(request)}</p>
+        <Request token={request} />
     {/each}
 {/await}
diff --git a/assets/src/entries/request.ts b/assets/src/entries/request.ts
index 74f84da..6b8a79f 100644
--- a/assets/src/entries/request.ts
+++ b/assets/src/entries/request.ts
@@ -1,6 +1,6 @@
-import Request from "../components/Request.svelte";
+import RequestPage from "../components/RequestPage.svelte";
 
-const app = new Request({
+const app = new RequestPage({
     target: document.getElementById("app"),
     props: {},
 });
diff --git a/assets/src/entries/share.ts b/assets/src/entries/share.ts
index d0279f1..2704a62 100644
--- a/assets/src/entries/share.ts
+++ b/assets/src/entries/share.ts
@@ -1,6 +1,6 @@
-import Share from "../components/Share.svelte";
+import SharePage from "../components/SharePage.svelte";
 
-const app = new Share({
+const app = new SharePage({
     target: document.getElementById("app"),
     props: {},
 });
diff --git a/assets/src/network/channel/connection.ts b/assets/src/network/channel/connection.ts
index 59eb633..e1ed2d1 100644
--- a/assets/src/network/channel/connection.ts
+++ b/assets/src/network/channel/connection.ts
@@ -54,6 +54,8 @@ export async function start(type: Type.REQUEST | Type.SHARE) {
     type === Type.SHARE
         ? await startShare(connection)
         : await startRequest(connection);
+
+    updateState(ConnectionState.CONNECTED)
 }
 
 export function send(event: string, data: any): Push {
diff --git a/assets/src/network/channel/messages/handler.ts b/assets/src/network/channel/messages/handler.ts
index f7a00d2..cc8f005 100644
--- a/assets/src/network/channel/messages/handler.ts
+++ b/assets/src/network/channel/messages/handler.ts
@@ -1,4 +1,4 @@
-import { getChannel } from "../connection";
+import type { Channel } from "phoenix";
 import type { AnyMessage } from "./messages";
 
 export type Handlers = {
@@ -14,7 +14,10 @@ export type TokenHandler<Message extends AnyMessage> = {
     [token: string]: Handler<Message>;
 };
 
-export type Handler<Message extends AnyMessage> = (message?: Message) => void;
+export type Handler<Message extends AnyMessage> = (
+    message?: Message,
+    unregister?: UnregisterHandler
+) => void;
 
 export type UnregisterHandler = () => void;
 
@@ -45,17 +48,12 @@ export function registerTokenHandler<Message extends AnyMessage>(
         const directHandlers = eventHandler.directHandlers;
         directHandlers.push(handler);
 
-        unregister = () => {
-            const index = directHandlers.findIndex(h => h === handler);
-            directHandlers.splice(index, 1);
-        };
+        unregister = makeDirectUnregister(directHandlers, handler);
     } else {
         const tokenHandler = eventHandler.tokenHandler;
         tokenHandler[token] = handler;
 
-        unregister = () => {
-            delete tokenHandler[token];
-        };
+        unregister = makeTokenUnregister(tokenHandler, token);
     }
 
     return unregister;
@@ -80,16 +78,35 @@ function handleEvent<Message extends AnyMessage>(
     if (message["token"] !== undefined) {
         const token = message["token"];
 
-        const handler: Handler<Message> = eventHandler.tokenHandler[token];
+        const tokenHandler = eventHandler.tokenHandler;
+        const handler: Handler<Message> = tokenHandler[token];
 
-        if (handler === undefined) {
-            throw new Error("Received message for an unknown token.");
+        if (handler !== undefined) {
+            handler(message, makeTokenUnregister(tokenHandler, token));
         }
-
-        handler(message);
     }
 
-    for (const handler of eventHandler.directHandlers) {
-        handler(message);
+    const directHandlers = eventHandler.directHandlers;
+    for (const handler of directHandlers) {
+        handler(message, makeDirectUnregister(directHandlers, handler));
     }
 }
+
+function makeDirectUnregister<Message extends AnyMessage>(
+    directHandlers: Handler<Message>[],
+    handler: Handler<Message>
+): UnregisterHandler {
+    return () => {
+        const index = directHandlers.findIndex(h => h === handler);
+        directHandlers.splice(index, 1);
+    };
+}
+
+function makeTokenUnregister<Message extends AnyMessage>(
+    tokenHandler: TokenHandler<Message>,
+    token: string
+): UnregisterHandler {
+    return () => {
+        delete tokenHandler[token];
+    };
+}
diff --git a/assets/src/network/channel/request.ts b/assets/src/network/channel/request.ts
index dd18aab..f5145fb 100644
--- a/assets/src/network/channel/request.ts
+++ b/assets/src/network/channel/request.ts
@@ -1,5 +1,7 @@
 import getShareToken from "../../utils/getShareToken";
-import type { Connection } from "./connection";
+import { answer } from "../transfer/transfer";
+import { Connection, on } from "./connection";
+import type { RequestAcceptedMessage } from "./messages/messages";
 import { joinRequestChannel } from "./socket";
 
 export async function startRequest(connection: Connection) {
@@ -9,4 +11,10 @@ export async function startRequest(connection: Connection) {
         getShareToken()
     );
     connection.channel = requestChannel;
+
+    on("request_accepted", onRequestAccepted);
+}
+
+async function onRequestAccepted(message: RequestAcceptedMessage) {
+    await answer(message);
 }
diff --git a/assets/src/network/channel/share.ts b/assets/src/network/channel/share.ts
index f93e8cb..6dbf0cd 100644
--- a/assets/src/network/channel/share.ts
+++ b/assets/src/network/channel/share.ts
@@ -1,5 +1,10 @@
 import requests from "../../stores/requests";
-import type { Connection } from "./connection";
+import { Connection, on, onWithToken } from "./connection";
+import type { UnregisterHandler } from "./messages/handler";
+import type {
+    NewRequestMessage,
+    RequestCancelledMessage,
+} from "./messages/messages";
 import { joinShareChannel } from "./socket";
 
 export async function startShare(connection: Connection) {
@@ -8,4 +13,23 @@ export async function startShare(connection: Connection) {
         connection.token
     );
     connection.channel = shareChannel;
-}
\ No newline at end of file
+
+    on("new_request", onNewRequest);
+}
+
+function onNewRequest(message: NewRequestMessage) {
+    const token = message.token;
+
+    requests.addRequest(token);
+
+    onWithToken("request_cancelled", token, onRequestCancelled);
+}
+
+function onRequestCancelled(
+    message: RequestCancelledMessage,
+    unregister: UnregisterHandler
+) {
+    const token = message.token;
+    requests.removeRequest(token);
+    unregister();
+}
diff --git a/assets/src/network/transfer/transfer.ts b/assets/src/network/transfer/transfer.ts
index 26d2534..1cc029b 100644
--- a/assets/src/network/transfer/transfer.ts
+++ b/assets/src/network/transfer/transfer.ts
@@ -1,4 +1,10 @@
-import { send } from "../channel/connection";
+import { onWithToken, send } from "../channel/connection";
+import type { UnregisterHandler } from "../channel/messages/handler";
+import type {
+    ShareAcceptedMessage,
+    RequestIceCandidateMessage,
+    ShareIceCandidateMessage,
+} from "../channel/messages/messages";
 
 export enum TransferType {
     OFFER,
@@ -11,20 +17,44 @@ export type Transfer = {
     type: TransferType;
 };
 
+const servers = {
+    iceServers: [
+        {
+            urls: [
+                "stun:stun1.l.google.com:19302",
+                "stun:stun2.l.google.com:19302",
+            ],
+        },
+    ],
+    iceCandidatePoolSize: 10,
+};
+
 export async function offer(request_token: string): Promise<Transfer> {
     const transfer = createTransfer(TransferType.OFFER);
 
     const offer = await transfer.pc.createOffer();
     transfer.pc.setLocalDescription(offer);
 
-    // TODO: Start waiting for remote answer
+    transfer.pc.onicecandidate = event => {
+        const candidate = event.candidate;
+        if (event.candidate !== null) {
+            send("ice_candidate", { candidate, token: request_token });
+        }
+    };
 
     send("accept_request", {
-        request: request_token,
+        token: request_token,
         sdp: offer.sdp,
         type: offer.type,
     });
 
+    onWithToken(
+        "share_accepted",
+        request_token,
+        (message: ShareAcceptedMessage, unregister) =>
+            onShareAccepted(transfer, message, unregister)
+    );
+
     return transfer;
 }
 
@@ -39,6 +69,13 @@ export async function answer(
     const answer = await transfer.pc.createAnswer();
     transfer.pc.setLocalDescription(answer);
 
+    transfer.pc.onicecandidate = event => {
+        const candidate = event.candidate;
+        if (event.candidate !== null) {
+            send("ice_candidate", { candidate });
+        }
+    };
+
     send("accept_share", {
         sdp: offer.sdp,
         type: offer.type,
@@ -48,15 +85,50 @@ export async function answer(
 }
 
 function createTransfer(type: TransferType): Transfer {
-    const pc = new RTCPeerConnection(null);
+    const pc = new RTCPeerConnection(servers);
     const channel = pc.createDataChannel("channel", {
         negotiated: true,
         id: 0,
     });
 
+    channel.onopen = e => console.log("ooooyeeee");
+
     return {
         pc,
         channel,
         type,
     };
-}
\ No newline at end of file
+}
+
+function onShareAccepted(
+    transfer: Transfer,
+    message: ShareAcceptedMessage,
+    unregister: UnregisterHandler
+) {
+    const token = message.token;
+    transfer.pc.setRemoteDescription(message);
+
+    const unregisterIce = onWithToken(
+        "ice_candidate",
+        token,
+        (message: RequestIceCandidateMessage) =>
+            onIncomingIceCandidate(transfer, message)
+    );
+
+    transfer.pc.onicegatheringstatechange = event => {
+        const connection = event.target as any;
+        console.log(connection.iceGatheringState);
+        if (connection.iceGatheringState === "complete") {
+            unregisterIce();
+        }
+    };
+
+    unregister();
+}
+
+function onIncomingIceCandidate(
+    transfer: Transfer,
+    message: ShareIceCandidateMessage | RequestIceCandidateMessage
+) {
+    transfer.pc.addIceCandidate(message.candidate);
+}
diff --git a/assets/src/stores/requests.ts b/assets/src/stores/requests.ts
index e80eb2b..1dc8cb2 100644
--- a/assets/src/stores/requests.ts
+++ b/assets/src/stores/requests.ts
@@ -1,11 +1,13 @@
 import { writable } from "svelte/store";
 
 const createRequestStore = () => {
-    const { subscribe, update } = writable([]);
+    const { subscribe, update } = writable<string[]>([]);
 
     return {
         subscribe,
         addRequest: request => update(state => [request, ...state]),
+        removeRequest: request =>
+            update(state => state.filter(r => r !== request)),
     };
 };