From 9776c346bd7448009b60a7d4cdce40d68f69728f Mon Sep 17 00:00:00 2001 From: pociej Date: Mon, 20 May 2024 10:58:43 +0200 Subject: [PATCH] feat: use socket.io close #65 close #66 --- .vscode/settings.json | 8 +- backend/package.json | 4 +- backend/src/fastify.ts | 7 +- backend/src/services/payment/routes.ts | 3 +- backend/src/services/user/routes.ts | 95 +++++++++++++------ backend/src/services/user/service.ts | 2 +- backend/src/services/yagna/routes.ts | 19 ++-- backend/src/services/yagna/service.ts | 47 ++++++++- backend/src/socket.io.ts | 42 ++++++++ frontend/.env.development | 3 +- frontend/.env.production | 3 +- frontend/package.json | 1 + .../providers/blockchainProvider.tsx | 20 ++-- .../src/components/providers/fileUploader.tsx | 2 +- .../src/components/providers/userProvider.tsx | 4 +- frontend/src/hooks/useCreateAllocation.ts | 4 +- frontend/src/hooks/useLocalStorage.ts | 18 ++++ frontend/src/hooks/useLogin.ts | 17 ++-- frontend/src/hooks/useReleaseAgreement.ts | 2 +- frontend/src/hooks/useReleaseAllocation.ts | 4 +- .../src/hooks/useRequestorWalletAddress.ts | 2 +- frontend/src/hooks/useSaveDeposit.tsx | 2 +- frontend/src/hooks/useScanResults.tsx | 2 +- frontend/src/hooks/useSignNonce.ts | 17 ++-- frontend/src/hooks/useTopUpAllocation.ts | 2 +- frontend/src/hooks/useUploadFile.ts | 2 +- frontend/src/hooks/userUserData.ts | 55 ++++++----- pnpm-lock.yaml | 90 ++++++++++++++++++ yagna | 2 +- 29 files changed, 363 insertions(+), 116 deletions(-) create mode 100644 backend/src/socket.io.ts create mode 100644 frontend/src/hooks/useLocalStorage.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 255c123..95c78f2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,3 @@ { - "cSpell.words": [ - "Fastify", - "Siwe", - "viem" - ] -} \ No newline at end of file + "cSpell.words": ["Fastify", "Siwe", "socketio", "viem"] +} diff --git a/backend/package.json b/backend/package.json index 632d06c..ba36092 100644 --- a/backend/package.json +++ b/backend/package.json @@ -24,7 +24,7 @@ "@golem-sdk/task-executor": "workspace:*", "@types/jsonwebtoken": "^9.0.6", "@types/uuid": "^9.0.8", - "@types/ws": "^8.5.10", + "@types/ws": "^8.5.10", "awilix": "^10.0.1", "chalk": "^5.3.0", "dayjs": "^1.11.10", @@ -34,10 +34,12 @@ "ftp-srv": "^4.6.3", "js-big-decimal": "^2.0.7", "jsonwebtoken": "^9.0.2", + "jwt-decode": "^4.0.0", "loginWithCrypto": "workspace:*", "mongodb": "^6.3.0", "mongoose": "^8.2.0", "rxjs": "^7.8.1", + "socket.io": "^4.7.5", "uuid": "^9.0.1", "viem": "^2.7.22", "ya-ts-client": "workspace:*" diff --git a/backend/src/fastify.ts b/backend/src/fastify.ts index 1a3277f..871a014 100644 --- a/backend/src/fastify.ts +++ b/backend/src/fastify.ts @@ -10,7 +10,7 @@ import { FastifySSEPlugin } from "fastify-sse-v2"; import fastifyMultipart from "@fastify/multipart"; import { Yagna } from "./services/yagna/routes.js"; import websocket from "@fastify/websocket"; - +import socketioServer from "./socket.io.js"; export const startupFastifyServer = async (): Promise => { const fastify = Fastify({ logger: false, @@ -24,6 +24,11 @@ export const startupFastifyServer = async (): Promise => { fastify.register(fastifyMultipart); fastify.register(FastifySSEPlugin); fastify.register(websocket); + fastify.register(socketioServer, { + cors: { + origin: "*", + }, + }); fastify.register(cors, { origin: "*", }); diff --git a/backend/src/services/payment/routes.ts b/backend/src/services/payment/routes.ts index 04123fb..1e39e7e 100644 --- a/backend/src/services/payment/routes.ts +++ b/backend/src/services/payment/routes.ts @@ -18,7 +18,6 @@ export const paymentService = fastifyPlugin( //@ts-ignore TODO: add declaration in auth module so ts-ignore is not needed onRequest: [fastify.authenticate], handler: async (request, reply) => { - console.log("wtf creating deposit"); const paymentService = container.cradle.paymentService; // @ts-ignore // TODO: make sure request.body is the right type @@ -28,7 +27,7 @@ export const paymentService = fastifyPlugin( request.body.nonce ); - console.log("res",res); + console.log("res", res); return res; }, }); diff --git a/backend/src/services/user/routes.ts b/backend/src/services/user/routes.ts index c265708..a5c74d2 100644 --- a/backend/src/services/user/routes.ts +++ b/backend/src/services/user/routes.ts @@ -1,38 +1,75 @@ import fastify, { FastifyInstance, FastifyRequest } from "fastify"; import { container } from "../../di.js"; import fastifyPlugin from "fastify-plugin"; - +import { userModel } from "./model.js"; +import { jwtDecode } from "jwt-decode"; +import { set } from "mongoose"; export const userService = fastifyPlugin( (fastify: FastifyInstance, opts, done) => { - fastify.get("/me", { - onRequest: [fastify.authenticate], - handler: async (request: FastifyRequest, reply) => { - const userService = container.cradle.userService; - const requestUser = request.user; - const user = await userService.findById(requestUser._id); - if (!user) { - throw new Error(`User not found with id ${requestUser._id}`); - } - return { - walletAddress: user.walletAddress, - _id: user._id.toString(), - nonce: user.nonce.toString(), - currentAllocation: { - id: user.currentAllocationId, - }, - currentActivity: { - id: user.currentActivityId, - }, - deposits: user.deposits.map((d) => { - return { - isCurrent: d.isCurrent, - isValid: d.isValid, - nonce: d.nonce.toString(), - }; - }), - }; - }, + fastify.io.of("/me").use((socket, next) => { + const token = socket.handshake.auth.token; + if (!token) { + next(new Error("Authentication error")); + } + next(); }); + + fastify.io.of("/me").on("connection", async (socket) => { + console.log("socket", socket.handshake.auth.token); + + const user = jwtDecode<{ + _id: string; + }>(socket.handshake.auth.token); + + if (!user._id) { + throw new Error(`Wrong token`); + } + if (!user) { + throw new Error( + `User not found with id ${socket.handshake.auth.token}` + ); + } + + const userDTO = await container.cradle.userService.getUserDTO(user._id); + socket.emit("user", userDTO); + userModel + .watch( + [ + { + $match: { + _id: user._id, + }, + }, + ], + { + fullDocument: "updateLookup", + } + ) + .on("change", async () => { + const userDTO = await container.cradle.userService.getUserDTO( + user._id + ); + socket.emit("user", userDTO); + }); + }); + // fastify.get( + // "/me", + // { + // websocket: true, + // onRequest: [fastify.authenticate], + // }, + // async (socket, request) => { + // console.log("socket", request.user._id); + // const userService = container.cradle.userService; + // const requestUser = request.user; + // const user = await userService.findById(requestUser._id); + // console.log("user", user); + // if (!user) { + // throw new Error(`User not found with id ${requestUser._id}`); + // } + + // } + // ); done(); } ); diff --git a/backend/src/services/user/service.ts b/backend/src/services/user/service.ts index 8141a53..6c9f7f4 100644 --- a/backend/src/services/user/service.ts +++ b/backend/src/services/user/service.ts @@ -100,7 +100,7 @@ export const userService: IUserService = { }, addDeposit: async (userId: string, deposit: Deposit) => { - console.log("adding deposit"); + console.log("adding deposit"); await userModel.updateOne( { _id: userId }, { diff --git a/backend/src/services/yagna/routes.ts b/backend/src/services/yagna/routes.ts index 0195845..c15fe1f 100644 --- a/backend/src/services/yagna/routes.ts +++ b/backend/src/services/yagna/routes.ts @@ -8,15 +8,16 @@ export const Yagna = fastifyPlugin((fastify: FastifyInstance, opts, done) => { handler: async (request, reply) => { const requestUser = request.user; const Yagna = container.cradle.Yagna; - try { - await Yagna.createExecutor(requestUser._id); - } catch (e) { - console.log("error", e); - reply.code(500).send({ - message: "Unable to create executor", - }); - } - const allocation = await Yagna.getUserAllocation(requestUser._id); + // try { + // await Yagna.createExecutor(requestUser._id); + // } catch (e) { + // console.log("error", e); + // reply.code(500).send({ + // message: "Unable to create executor", + // }); + // } + const allocation = await Yagna.createUserAllocation(requestUser._id); + // const allocation = await Yagna.getUserAllocation(requestUser._id); if (!allocation) { reply.code(500).send({ message: "Unable to create allocation", diff --git a/backend/src/services/yagna/service.ts b/backend/src/services/yagna/service.ts index 5e540b8..690ead2 100644 --- a/backend/src/services/yagna/service.ts +++ b/backend/src/services/yagna/service.ts @@ -10,9 +10,9 @@ import bigDecimal from "js-big-decimal"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); import { Worker } from "./worker.js"; -import { WorkContext } from "@golem-sdk/golem-js" +import { WorkContext } from "@golem-sdk/golem-js"; import { TaskExecutor } from "@golem-sdk/task-executor"; -import { formatEther } from "viem"; +import { formatEther, parseEther } from "viem"; export class Yagna { public debitNoteEvents: Subject; private paymentService: YaTsClient.PaymentApi.RequestorService; @@ -80,6 +80,43 @@ export class Yagna { }).default; } + async createUserAllocation(userId: string) { + debugLog("payments", "creating user allocation", userId); + const userService = container.cradle.userService; + const userDeposit = await userService.getCurrentDeposit(userId); + + if (!userDeposit) { + throw new Error({ code: ErrorCode.NO_DEPOSIT }); + } + console.log("userDeposit", userDeposit); + try { + console.log("trying"); + //@ts-ignore + + const allocation = await this.paymentService.createAllocation({ + totalAmount: formatEther(userDeposit.amount), + makeDeposit: false, + deposit: { + contract: container.cradle.contractAddress, + id: userDeposit.id.toString(16), + validate: { + flatFeeAmount: parseEther("23").toString(), + }, + }, + }); + + console.log("allocation", allocation); + + container.cradle.userService.setCurrentAllocationId( + userId, + allocation.allocationId + ); + return allocation; + } catch (e) { + console.log("error", e); + } + // @ts-ignore + } async getUserAllocation(userId: string) { debugLog("payments", "getting user allocation", userId); const user = await container.cradle.userService.getUserById(userId); @@ -169,8 +206,8 @@ export class Yagna { agreementMaxPoolSize: 1, //@ts-ignore budget: formatEther(userDeposit.amount), - enableLogging : true, - subnetTag : 'pociej_own' + enableLogging: true, + subnetTag: "pociej_own", }); this.userContext.setExecutor(userId, executor); @@ -239,7 +276,7 @@ export class Yagna { }) .catch((e: any) => { console.log("Error", e); - reject(); + reject(); }); } }); diff --git a/backend/src/socket.io.ts b/backend/src/socket.io.ts new file mode 100644 index 0000000..60fd4ee --- /dev/null +++ b/backend/src/socket.io.ts @@ -0,0 +1,42 @@ +import { FastifyInstance, FastifyPluginAsync } from "fastify"; +import fp from "fastify-plugin"; +import { Server, ServerOptions } from "socket.io"; +import { IUser } from "./services/user/types.js"; + +const fastifySocketIO: FastifyPluginAsync> = fp( + async function (fastify, opts) { + const server = new Server< + {}, + { + user: () => void; + } + >({ + cors: { + origin: "*", + }, + }); + + server.listen(Number(process.env.PORT) || 5174); + + fastify.decorate("io", server); + + fastify.addHook("onClose", (fastify: FastifyInstance, done) => { + (fastify as any).io.close(); + done(); + }); + }, + { fastify: ">=4.x.x", name: "fastify-socket.io" } +); + +declare module "fastify" { + interface FastifyInstance { + io: Server< + {}, + { + user: (data: IUser) => void; + } + >; + } +} + +export default fastifySocketIO; diff --git a/frontend/.env.development b/frontend/.env.development index 0eb6119..823b146 100644 --- a/frontend/.env.development +++ b/frontend/.env.development @@ -1 +1,2 @@ -VITE_BACKEND_URL=http://127.0.0.1:5174/api +VITE_BACKEND_HTTP_URL=http://127.0.0.1:5174/api +VITE_BACKEND_WS_URL=127.0.0.1:5174 diff --git a/frontend/.env.production b/frontend/.env.production index d3f9829..db7bff0 100644 --- a/frontend/.env.production +++ b/frontend/.env.production @@ -1 +1,2 @@ -VITE_BACKEND_URL=http://0.0.0.0:5174/api +VITE_BACKEND_HTTP_URL=https://0.0.0.0:5174/api +VITE_BACKEND_WS_URL=wss://0.0.0.0:5174/api diff --git a/frontend/package.json b/frontend/package.json index f766e44..614c45d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,6 +28,7 @@ "react-daisyui": "^5.0.0", "react-dom": "^18.2.0", "siwe": "^2.3.2", + "socket.io-client": "^4.7.5", "swr": "^2.2.5", "ts-pattern": "^5.1.1", "usehooks-ts": "^3.1.0", diff --git a/frontend/src/components/providers/blockchainProvider.tsx b/frontend/src/components/providers/blockchainProvider.tsx index 324d569..de81d05 100644 --- a/frontend/src/components/providers/blockchainProvider.tsx +++ b/frontend/src/components/providers/blockchainProvider.tsx @@ -7,6 +7,7 @@ import { WagmiProvider } from "wagmi"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { PropsWithChildren } from "react"; import { config } from "config"; +import { holesky } from "viem/chains"; const queryClient = new QueryClient(); function sleep(ms: number) { @@ -39,11 +40,12 @@ function createMessage({ nonce, address, chainId }: any) { return message.prepareMessage(); } +// @ts-ignore const siweConfig = createSIWEConfig({ createMessage, getNonce: async (address) => { const response = await fetch( - `${import.meta.env.VITE_BACKEND_URL}/register`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/register`, { method: "POST", headers: { @@ -58,16 +60,18 @@ const siweConfig = createSIWEConfig({ } const responseData = await response.json(); + console.log("nonce", responseData.nonce.toString()); return responseData.nonce.toString(); }, getSession: async () => { return { - address: "0x8e2A131F99b4Dce031D3BceEb67b632c4d6C12fF", + address: "0xcC2f7D53e0c32B31d670efA7F5Ad01e581bB0A18", chainId: 1700, }; }, verifyMessage: async ({ message, signature }) => { - const res = await fetch(`${import.meta.env.VITE_BACKEND_URL}/login`, { + console.log("message", message); + const res = await fetch(`${import.meta.env.VITE_BACKEND_HTTP_URL}/login`, { method: "POST", headers: { "Content-Type": "application/json", @@ -86,16 +90,18 @@ const siweConfig = createSIWEConfig({ return true; }, - signOut: async () => { - return true; - }, - signOutOnNetworkChange: true, }); createWeb3Modal({ wagmiConfig, projectId: config.projectId, siweConfig, + tokens: { + [holesky.id]: { + address: config.GLMContractAddress[holesky.id], + image: "./favicon.svg", //optional + }, + }, themeVariables: { "--w3m-font-family": "Kanit-Light", "--w3m-accent": "#181ea9a6", diff --git a/frontend/src/components/providers/fileUploader.tsx b/frontend/src/components/providers/fileUploader.tsx index aa3a5dd..4bb1aa7 100644 --- a/frontend/src/components/providers/fileUploader.tsx +++ b/frontend/src/components/providers/fileUploader.tsx @@ -60,7 +60,7 @@ async function processFile( formData.append("file", file); const response = await axios.post( - `${import.meta.env.VITE_BACKEND_URL}/process-file`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/process-file`, formData, { headers: { diff --git a/frontend/src/components/providers/userProvider.tsx b/frontend/src/components/providers/userProvider.tsx index 6ad2046..9a50fe4 100644 --- a/frontend/src/components/providers/userProvider.tsx +++ b/frontend/src/components/providers/userProvider.tsx @@ -161,7 +161,7 @@ export const UserProvider = ({ children }: PropsWithChildren<{}>) => { const { login, tokens, isLoggingIn } = useLogin(); const chainId = useChainId(); const [currentDepositNonce, setCurrentDepositNonce] = useState(0); - const { userData, isLoading: isUserLoading } = useUserData(); + const { data: userData, isLoading: isUserLoading } = useUserData(); //TODO : get rid of const [isRegistered, setIsRegistered] = useState(false); @@ -199,7 +199,7 @@ export const UserProvider = ({ children }: PropsWithChildren<{}>) => { useEffect(() => { const currentDeposit = (userData?.deposits || []).find( - (deposit) => deposit.isCurrent + (deposit: { isCurrent: boolean }) => deposit.isCurrent ); if (!isUserLoading && userData?._id) { setIsRegistered(true); diff --git a/frontend/src/hooks/useCreateAllocation.ts b/frontend/src/hooks/useCreateAllocation.ts index 7a051d1..8714e1e 100644 --- a/frontend/src/hooks/useCreateAllocation.ts +++ b/frontend/src/hooks/useCreateAllocation.ts @@ -3,10 +3,10 @@ import useSWRMutation from "swr/mutation"; export const useCreateAllocation = () => { const { trigger, isMutating } = useSWRMutation( - `${import.meta.env.VITE_BACKEND_URL}/me`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/me`, function () { return axios.post( - `${import.meta.env.VITE_BACKEND_URL}/create-allocation` + `${import.meta.env.VITE_BACKEND_HTTP_URL}/create-allocation` ); } ); diff --git a/frontend/src/hooks/useLocalStorage.ts b/frontend/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..555fc66 --- /dev/null +++ b/frontend/src/hooks/useLocalStorage.ts @@ -0,0 +1,18 @@ +import { useSyncExternalStore } from "react"; +export const useLocalStorage = (key: string) => { + const setState = (newValue: any) => { + localStorage.setItem(key, newValue); + window.dispatchEvent(new StorageEvent("storage", { key, newValue })); + }; + + const getSnapshot = () => localStorage.getItem(key); + + const subscribe = (listener: () => void) => { + window.addEventListener("storage", listener); + return () => void window.removeEventListener("storage", listener); + }; + + const store = useSyncExternalStore(subscribe, getSnapshot); + + return [store, setState] as const; +}; diff --git a/frontend/src/hooks/useLogin.ts b/frontend/src/hooks/useLogin.ts index 24428ae..5d96d6d 100644 --- a/frontend/src/hooks/useLogin.ts +++ b/frontend/src/hooks/useLogin.ts @@ -11,13 +11,16 @@ async function login({ walletAddress: `0x${string}`; message: string; }): Promise<{ accessToken: string; refreshToken: string }> { - const response = await fetch(`${import.meta.env.VITE_BACKEND_URL}/login`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ walletAddress, messageSignature, message }), - }); + const response = await fetch( + `${import.meta.env.VITE_BACKEND_HTTP_URL}/login`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ walletAddress, messageSignature, message }), + } + ); if (!response.ok) throw new Error(`Error registering user: ${response.statusText}`); diff --git a/frontend/src/hooks/useReleaseAgreement.ts b/frontend/src/hooks/useReleaseAgreement.ts index dc7ee68..6f67610 100644 --- a/frontend/src/hooks/useReleaseAgreement.ts +++ b/frontend/src/hooks/useReleaseAgreement.ts @@ -3,7 +3,7 @@ import useSWRMutation from "swr/mutation"; export const useReleaseAgreement = () => { const { trigger } = useSWRMutation( - `${import.meta.env.VITE_BACKEND_URL}/release-agreement`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/release-agreement`, axios.post ); return { diff --git a/frontend/src/hooks/useReleaseAllocation.ts b/frontend/src/hooks/useReleaseAllocation.ts index f12d528..ec87295 100644 --- a/frontend/src/hooks/useReleaseAllocation.ts +++ b/frontend/src/hooks/useReleaseAllocation.ts @@ -3,10 +3,10 @@ import useSWRMutation from "swr/mutation"; export const useReleaseAllocation = () => { const { trigger } = useSWRMutation( - `${import.meta.env.VITE_BACKEND_URL}/me`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/me`, function () { return axios.post( - `${import.meta.env.VITE_BACKEND_URL}/release-allocation` + `${import.meta.env.VITE_BACKEND_HTTP_URL}/release-allocation` ); } ); diff --git a/frontend/src/hooks/useRequestorWalletAddress.ts b/frontend/src/hooks/useRequestorWalletAddress.ts index 47244f8..3ce8379 100644 --- a/frontend/src/hooks/useRequestorWalletAddress.ts +++ b/frontend/src/hooks/useRequestorWalletAddress.ts @@ -12,7 +12,7 @@ export const useRequestorWalletAddress = (): { } => { const { data, error, isLoading } = useSWR<{ data: { wallet: `0x${string}` }; - }>(`${import.meta.env.VITE_BACKEND_URL}/requestor`, axios.get); + }>(`${import.meta.env.VITE_BACKEND_HTTP_URL}/requestor`, axios.get); return { data: { wallet: data?.data.wallet }, error, diff --git a/frontend/src/hooks/useSaveDeposit.tsx b/frontend/src/hooks/useSaveDeposit.tsx index 9fe687c..e7ce256 100644 --- a/frontend/src/hooks/useSaveDeposit.tsx +++ b/frontend/src/hooks/useSaveDeposit.tsx @@ -10,7 +10,7 @@ async function saveDeposit({ nonce: number; }): Promise<{ result: boolean }> { const response = await fetch( - `${import.meta.env.VITE_BACKEND_URL}/create-deposit`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/create-deposit`, { method: "POST", headers: { diff --git a/frontend/src/hooks/useScanResults.tsx b/frontend/src/hooks/useScanResults.tsx index 7b0aa59..f07d200 100644 --- a/frontend/src/hooks/useScanResults.tsx +++ b/frontend/src/hooks/useScanResults.tsx @@ -7,7 +7,7 @@ export const useScanResults = () => { const { removeFile } = useFileUploader(); const { data, error } = useSWRSubscription("scanResult", (key, { next }) => { const eventSource = new WebSocket( - `${import.meta.env.VITE_BACKEND_URL.replace("http", "ws")}/scan-result` + `${import.meta.env.VITE_BACKEND_HTTP_URL.replace("http", "ws")}/scan-result` ); eventSource.addEventListener("message", (event) => { diff --git a/frontend/src/hooks/useSignNonce.ts b/frontend/src/hooks/useSignNonce.ts index f979d57..9241b10 100644 --- a/frontend/src/hooks/useSignNonce.ts +++ b/frontend/src/hooks/useSignNonce.ts @@ -8,13 +8,16 @@ async function signNonce({ }: { walletAddress: `0x${string}`; }): Promise<{ nonce: number }> { - const response = await fetch(`${import.meta.env.VITE_BACKEND_URL}/register`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ walletAddress }), - }); + const response = await fetch( + `${import.meta.env.VITE_BACKEND_HTTP_URL}/register`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ walletAddress }), + } + ); if (!response.ok) throw new Error(`Error registering user: ${response.statusText}`); diff --git a/frontend/src/hooks/useTopUpAllocation.ts b/frontend/src/hooks/useTopUpAllocation.ts index 1ece8b3..8a4beba 100644 --- a/frontend/src/hooks/useTopUpAllocation.ts +++ b/frontend/src/hooks/useTopUpAllocation.ts @@ -3,7 +3,7 @@ import useSWRMutation from "swr/mutation"; export const useTopUpAllocation = () => { const { trigger, isMutating } = useSWRMutation( - `${import.meta.env.VITE_BACKEND_URL}/top-up-allocation`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/top-up-allocation`, (url, { arg: amount }: { arg: number }) => { return axios.put(url, { amount }); } diff --git a/frontend/src/hooks/useUploadFile.ts b/frontend/src/hooks/useUploadFile.ts index f734c92..ad621e1 100644 --- a/frontend/src/hooks/useUploadFile.ts +++ b/frontend/src/hooks/useUploadFile.ts @@ -35,7 +35,7 @@ async function processFile( formData.append("file", file); const response = await axios.post( - `${import.meta.env.VITE_BACKEND_URL}/process-file`, + `${import.meta.env.VITE_BACKEND_HTTP_URL}/process-file`, formData, { headers: { diff --git a/frontend/src/hooks/userUserData.ts b/frontend/src/hooks/userUserData.ts index bc5dd5b..872edb4 100644 --- a/frontend/src/hooks/userUserData.ts +++ b/frontend/src/hooks/userUserData.ts @@ -1,32 +1,37 @@ -import useSWR from "swr"; +import useSWRSubscription from "swr/subscription"; +import { io } from "socket.io-client"; +import { useEffect, useState } from "react"; +import { useLocalStorage } from "./useLocalStorage"; -import { UserData } from "types/user"; -const fetcher = (url: string) => - fetch(url, { - headers: { - Authorization: `Bearer ${localStorage.getItem("accessToken")}`, - }, - }) - .then((res) => { - return res.json(); - }) - .catch((error) => { - console.error("Error fetching user data", error); +const socket = io(`http://localhost:5174/me`, { + autoConnect: false, +}); + +export const useUserData = () => { + const [isLoading, setIsLoading] = useState(true); + const [accessToken] = useLocalStorage("accessToken"); + + useEffect(() => { + if (accessToken) { + socket.auth = { token: accessToken }; + socket.connect(); + } + }, [accessToken]); + + const { data, error } = useSWRSubscription("userData", (key, { next }) => { + socket.on("user", (data) => { + setIsLoading(false); + next(null, data); }); -export const useUserData = (): { - userData?: UserData; - error?: Error; - isLoading: boolean; -} => { - const { data, error, isLoading } = useSWR( - `${import.meta.env.VITE_BACKEND_URL}/me`, - fetcher, - { refreshInterval: 10000 } - ); + return () => { + socket.disconnect(); + }; + }); + return { - userData: data, + isLoading, + data: data || [], error, - isLoading: isLoading, }; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0b1c7af..46ad108 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,6 +84,9 @@ importers: jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 + jwt-decode: + specifier: ^4.0.0 + version: 4.0.0 loginWithCrypto: specifier: workspace:* version: link:../loginWithCrypto @@ -96,6 +99,9 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 + socket.io: + specifier: ^4.7.5 + version: 4.7.5 uuid: specifier: ^9.0.1 version: 9.0.1 @@ -178,6 +184,9 @@ importers: siwe: specifier: ^2.3.2 version: 2.3.2(ethers@6.12.1) + socket.io-client: + specifier: ^4.7.5 + version: 4.7.5(bufferutil@4.0.8)(utf-8-validate@6.0.3) swr: specifier: ^2.2.5 version: 2.2.5(react@18.2.0) @@ -5263,10 +5272,20 @@ packages: '@types/node': 20.12.4 dev: true + /@types/cookie@0.4.1: + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + dev: false + /@types/cookiejar@2.1.5: resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} dev: true + /@types/cors@2.8.17: + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + dependencies: + '@types/node': 20.12.4 + dev: false + /@types/debug@4.1.12: resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: @@ -7002,6 +7021,11 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + /base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + dev: false + /bcrypt-pbkdf@1.0.2: resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} dependencies: @@ -7823,6 +7847,11 @@ packages: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} dev: true + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: false + /cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -7844,6 +7873,14 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + /cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: false + /cosmiconfig-typescript-loader@5.0.0(@types/node@20.12.4)(cosmiconfig@8.3.6)(typescript@5.4.3): resolution: {integrity: sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==} engines: {node: '>=v16'} @@ -8484,6 +8521,26 @@ packages: engines: {node: '>=10.0.0'} dev: false + /engine.io@6.5.4: + resolution: {integrity: sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==} + engines: {node: '>=10.2.0'} + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.17 + '@types/node': 20.12.4 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.2 + cors: 2.8.5 + debug: 4.3.4(supports-color@8.1.1) + engine.io-parser: 5.2.2 + ws: 8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /enhanced-resolve@5.16.0: resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==} engines: {node: '>=10.13.0'} @@ -11346,6 +11403,11 @@ packages: safe-buffer: 5.2.1 dev: false + /jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + dev: false + /kareem@2.6.0: resolution: {integrity: sha512-B9wwgyKKKZkxYZXQzefvb/Ykh9eHixxR+ttTP2c/Pq8NvHi1iYIAImf3nj/DXkPcnenjGEffhPWXnCFRIbNAhw==} engines: {node: '>=12.0.0'} @@ -14694,6 +14756,17 @@ packages: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} dev: true + /socket.io-adapter@2.5.4: + resolution: {integrity: sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==} + dependencies: + debug: 4.3.4(supports-color@8.1.1) + ws: 8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /socket.io-client@4.7.5(bufferutil@4.0.8)(utf-8-validate@6.0.3): resolution: {integrity: sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==} engines: {node: '>=10.0.0'} @@ -14718,6 +14791,23 @@ packages: - supports-color dev: false + /socket.io@4.7.5: + resolution: {integrity: sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==} + engines: {node: '>=10.2.0'} + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.4(supports-color@8.1.1) + engine.io: 6.5.4 + socket.io-adapter: 2.5.4 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /socks-proxy-agent@7.0.0: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} diff --git a/yagna b/yagna index 0905043..620f644 160000 --- a/yagna +++ b/yagna @@ -1 +1 @@ -Subproject commit 0905043dc3ce089da6331827f21665673caddfd2 +Subproject commit 620f64494df3448f11f0b129274f5b3d04d44bda