import axios, { AxiosResponse } from 'axios'; export async function storeData(servers: string[], key: string, value: Blob, ttl: number | null): Promise { for (const server of servers) { try { // Handle relative paths (for development proxy) vs absolute URLs (for production) let url: string; if (server.startsWith('/')) { // Relative path - construct manually for proxy url = `${server}/store?key=${encodeURIComponent(key)}`; if (ttl !== null) { url += `&ttl=${ttl}`; } } else { // Absolute URL - use URL constructor const urlObj = new URL(`${server}/store`); urlObj.searchParams.append('key', key); if (ttl !== null) { urlObj.searchParams.append('ttl', ttl.toString()); } url = urlObj.toString(); } // Send the encrypted ArrayBuffer as the raw request body. const response = await axios.post(url, value, { headers: { 'Content-Type': 'application/octet-stream' }, }); console.log('Data stored successfully:', key); if (response.status !== 200) { console.error('Received response status', response.status); continue; } return response; } catch (error) { if (axios.isAxiosError(error) && error.response?.status === 409) { return null; } console.error('Error storing data:', error); } } return null; } export async function retrieveData(servers: string[], key: string): Promise { for (const server of servers) { try { // Handle relative paths (for development proxy) vs absolute URLs (for production) const url = server.startsWith('/') ? `${server}/retrieve/${key}` // Relative path - use as-is for proxy : new URL(`${server}/retrieve/${key}`).toString(); // Absolute URL - construct properly console.log('Retrieving data', key,' from:', url); // When fetching the data from the server: const response = await axios.get(url, { responseType: 'arraybuffer' }); if (response.status === 200) { // Validate that we received an ArrayBuffer if (response.data instanceof ArrayBuffer) { return response.data; } else { console.error('Server returned non-ArrayBuffer data:', typeof response.data); continue; } } else { console.error(`Server ${server} returned status ${response.status}`); continue; } } catch (error) { if (axios.isAxiosError(error)) { if (error.response?.status === 404) { console.log(`Data not found on server ${server} for key ${key}`); continue; // Try next server } else if (error.response?.status) { console.error(`Server ${server} error ${error.response.status}:`, error.response.statusText); continue; } else { console.error(`Network error connecting to ${server}:`, error.message); continue; } } else { console.error(`Unexpected error retrieving data from ${server}:`, error); continue; } } } return null; } interface TestResponse { key: string; value: boolean; } export async function testData(servers: string[], key: string): Promise | null> { const res: Record = {}; for (const server of servers) { res[server] = null; try { // Handle relative paths (for development proxy) vs absolute URLs (for production) const url = server.startsWith('/') ? `${server}/test/${key}` // Relative path - use as-is for proxy : new URL(`${server}/test/${key}`).toString(); // Absolute URL - construct properly const response = await axios.get(url); if (response.status !== 200) { console.error(`${server}: Test response status: ${response.status}`); continue; } const data: TestResponse = response.data; res[server] = data.value; } catch (error) { console.error('Error retrieving data:', error); return null; } } return res; }