import axios, { AxiosResponse } from 'axios'; export async function storeData(servers: string[], key: string, value: Buffer, ttl: number | null): Promise { for (const server of servers) { try { // Use key in the URL path instead of query parameters let url = `${server}/store/${key}`; // Add ttl as query parameter if provided if (ttl !== null) { const urlObj = new URL(url); 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) { // Handle both ArrayBuffer and Buffer (Node.js) if (response.data instanceof ArrayBuffer) { return response.data; } else if (Buffer.isBuffer(response.data)) { // Convert Buffer to ArrayBuffer return (response.data.buffer as ArrayBuffer).slice( response.data.byteOffset, response.data.byteOffset + response.data.byteLength ); } else if (response.data && typeof response.data === 'object' && 'buffer' in response.data) { // Handle Uint8Array or similar typed arrays const buffer = response.data.buffer; return (buffer as ArrayBuffer).slice( response.data.byteOffset, response.data.byteOffset + response.data.byteLength ); } else { console.error('Server returned unsupported data type:', typeof response.data, response.data?.constructor?.name); 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 { const response = await axios.get(`${server}/test/${key}`); 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; }