/* This file is part of GNU Taler (C) 2021-2024 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ /** * * @author Sebastian Javier Marchano (sebasjm) * @author Nic Eigel */ import { HttpResponse, HttpResponseOk, RequestError, RequestOptions, useApiContext, } from "@gnu-taler/web-util/browser"; import {useCallback, useEffect, useState} from "preact/hooks"; import {useSWRConfig} from "swr"; import { useBackendContext } from "../context/backend.js"; import { AuditorBackend } from "../declaration.js"; export function useMatchMutate(): ( re?: RegExp, value?: unknown, ) => Promise { const {cache, mutate} = useSWRConfig(); if (!(cache instanceof Map)) { throw new Error( "matchMutate requires the cache provider to be a Map instance", ); } return function matchRegexMutate(re?: RegExp) { return mutate((key) => { // evict if no key or regex === all if (!key || !re) return true // match string if (typeof key === 'string' && re.test(key)) return true // record or object have the path at [0] if (typeof key === 'object' && re.test(key[0])) return true //key didn't match regex return false }, undefined, { revalidate: true, }); }; } const CHECK_CONFIG_INTERVAL_OK = 5 * 60 * 1000; const CHECK_CONFIG_INTERVAL_FAIL = 2 * 1000; export function useBackendConfig(): HttpResponse< AuditorBackend.VersionResponse | undefined, RequestError > { const {request} = useBackendBaseRequest(); type Type = AuditorBackend.VersionResponse; type State = { data: HttpResponse>, timer: number } const [result, setResult] = useState({data: {loading: true}, timer: 0}); useEffect(() => { if (result.timer) { clearTimeout(result.timer); } function tryConfig(): void { request(`/config`) .then((data) => { const timer: any = setTimeout(() => { tryConfig(); }, CHECK_CONFIG_INTERVAL_OK); setResult({data, timer}); }) .catch((error) => { const timer: any = setTimeout(() => { tryConfig(); }, CHECK_CONFIG_INTERVAL_FAIL); const data = error.cause; setResult({data, timer}); }); } tryConfig(); }, [request]); return result.data; } export function useBackendToken(): HttpResponse< AuditorBackend.VersionResponse, RequestError > { const {request} = useBackendBaseRequest(); type Type = AuditorBackend.VersionResponse; type State = { data: HttpResponse>, timer: number } const [result, setResult] = useState({data: {loading: true}, timer: 0}); useEffect(() => { if (result.timer) { clearTimeout(result.timer); } function tryToken(): void { request(`/monitoring/balances`) .then((data) => { const timer: any = setTimeout(() => { tryToken(); }, CHECK_CONFIG_INTERVAL_OK); setResult({data, timer}); }) .catch((error) => { const timer: any = setTimeout(() => { tryToken(); }, CHECK_CONFIG_INTERVAL_FAIL); const data = error.cause; setResult({data, timer}); }); } tryToken(); }, [request]); return result.data; } interface useBackendInstanceRequestType { request: ( endpoint: string, options?: RequestOptions, ) => Promise>; fetcher: (endpoint: string) => Promise>; multiFetcher: (params: string[]) => Promise[]>; depositConfirmationFetcher: ( params: [ endpoint: string, ], ) => Promise>; } interface useBackendBaseRequestType { request: ( endpoint: string, options?: RequestOptions ) => Promise>; } type YesOrNo = "yes" | "no"; /** * * @param root the request is intended to the base URL and no the instance URL * @returns request handler to */ //TODO: Add token export function useBackendBaseRequest(): useBackendBaseRequestType { const {url: backend} = useBackendContext(); const {request: requestHandler} = useApiContext(); //const { token } = useBackendTokenContext(); const token = "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"; const request = useCallback( function requestImpl( endpoint: string, //todo: remove options: RequestOptions = {}, ): Promise> { return requestHandler(backend, endpoint, {...options, token}).then(res => { return res; }).catch(err => { throw err; }); }, [backend], ); return {request}; } export function useBackendRequest(): useBackendInstanceRequestType { const {url: rootBackendUrl} = useBackendContext(); // const {id} = useInstanceContext(); const {request: requestHandler} = useApiContext(); //TODO: check const baseUrl = "http://localhost:8083/"; const token = "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"; const request = useCallback( function requestImpl( endpoint: string, options: RequestOptions = {}, ): Promise> { return requestHandler(baseUrl, endpoint, {...options, token}); }, [baseUrl], ); const multiFetcher = useCallback( function multiFetcherImpl( params: string[], options: RequestOptions = {}, ): Promise[]> { return Promise.all( params.map((endpoint) => requestHandler(baseUrl, endpoint, {...options, token}), ), ); }, [baseUrl], ); const fetcher = useCallback( function fetcherImpl(endpoint: string): Promise> { return requestHandler(baseUrl, endpoint, {token}); }, [baseUrl], ); const depositConfirmationFetcher = useCallback( function orderFetcherImpl( args: [endpoint: string, ], ): Promise> { const [endpoint] = args; const params: any = {"token": "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"}; return requestHandler(baseUrl, endpoint, {params, token}); }, [baseUrl], ); return { request, fetcher, depositConfirmationFetcher, multiFetcher }; }