From c3b05a72b7185112ece6e42c99e9a828c8298f04 Mon Sep 17 00:00:00 2001 From: Melonai Date: Thu, 8 Jul 2021 23:29:20 +0200 Subject: State display for incoming and own requests --- assets/src/network/transfer/request.ts | 49 ---------------- assets/src/network/transfer/request_transfer.ts | 51 +++++++++++++++++ assets/src/network/transfer/share.ts | 71 ------------------------ assets/src/network/transfer/share_transfer.ts | 74 +++++++++++++++++++++++++ assets/src/network/transfer/transfer.ts | 44 ++++++++++++--- 5 files changed, 161 insertions(+), 128 deletions(-) delete mode 100644 assets/src/network/transfer/request.ts create mode 100644 assets/src/network/transfer/request_transfer.ts delete mode 100644 assets/src/network/transfer/share.ts create mode 100644 assets/src/network/transfer/share_transfer.ts (limited to 'assets/src/network/transfer') diff --git a/assets/src/network/transfer/request.ts b/assets/src/network/transfer/request.ts deleted file mode 100644 index 920cd9a..0000000 --- a/assets/src/network/transfer/request.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { on, send } from "../channel/connection"; -import type { RequestIceCandidateMessage } from "../channel/messages/messages"; -import { - createTransfer, - onIncomingIceCandidate, - Transfer, - TransferType, - unregisterIceOnComplete, -} from "./transfer"; - -export async function answer( - offer: RTCSessionDescriptionInit -): Promise { - const transfer = createTransfer(TransferType.ANSWER, onChannel); - - const offerDescription = new RTCSessionDescription(offer); - transfer.pc.setRemoteDescription(offerDescription); - - 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 }); - } - }; - - const unregisterIce = on( - "ice_candidate", - (message: RequestIceCandidateMessage) => - onIncomingIceCandidate(transfer, message) - ); - - unregisterIceOnComplete(transfer, unregisterIce); - - send("accept_share", { - sdp: answer.sdp, - type: answer.type, - }); - - return transfer; -} - -function onChannel(channel: RTCDataChannel) { - channel.onmessage = event => { - console.log(event.data) - } -} diff --git a/assets/src/network/transfer/request_transfer.ts b/assets/src/network/transfer/request_transfer.ts new file mode 100644 index 0000000..317f5e5 --- /dev/null +++ b/assets/src/network/transfer/request_transfer.ts @@ -0,0 +1,51 @@ +import data from "../../stores/data"; +import { on, send } from "../channel/connection"; +import type { RequestIceCandidateMessage } from "../channel/messages/messages"; +import { + createTransfer, + onIncomingIceCandidate, + Transfer, + unregisterIceOnComplete, +} from "./transfer"; + +export async function createAnswerTransfer( + offer: RTCSessionDescriptionInit +): Promise { + const transfer = createTransfer(onChannel); + + const offerDescription = new RTCSessionDescription(offer); + transfer.pc.setRemoteDescription(offerDescription); + + 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 }); + } + }; + + const unregisterIce = on( + "ice_candidate", + (message: RequestIceCandidateMessage) => + onIncomingIceCandidate(transfer, message) + ); + + unregisterIceOnComplete(transfer, unregisterIce); + + send("accept_share", { + sdp: answer.sdp, + type: answer.type, + }); + + return transfer; +} + +function onChannel(channel: RTCDataChannel, completeTransfer: () => void) { + channel.onmessage = event => { + data.set(event.data); + // TODO: Disconnect from channel + completeTransfer(); + }; +} diff --git a/assets/src/network/transfer/share.ts b/assets/src/network/transfer/share.ts deleted file mode 100644 index 5e43df0..0000000 --- a/assets/src/network/transfer/share.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { get } from "svelte/store"; -import dataStore from "../../stores/data"; -import { onWithToken, send } from "../channel/connection"; -import type { UnregisterHandler } from "../channel/messages/handler"; -import type { - RequestIceCandidateMessage, - ShareAcceptedMessage, -} from "../channel/messages/messages"; -import { - createTransfer, - onIncomingIceCandidate, - Transfer, - TransferType, - unregisterIceOnComplete, -} from "./transfer"; - -export async function offer(request_token: string): Promise { - const transfer = createTransfer(TransferType.OFFER, onChannel); - - const offer = await transfer.pc.createOffer(); - transfer.pc.setLocalDescription(offer); - - transfer.pc.onicecandidate = event => { - const candidate = event.candidate; - if (event.candidate !== null) { - send("ice_candidate", { candidate, token: request_token }); - } - }; - - send("accept_request", { - token: request_token, - sdp: offer.sdp, - type: offer.type, - }); - - onWithToken( - "share_accepted", - request_token, - (message: ShareAcceptedMessage, unregister) => - onShareAccepted(transfer, message, unregister) - ); - - return transfer; -} - -function onShareAccepted( - transfer: Transfer, - message: ShareAcceptedMessage, - unregister: UnregisterHandler -) { - const token = message.token; - - const answerDescription = new RTCSessionDescription(message); - transfer.pc.setRemoteDescription(answerDescription); - - const unregisterIce = onWithToken( - "ice_candidate", - token, - (message: RequestIceCandidateMessage) => - onIncomingIceCandidate(transfer, message) - ); - - unregisterIceOnComplete(transfer, unregisterIce); - - unregister(); -} - -function onChannel(channel: RTCDataChannel) { - const data = get(dataStore).data; - channel.send(data); -} diff --git a/assets/src/network/transfer/share_transfer.ts b/assets/src/network/transfer/share_transfer.ts new file mode 100644 index 0000000..fc6df9c --- /dev/null +++ b/assets/src/network/transfer/share_transfer.ts @@ -0,0 +1,74 @@ +import { get } from "svelte/store"; +import dataStore from "../../stores/data"; +import { onWithToken, send } from "../channel/connection"; +import type { UnregisterHandler } from "../channel/messages/handler"; +import type { + RequestIceCandidateMessage, + ShareAcceptedMessage, +} from "../channel/messages/messages"; +import { + createTransfer, + onIncomingIceCandidate, + Transfer, + unregisterIceOnComplete, +} from "./transfer"; + +export async function createOfferTransfer( + request_token: string +): Promise { + const transfer = createTransfer(onChannel); + + const offer = await transfer.pc.createOffer(); + transfer.pc.setLocalDescription(offer); + + transfer.pc.onicecandidate = event => { + const candidate = event.candidate; + if (event.candidate !== null) { + send("ice_candidate", { candidate, token: request_token }); + } + }; + + send("accept_request", { + token: request_token, + sdp: offer.sdp, + type: offer.type, + }); + + onWithToken( + "share_accepted", + request_token, + (message: ShareAcceptedMessage, unregister) => + onShareAccepted(transfer, message, unregister) + ); + + return transfer; +} + +function onShareAccepted( + transfer: Transfer, + message: ShareAcceptedMessage, + unregister: UnregisterHandler +) { + const token = message.token; + + const answerDescription = new RTCSessionDescription(message); + transfer.pc.setRemoteDescription(answerDescription); + + const unregisterIce = onWithToken( + "ice_candidate", + token, + (message: RequestIceCandidateMessage) => + onIncomingIceCandidate(transfer, message) + ); + + unregisterIceOnComplete(transfer, unregisterIce); + + unregister(); +} + +function onChannel(channel: RTCDataChannel, completeTransfer: () => void) { + const data = get(dataStore).data; + channel.send(data); + // TODO: Add retransmission possibility in case of transfer failure? + completeTransfer(); +} diff --git a/assets/src/network/transfer/transfer.ts b/assets/src/network/transfer/transfer.ts index 976d113..7641c17 100644 --- a/assets/src/network/transfer/transfer.ts +++ b/assets/src/network/transfer/transfer.ts @@ -1,18 +1,22 @@ +import { Writable, writable } from "svelte/store"; +import type { IncomingRequest } from "../../models/incoming_request"; +import type { OwnRequest } from "../../models/own_request"; import type { UnregisterHandler } from "../channel/messages/handler"; import type { RequestIceCandidateMessage, ShareIceCandidateMessage, } from "../channel/messages/messages"; -export enum TransferType { - OFFER, - ANSWER, +export enum TransferState { + CONNECTING, + TRANSFERRING, + DONE, } export type Transfer = { pc: RTCPeerConnection; channel: RTCDataChannel; - type: TransferType; + state: Writable; }; const servers = { @@ -28,24 +32,48 @@ const servers = { }; export function createTransfer( - type: TransferType, - onChannel: (channel: RTCDataChannel) => void + onChannel: (channel: RTCDataChannel, completeTransfer: () => void) => void ): Transfer { const pc = new RTCPeerConnection(servers); const channel = pc.createDataChannel("channel", { negotiated: true, id: 0, }); + const state = writable(TransferState.CONNECTING); - channel.onopen = () => onChannel(channel); + channel.onopen = () => { + state.set(TransferState.TRANSFERRING); + const completeTransfer = () => state.set(TransferState.DONE); + onChannel(channel, completeTransfer); + }; return { pc, channel, - type, + state, }; } +export function bindTransfer( + request: OwnRequest | IncomingRequest, + transferPromise: Promise, + onTransferComplete: () => void +) { + transferPromise.then(transfer => { + request.transfer = transfer; + + const unsubsribe = transfer.state.subscribe(transferState => { + if (transferState === TransferState.DONE) { + unsubsribe(); + // Once the data has been transferred we can remove the transfer + request.transfer = null; + + onTransferComplete(); + } + }); + }); +} + export function onIncomingIceCandidate( transfer: Transfer, message: ShareIceCandidateMessage | RequestIceCandidateMessage -- cgit 1.4.1