Skip to content

Commit

Permalink
refactor(web): remove the HTTPClient
Browse files Browse the repository at this point in the history
  • Loading branch information
imobachgs committed Sep 25, 2024
1 parent 87cb52b commit a607be4
Show file tree
Hide file tree
Showing 14 changed files with 29 additions and 187 deletions.
20 changes: 11 additions & 9 deletions web/src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@

// @ts-check

import { HTTPClient } from "./http";
import { WSClient } from "./ws";

/**
* @typedef {object} InstallerClient
* @property {() => import("./http").WSClient} ws - Agama WebSocket client.
* @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
*/

/**
Expand All @@ -42,18 +42,20 @@ import { HTTPClient } from "./http";
* @return {InstallerClient}
*/
const createClient = (url) => {
const client = new HTTPClient(url);
// TODO: unify with the manager client
url.hash = "";
url.pathname = url.pathname.concat("api/ws");
url.protocol = url.protocol === "http:" ? "ws" : "wss";
const _ws = new WSClient(url);

const isConnected = () => client.ws().isConnected() || false;
const isRecoverable = () => !!client.ws().isRecoverable();
const isConnected = () => _ws.isConnected() || false;
const isRecoverable = () => !!_ws.isRecoverable();

return {
isConnected,
isRecoverable,
onConnect: (handler) => client.ws().onOpen(handler),
onDisconnect: (handler) => client.ws().onClose(handler),
ws: () => client.ws(),
onConnect: (handler) => _ws.onOpen(handler),
onDisconnect: (handler) => _ws.onClose(handler),
onEvent: (handler) => _ws.onEvent(handler),
};
};

Expand Down
162 changes: 1 addition & 161 deletions web/src/client/http.js → web/src/client/ws.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,164 +230,4 @@ class WSClient {
}
}

/**
* Agama HTTP API client.
*/
class HTTPClient {
/**
* @param {URL} url - URL of the HTTP API.
*/
constructor(url) {
const httpUrl = new URL(url.toString());
httpUrl.pathname = url.pathname.concat("api");
this.baseUrl = httpUrl.toString();
this.url = url;
}

/**
* Return the websocket client
*
* The WSClient is lazily created in the first call of this method.
*
* @return {WSClient}
*/
ws() {
if (this._ws) return this._ws;

const wsUrl = new URL(this.url.toString());
wsUrl.pathname = wsUrl.pathname.concat("api/ws");
wsUrl.protocol = this.url.protocol === "http:" ? "ws" : "wss";
this._ws = new WSClient(wsUrl);
return this._ws;
}

/**
* @param {string} url - Endpoint URL (e.g., "/l10n/config").
* @return {Promise<Response>} Server response.
*/
async get(url) {
const response = await fetch(`${this.baseUrl}${url}`, {
headers: {
"Content-Type": "application/json",
},
});
return response;
}

/**
* @param {string} url - Endpoint URL (e.g., "/l10n/config").
* @param {object} data - Data to submit
* @return {Promise<Response>} Server response.
*/
async post(url, data) {
const response = await fetch(`${this.baseUrl}${url}`, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
});

return response;
}

/**
* @param {string} url - Endpoint URL (e.g., "/l10n/config").
* @param {object} data - Data to submit
* @return {Promise<Response>} Server response.
*/
async put(url, data) {
const response = await fetch(`${this.baseUrl}${url}`, {
method: "PUT",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
});

return response;
}

/**
* @param {string} url - Endpoint URL (e.g., "/l10n/config").
* @return {Promise<Response>} Server response.
*/
async delete(url) {
const response = await fetch(`${this.baseUrl}${url}`, {
method: "DELETE",
});

return response;
}

/**
* @param {string} url - Endpoint URL (e.g., "/l10n/config").
* @param {object} data - Data to submit
* @return {Promise<Response>} Server response.
*/
async patch(url, data) {
const response = await fetch(`${this.baseUrl}${url}`, {
method: "PATCH",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
});

return response;
}

/**
* Registers a handler for being called when the socket is closed
*
* @param {() => void} func - Handler function to register.
* @return {RemoveFn} - Function to remove the handler.
*/
onClose(func) {
return this.ws().onClose(() => {
func();
});
}

/**
*
* Registers a handler for being called when there is some error in the socket
*
* @param {(event: Object) => void} func - Handler function to register.
* @return {RemoveFn} - Function to remove the handler.
*/
onError(func) {
return this.ws().onError((event) => {
func(event);
});
}

/**
* Registers a handler for being called when the socket is opened
*
* @param {(event: Object) => void} func - Handler function to register.
* @return {RemoveFn} - Function to remove the handler.
*/
onOpen(func) {
return this.ws().onOpen((event) => {
func(event);
});
}

/**
* Registers a handler for a given type of events.
*
* @param {string} type - Event type (e.g., "LocaleChanged").
* @param {(event: Object) => void} func - Handler function to register.
* @return {RemoveFn} - Function to remove the handler.
*/
onEvent(type, func) {
return this.ws().onEvent((event) => {
if (event.type === type) {
func(event);
}
});
}
}

export { HTTPClient, WSClient };
export { WSClient };
2 changes: 1 addition & 1 deletion web/src/queries/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const useIssuesChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "IssuesChanged") {
const path = event.path;
const scope = scopesFromPath[path];
Expand Down
2 changes: 1 addition & 1 deletion web/src/queries/l10n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const useL10nConfigChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "L10nConfigChanged") {
queryClient.invalidateQueries({ queryKey: ["l10n/config"] });
}
Expand Down
2 changes: 1 addition & 1 deletion web/src/queries/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ const useNetworkConfigChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "NetworkChange") {
if (event.deviceRemoved || event.deviceAdded) {
queryClient.invalidateQueries({ queryKey: ["network"] });
Expand Down
2 changes: 1 addition & 1 deletion web/src/queries/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const useProgressChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "Progress") {
const service = servicesMap[event.service];
if (!service) {
Expand Down
2 changes: 1 addition & 1 deletion web/src/queries/questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const useQuestionsChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "QuestionsChanged") {
queryClient.invalidateQueries({ queryKey: ["questions"] });
}
Expand Down
4 changes: 2 additions & 2 deletions web/src/queries/software.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const useProductChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "ProductChanged") {
queryClient.invalidateQueries({ queryKey: ["software/config"] });
}
Expand All @@ -204,7 +204,7 @@ const useProposalChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "SoftwareProposalChanged") {
queryClient.invalidateQueries({ queryKey: ["software/proposal"] });
}
Expand Down
2 changes: 1 addition & 1 deletion web/src/queries/status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const useInstallerStatusChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
const { type } = event;
const data = queryClient.getQueryData(["status"]) as object;
if (!data) {
Expand Down
2 changes: 1 addition & 1 deletion web/src/queries/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ const useDeprecatedChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent(({ type, dirty: value }) => {
return client.onEvent(({ type, dirty: value }) => {
if (type === "DevicesDirty") {
queryClient.setQueryData(deprecatedQuery.queryKey, value);
}
Expand Down
4 changes: 2 additions & 2 deletions web/src/queries/storage/dasd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const useDASDFormatJobChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
// TODO: for simplicity we now just invalidate query instead of manually adding, removing or changing devices
switch (event.type) {
case "DASDFormatJobChanged": {
Expand Down Expand Up @@ -132,7 +132,7 @@ const useDASDDevicesChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
switch (event.type) {
case "DASDDeviceAdded": {
const device: DASDDevice = event.device;
Expand Down
4 changes: 2 additions & 2 deletions web/src/queries/storage/iscsi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const useInitiatorChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent(({ type, name, ibft }) => {
return client.onEvent(({ type, name, ibft }) => {
if (type !== "ISCSIInitiatorChanged") return;

queryClient.setQueryData(initiatorQuery.queryKey, (oldData: ISCSIInitiator | undefined) => {
Expand Down Expand Up @@ -102,7 +102,7 @@ const useNodesChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent(({ type, node }) => {
return client.onEvent(({ type, node }) => {
if (!["ISCSINodeAdded", "ISCSINodeChanged", "ISCSINodeRemoved"].includes(type)) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions web/src/queries/storage/zfcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const useZFCPControllersChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent(({ type, device }) => {
return client.onEvent(({ type, device }) => {
if (
!["ZFCPControllerAdded", "ZFCPControllerChanged", "ZFCPControllerRemoved"].includes(type)
) {
Expand Down Expand Up @@ -132,7 +132,7 @@ const useZFCPDisksChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent(({ type, device }) => {
return client.onEvent(({ type, device }) => {
if (!["ZFCPDiskAdded", "ZFCPDiskChanged", "ZFCPDiskRemoved"].includes(type)) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions web/src/queries/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const useFirstUserChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "FirstUserChanged") {
const { fullName, userName, password, autologin, data } = event;
queryClient.setQueryData(["users", "firstUser"], {
Expand Down Expand Up @@ -131,7 +131,7 @@ const useRootUserChanges = () => {
React.useEffect(() => {
if (!client) return;

return client.ws().onEvent((event) => {
return client.onEvent((event) => {
if (event.type === "RootChanged") {
const { password, sshkey } = event;
queryClient.setQueryData(["users", "root"], (oldRoot: RootUser) => {
Expand Down

0 comments on commit a607be4

Please sign in to comment.