From 8f1f90c3e7d836a23f1cd09617c2a0fcfac3f3f4 Mon Sep 17 00:00:00 2001 From: Melonai Date: Mon, 31 May 2021 01:47:38 +0200 Subject: Socket connection with managed state --- assets/src/components/IncomingRequests.svelte | 17 ++++--- assets/src/components/Request.svelte | 10 ++-- assets/src/network/channel/connection.ts | 69 +++++++++++++++++++++++++++ assets/src/network/channel/request.ts | 14 ++++++ assets/src/network/channel/share.ts | 17 +++++++ assets/src/network/channel/socket.ts | 59 +++++++++++++++++++++++ assets/src/network/socket.ts | 44 ----------------- 7 files changed, 170 insertions(+), 60 deletions(-) create mode 100644 assets/src/network/channel/connection.ts create mode 100644 assets/src/network/channel/request.ts create mode 100644 assets/src/network/channel/share.ts create mode 100644 assets/src/network/channel/socket.ts delete mode 100644 assets/src/network/socket.ts diff --git a/assets/src/components/IncomingRequests.svelte b/assets/src/components/IncomingRequests.svelte index 1db50af..bf08ffe 100644 --- a/assets/src/components/IncomingRequests.svelte +++ b/assets/src/components/IncomingRequests.svelte @@ -1,18 +1,17 @@ -{#await startConnection()} +{#await startPromise}

Fetching token...

-{:then token} -

Your token is {token}.

+{:then} +

Your token is {getOwnToken()}.

{#each $requests as request}

{JSON.stringify(request)}

diff --git a/assets/src/components/Request.svelte b/assets/src/components/Request.svelte index 134c4d5..0c0b111 100644 --- a/assets/src/components/Request.svelte +++ b/assets/src/components/Request.svelte @@ -1,13 +1,9 @@
diff --git a/assets/src/network/channel/connection.ts b/assets/src/network/channel/connection.ts new file mode 100644 index 0000000..52d85d1 --- /dev/null +++ b/assets/src/network/channel/connection.ts @@ -0,0 +1,69 @@ +import { Channel, Push, Socket } from "phoenix"; +import { startRequest } from "./request"; +import { startShare } from "./share"; +import { connectSocket, fetchToken } from "./socket"; + +export enum Type { + NONE, + REQUEST, + SHARE, +} + +enum ConnectionState { + CONNECTING_SOCKET, + FETCHING_TOKEN, + CONNECTING_CHANNEL, + + CONNECTED, +} + +export type Connection = { + socket: Socket; + channel: Channel | null; + token: string | null; + state: ConnectionState; + type: Type; +}; + +const connection: Connection = { + socket: new Socket("/socket", {}), + channel: null, + token: null, + state: ConnectionState.CONNECTING_SOCKET, + type: Type.NONE, +}; + +export async function start(type: Type.REQUEST | Type.SHARE) { + connection.type = type; + + await connectSocket(connection.socket); + + updateState(ConnectionState.FETCHING_TOKEN); + connection.token = await fetchToken(connection.socket); + + updateState(ConnectionState.CONNECTING_CHANNEL); + type === Type.SHARE + ? await startShare(connection) + : await startRequest(connection); +} + +export function send(event: string, data: any): Push { + if (connection.state !== ConnectionState.CONNECTED) { + throw new Error("There is no connection yet."); + } + + return connection.channel.push(event, data); +} + +export function getOwnToken(): string { + if (connection.state <= ConnectionState.FETCHING_TOKEN) { + throw new Error("There is no token yet."); + } + + return connection.token; +} + +function updateState(state: ConnectionState) { + // TODO: Notify state listeners + connection.state = state; +} diff --git a/assets/src/network/channel/request.ts b/assets/src/network/channel/request.ts new file mode 100644 index 0000000..801eee1 --- /dev/null +++ b/assets/src/network/channel/request.ts @@ -0,0 +1,14 @@ +import getShareToken from "../../utils/getShareToken"; +import type { Connection } from "./connection"; +import { joinRequestChannel } from "./socket"; + +export async function startRequest(connection: Connection) { + const requestChannel = await joinRequestChannel( + connection.socket, + connection.token, + getShareToken() + ); + connection.channel = requestChannel; + + // TODO: Handle incoming messages from the request channel +} diff --git a/assets/src/network/channel/share.ts b/assets/src/network/channel/share.ts new file mode 100644 index 0000000..10a34fa --- /dev/null +++ b/assets/src/network/channel/share.ts @@ -0,0 +1,17 @@ +import requests from "../../stores/requests"; +import type { Connection } from "./connection"; +import { joinShareChannel } from "./socket"; + +export async function startShare(connection: Connection) { + const shareChannel = await joinShareChannel( + connection.socket, + connection.token + ); + connection.channel = shareChannel; + + shareChannel.on("new_request", onNewRequest); +} + +function onNewRequest(data) { + requests.addRequest(data); +} diff --git a/assets/src/network/channel/socket.ts b/assets/src/network/channel/socket.ts new file mode 100644 index 0000000..7d14842 --- /dev/null +++ b/assets/src/network/channel/socket.ts @@ -0,0 +1,59 @@ +import type { Channel, Socket } from "phoenix"; + +export function connectSocket(socket: Socket): Promise { + return new Promise((resolve, _reject) => { + socket.connect(); + socket.onOpen(() => { + resolve(); + }); + }); +} + +export function fetchToken(socket: Socket): Promise { + let tokenChannel = socket.channel("token", {}); + return new Promise((resolve, reject) => { + tokenChannel + .join() + .receive("ok", () => { + tokenChannel + .push("get_token", {}, 5000) + .receive("ok", ({ token }) => resolve(token)) + .receive("error", err => reject(err)) + .receive("timeout", err => reject(err)); + }) + .receive("error", err => reject(err)); + }); +} + +export function joinShareChannel( + socket: Socket, + token: string +): Promise { + return joinChannel(socket, `share:${token}`); +} + +export function joinRequestChannel( + socket: Socket, + request_token: string, + share_token: string +): Promise { + return joinChannel(socket, `request:${request_token}`, { + share: share_token, + }); +} + +function joinChannel( + socket: Socket, + topic: string, + opts?: object +): Promise { + let channel = socket.channel(topic, opts); + + return new Promise((resolve, reject) => { + channel + .join() + .receive("ok", () => resolve(channel)) + .receive("error", err => reject(err)) + .receive("timeout", err => reject(err)); + }); +} diff --git a/assets/src/network/socket.ts b/assets/src/network/socket.ts deleted file mode 100644 index 87f5b7c..0000000 --- a/assets/src/network/socket.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Socket } from "phoenix"; -import requests from "../stores/requests"; - -let socket = new Socket("/socket", {}); -socket.connect(); - -export const getToken: () => Promise = () => { - let tokenChannel = socket.channel("token", {}); - return new Promise((resolve, reject) => { - tokenChannel - .join() - .receive("ok", () => { - tokenChannel - .push("get_token", {}, 5000) - .receive("ok", ({ token }) => resolve(token)) - .receive("error", err => reject(err)) - .receive("timeout", err => reject(err)); - }) - .receive("error", err => reject(err)); - }); -}; - -export const joinShareChannel = token => { - let shareChannel = socket.channel(`share:${token}`); - - shareChannel.on("new_request", requests.addRequest); - - shareChannel - .join() - .receive("error", err => - console.log("Failed joining share channel: " + JSON.stringify(err)) - ); -}; - -export const joinRequestChannel = (token, share) => { - let requestChannel = socket.channel(`request:${token}`, { share }); - - requestChannel - .join() - .receive("ok", () => console.log("Connected to request!")) - .receive("error", err => - console.log("Failed joining request channel:" + JSON.stringify(err)) - ); -}; -- cgit 1.4.1