162 lines
4.3 KiB
TypeScript
162 lines
4.3 KiB
TypeScript
import { create } from "zustand";
|
|
import { isNil } from "lodash";
|
|
import io from "socket.io-client";
|
|
import { SOCKET_BASE_URI } from "../constants/endpoints";
|
|
import { produce } from "immer";
|
|
import { QueryClient } from "@tanstack/react-query";
|
|
import { toast } from "react-toastify";
|
|
import "react-toastify/dist/ReactToastify.min.css";
|
|
|
|
/* Broadly, this file sets up:
|
|
* 1. The zustand-based global client state
|
|
* 2. socket.io client
|
|
*/
|
|
export const useStore = create((set, get) => ({
|
|
// Socket.io state
|
|
socketIOInstance: {},
|
|
// ComicVine Scraping status
|
|
comicvine: {
|
|
scrapingStatus: "",
|
|
},
|
|
|
|
// Import job queue and associated statuses
|
|
importJobQueue: {
|
|
successfulJobCount: 0,
|
|
failedJobCount: 0,
|
|
status: undefined,
|
|
setStatus: (status: string) =>
|
|
set(
|
|
produce((draftState) => {
|
|
draftState.importJobQueue.status = status;
|
|
}),
|
|
),
|
|
setJobCount: (jobType: string, count: Number) => {
|
|
switch (jobType) {
|
|
case "successful":
|
|
set(
|
|
produce((draftState) => {
|
|
draftState.importJobQueue.successfulJobCount = count;
|
|
}),
|
|
);
|
|
break;
|
|
|
|
case "failed":
|
|
set(
|
|
produce((draftState) => {
|
|
draftState.importJobQueue.failedJobCount = count;
|
|
}),
|
|
);
|
|
break;
|
|
}
|
|
},
|
|
mostRecentImport: null,
|
|
setMostRecentImport: (fileName: string) => {
|
|
set(
|
|
produce((state) => {
|
|
state.importJobQueue.mostRecentImport = fileName;
|
|
}),
|
|
);
|
|
},
|
|
},
|
|
}));
|
|
|
|
const { getState, setState } = useStore;
|
|
const queryClient = new QueryClient();
|
|
|
|
/** Socket.IO initialization **/
|
|
// 1. Fetch sessionId from localStorage
|
|
const sessionId = localStorage.getItem("sessionId");
|
|
// 2. socket.io instantiation
|
|
const socketIOInstance = io(SOCKET_BASE_URI, {
|
|
transports: ["websocket"],
|
|
withCredentials: true,
|
|
query: { sessionId },
|
|
});
|
|
// 3. Set the instance in global state
|
|
setState({
|
|
socketIOInstance,
|
|
});
|
|
|
|
// Socket.io-based session restoration
|
|
if (!isNil(sessionId)) {
|
|
// 1. Resume the session
|
|
socketIOInstance.emit(
|
|
"call",
|
|
"socket.resumeSession",
|
|
{
|
|
namespace: "/",
|
|
sessionId,
|
|
},
|
|
(data) => console.log(data),
|
|
);
|
|
} else {
|
|
// 1. Inititalize the session and persist the sessionId to localStorage
|
|
socketIOInstance.on("sessionInitialized", (sessionId) => {
|
|
localStorage.setItem("sessionId", sessionId);
|
|
});
|
|
}
|
|
// 2. If a job is in progress, restore the job counts and persist those to global state
|
|
socketIOInstance.on("RESTORE_JOB_COUNTS_AFTER_SESSION_RESTORATION", (data) => {
|
|
console.log("Active import in progress detected; restoring counts...");
|
|
const { completedJobCount, failedJobCount, queueStatus } = data;
|
|
setState((state) => ({
|
|
importJobQueue: {
|
|
...state.importJobQueue,
|
|
successfulJobCount: completedJobCount,
|
|
failedJobCount,
|
|
status: queueStatus,
|
|
},
|
|
}));
|
|
});
|
|
|
|
// 1a. Act on each comic issue successfully imported/failed, as indicated
|
|
// by the LS_COVER_EXTRACTED/LS_COVER_EXTRACTION_FAILED events
|
|
socketIOInstance.on("LS_COVER_EXTRACTED", (data) => {
|
|
const { completedJobCount, importResult } = data;
|
|
console.log(importResult);
|
|
setState((state) => ({
|
|
importJobQueue: {
|
|
...state.importJobQueue,
|
|
successfulJobCount: completedJobCount,
|
|
mostRecentImport: importResult.data.rawFileDetails.name,
|
|
},
|
|
}));
|
|
});
|
|
socketIOInstance.on("LS_COVER_EXTRACTION_FAILED", (data) => {
|
|
const { failedJobCount } = data;
|
|
setState((state) => ({
|
|
importJobQueue: {
|
|
...state.importJobQueue,
|
|
failedJobCount,
|
|
},
|
|
}));
|
|
});
|
|
|
|
socketIOInstance.on("searchResultsAvailable", (data) => {
|
|
console.log(data);
|
|
toast(`Results found for query: ${JSON.stringify(data.query, null, 2)}`);
|
|
});
|
|
|
|
// 1b. Clear the localStorage sessionId upon receiving the
|
|
// LS_IMPORT_QUEUE_DRAINED event
|
|
socketIOInstance.on("LS_IMPORT_QUEUE_DRAINED", (data) => {
|
|
localStorage.removeItem("sessionId");
|
|
setState((state) => ({
|
|
importJobQueue: {
|
|
...state.importJobQueue,
|
|
status: "drained",
|
|
},
|
|
}));
|
|
queryClient.invalidateQueries({ queryKey: ["allImportJobResults"] });
|
|
});
|
|
|
|
// ComicVine Scraping status
|
|
socketIOInstance.on("CV_SCRAPING_STATUS", (data) => {
|
|
setState((state) => ({
|
|
comicvine: {
|
|
...state.comicvine,
|
|
scrapingStatus: data.message,
|
|
},
|
|
}));
|
|
});
|