From 9aa1bf9c0e9670e85fe50f07ad7fb0cdfef19866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20D=C3=ADaz=20Gonz=C3=A1lez?= Date: Mon, 23 Dec 2024 22:25:06 +0000 Subject: [PATCH] refactor(web): migrate src/client to TypeScript --- web/src/client/{index.js => index.ts} | 57 +++++++++++++++++--------- web/src/client/{ws.js => ws.ts} | 58 +++++++++++++-------------- 2 files changed, 67 insertions(+), 48 deletions(-) rename web/src/client/{index.js => index.ts} (50%) rename web/src/client/{ws.js => ws.ts} (84%) diff --git a/web/src/client/index.js b/web/src/client/index.ts similarity index 50% rename from web/src/client/index.js rename to web/src/client/index.ts index 5e161ef5f3..dbead2a40d 100644 --- a/web/src/client/index.js +++ b/web/src/client/index.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) [2021-2023] SUSE LLC + * Copyright (c) [2021-2024] SUSE LLC * * All Rights Reserved. * @@ -20,28 +20,47 @@ * find current contact information at www.suse.com. */ -// @ts-check - +import { InstallationPhase, InstallerStatus } from "~/types/status"; import { WSClient } from "./ws"; -/** - * @typedef {object} InstallerClient - * @property {() => boolean} isConnected - determines whether the client is connected - * @property {() => boolean} isRecoverable - determines whether the client is recoverable after disconnected - * @property {(handler: () => void) => (() => void)} onConnect - registers a handler to run - * @property {(handler: () => void) => (() => void)} onDisconnect - registers a handler to run - * when the connection is lost. It returns a function to deregister the - * handler. - * @property {(handler: (any) => void) => (() => void)} onEvent - registers a handler to run on events - */ +export type AgamaMessageEvent = MessageEvent & { + path: string; + phase: InstallationPhase; + status: InstallerStatus; + service: string; +}; +type VoidFn = () => void; +type BooleanFn = () => boolean; +type EventHandlerFn = (event: AgamaMessageEvent) => void; + +export type InstallerClient = { + /** Whether the client is connected. */ + isConnected: BooleanFn; + /** Whether the client is recoverable after disconnecting. */ + isRecoverable: BooleanFn; + /** + * Registers a handler to run when connection is set. It returns a function + * for deregistering the handler. + */ + onConnect: (handler: VoidFn) => VoidFn; + /** + * Registers a handler to run when connection is lost. It returns a function + * for deregistering the handler. + */ + onDisconnect: (handler: VoidFn) => VoidFn; + /** + * Registers a handler to run on events. It returns a function for + * deregistering the handler. + */ + onEvent: (handler: EventHandlerFn) => VoidFn; +}; /** * Creates the Agama client * - * @param {URL} url - URL of the HTTP API. - * @return {InstallerClient} + * @param url - URL of the HTTP API. */ -const createClient = (url) => { +const createClient = (url: URL): InstallerClient => { url.hash = ""; url.pathname = url.pathname.concat("api/ws"); url.protocol = url.protocol === "http:" ? "ws" : "wss"; @@ -53,9 +72,9 @@ const createClient = (url) => { return { isConnected, isRecoverable, - onConnect: (handler) => ws.onOpen(handler), - onDisconnect: (handler) => ws.onClose(handler), - onEvent: (handler) => ws.onEvent(handler), + onConnect: (handler: VoidFn) => ws.onOpen(handler), + onDisconnect: (handler: VoidFn) => ws.onClose(handler), + onEvent: (handler: EventHandlerFn) => ws.onEvent(handler), }; }; diff --git a/web/src/client/ws.js b/web/src/client/ws.ts similarity index 84% rename from web/src/client/ws.js rename to web/src/client/ws.ts index b63c8e2a51..adfa60d3af 100644 --- a/web/src/client/ws.js +++ b/web/src/client/ws.ts @@ -20,19 +20,15 @@ * find current contact information at www.suse.com. */ -// @ts-check +import { AgamaMessageEvent } from "."; -/** - * @callback RemoveFn - * @return {void} - */ +type RemoveFn = () => void; +type BaseHandlerFn = () => void; +type EventHandlerFn = (event: AgamaMessageEvent) => void; /** * Enum for the WebSocket states. - * - * */ - const SocketStates = Object.freeze({ CONNECTED: 0, CONNECTING: 1, @@ -52,10 +48,25 @@ const ATTEMPT_INTERVAL = 1000; * HTTPClient API. */ class WSClient { + url: string; + + client: WebSocket; + + handlers: { + open: Array; + close: Array; + error: Array; + events: Array; + }; + + reconnectAttempts: number; + + timeout: ReturnType; + /** - * @param {URL} url - Websocket URL. + * @param url - Websocket URL. */ - constructor(url) { + constructor(url: URL) { this.url = url.toString(); this.handlers = { @@ -126,13 +137,10 @@ class WSClient { /** * Registers a handler for events. * - * The handler is executed for all the events. It is up to the callback to - * filter the relevant events. - * - * @param {(object) => void} func - Handler function to register. - * @return {RemoveFn} + * The handler is executed for all events. It is up to the callback to + * filter the relevant ones for it. */ - onEvent(func) { + onEvent(func: EventHandlerFn): RemoveFn { this.handlers.events.push(func); return () => { const position = this.handlers.events.indexOf(func); @@ -144,11 +152,8 @@ class WSClient { * Registers a handler for close socket. * * The handler is executed when the socket is close. - * - * @param {(object) => void} func - Handler function to register. - * @return {RemoveFn} */ - onClose(func) { + onClose(func: BaseHandlerFn): RemoveFn { this.handlers.close.push(func); return () => { @@ -161,10 +166,8 @@ class WSClient { * Registers a handler for open socket. * * The handler is executed when the socket is open. - * @param {(object) => void} func - Handler function to register. - * @return {RemoveFn} */ - onOpen(func) { + onOpen(func: BaseHandlerFn): RemoveFn { this.handlers.open.push(func); return () => { @@ -177,11 +180,8 @@ class WSClient { * Registers a handler for socket errors. * * The handler is executed when an error is reported by the socket. - * - * @param {(object) => void} func - Handler function to register. - * @return {RemoveFn} */ - onError(func) { + onError(func: BaseHandlerFn): RemoveFn { this.handlers.error.push(func); return () => { @@ -195,9 +195,9 @@ class WSClient { * * Dispatchs an event by running all the handlers. * - * @param {object} event - Event object, which is basically a websocket message. + * @param event - Event object, which is basically a websocket message. */ - dispatchEvent(event) { + dispatchEvent(event: MessageEvent) { const eventObject = JSON.parse(event.data); this.handlers.events.forEach((f) => f(eventObject)); }