diff options
| author | Mel <einebeere@gmail.com> | 2022-02-19 20:00:38 +0100 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2022-02-19 20:00:38 +0100 |
| commit | bf1450799df0deb424a9675be89e13c29e3620d7 (patch) | |
| tree | 6a5f2f7559c5946058deadf8375f6609485a3d3f /assets/src/state/request.ts | |
| parent | 5384c34952b031995ecb8aa58d72954b0c685e18 (diff) | |
| download | rook-bf1450799df0deb424a9675be89e13c29e3620d7.tar.zst rook-bf1450799df0deb424a9675be89e13c29e3620d7.zip | |
Split state into stages to handle messages
Diffstat (limited to 'assets/src/state/request.ts')
| -rw-r--r-- | assets/src/state/request.ts | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/assets/src/state/request.ts b/assets/src/state/request.ts new file mode 100644 index 0000000..30e71af --- /dev/null +++ b/assets/src/state/request.ts @@ -0,0 +1,153 @@ +import { writable, Writable } from "svelte/store"; +import { RookType } from "../models/rook_type"; +import { Connection } from "../network/channel/connection"; +import type { + RequestAcceptedMessage, + RequestAcknowledgedMessage, + ShareCancelledMessage, + ShareIceCandidateMessage, +} from "../network/channel/messages/messages"; +import { respondToOffer } from "../network/transfer/request_transfer"; +import { addRemoteIceCandidate, Transfer } from "../network/transfer/transfer"; +import { isClientRequest } from "./constant_state"; +import b from "../utils/bind"; + +export enum RequestStateType { + CONNECTING, + + WAITING_FOR_RESPONSE, + + IN_FLIGHT, + DONE, + + DECLINED, + SHARE_CANCELLED, + NO_SUCH_SHARE, +} + +type RequestState = { + type: Writable<RequestStateType>; + state: + | Connecting + | WaitingForResponse + | Transferring + | Done + | Declined + | ShareCancelled + | NoSuchShare; +}; + +let request: RequestState | null = null; + +export function initializeRequest() { + if (!isClientRequest()) { + throw new Error( + "Tried to initialize request state on non-request client." + ); + } + + if (request) { + throw new Error("Request state already initialized."); + } + + request = { + type: writable(RequestStateType.CONNECTING), + state: new Connecting(), + }; +} + +export function getRequestState(): RequestState { + if (!isClientRequest()) { + throw new Error("Tried to access share state on non-share client."); + } + + return request; +} + +class Connecting { + private connection: Connection; + + constructor() { + this.connection = new Connection(); + this.connection.setChannelMessageHandler({ + request_acknowledged: b(this, this.onRequestAcknowledged), + }); + + this.connection.start(RookType.REQUEST); + } + + private onRequestAcknowledged(m: RequestAcknowledgedMessage) { + request.type.set(RequestStateType.WAITING_FOR_RESPONSE); + request.state = new WaitingForResponse(this.connection); + } +} + +class WaitingForResponse { + private connection: Connection; + + constructor(connection: Connection) { + this.connection = connection; + + this.connection.setChannelMessageHandler({ + request_accepted: b(this, this.onRequestAccepted), + share_cancelled: b(this, this.onShareCancelled), + // TODO: request_declined + }); + } + + private onRequestAccepted(m: RequestAcceptedMessage) { + request.type.set(RequestStateType.IN_FLIGHT); + request.state = new Transferring(this.connection, m); + } + + private onShareCancelled(m: ShareCancelledMessage) { + request.type.set(RequestStateType.SHARE_CANCELLED); + request.state = null; + } +} + +class Transferring { + private connection: Connection; + private transfer: Transfer | null = null; + private unaddedIceCandidates: RTCIceCandidateInit[] = []; + + constructor(connection: Connection, offer: RTCSessionDescriptionInit) { + this.connection = connection; + this.connection.setChannelMessageHandler({ + share_ice_candidate: b(this, this.onShareIceCandidate), + // TODO: share_cancelled + }); + + const offerPromise = respondToOffer( + this.connection, + offer, + b(this, this.onTransferComplete) + ); + + offerPromise.then(transfer => { + for (const candidate of this.unaddedIceCandidates) { + addRemoteIceCandidate(transfer, candidate); + } + this.unaddedIceCandidates = []; + }); + } + + private onShareIceCandidate(m: ShareIceCandidateMessage) { + if (!this.transfer) { + this.unaddedIceCandidates.push(m.candidate); + } else { + addRemoteIceCandidate(this.transfer, m.candidate); + } + } + + private onTransferComplete() { + request.type.set(RequestStateType.DONE); + request.state = null; + } +} + +// Finished states. +type Done = null; +type Declined = null; +type ShareCancelled = null; +type NoSuchShare = null; |
