UNPKG

pic-js-mops

Version:

An Internet Computer Protocol canister testing library for TypeScript and JavaScript.

144 lines 6.11 kB
import { ServerRequestTimeoutError } from './error.js'; import { isNil, poll } from './util/index.js'; export const JSON_HEADER = { 'Content-Type': 'application/json', }; export class Http2Client { baseUrl; processingTimeoutMs; constructor(baseUrl, processingTimeoutMs) { this.baseUrl = baseUrl; this.processingTimeoutMs = processingTimeoutMs; } request(init) { const timeoutAbortController = new AbortController(); const requestAbortController = new AbortController(); const cancelAfterTimeout = async () => { return await new Promise((_, reject) => { const timeoutId = setTimeout(() => { requestAbortController.abort(); reject(new ServerRequestTimeoutError()); }, this.processingTimeoutMs); timeoutAbortController.signal.addEventListener('abort', () => { clearTimeout(timeoutId); reject(new ServerRequestTimeoutError()); }); }); }; const makeRequest = async () => { const url = `${this.baseUrl}${init.path}`; const res = await fetch(url, { method: init.method, headers: init.headers, body: init.body, signal: requestAbortController.signal, }); timeoutAbortController.abort(); return res; }; return Promise.race([makeRequest(), cancelAfterTimeout()]); } async jsonGet(init) { // poll the request until it is successful or times out return await poll(async () => { const res = await this.request({ method: 'GET', path: init.path, headers: { ...init.headers, ...JSON_HEADER }, }); const resBody = await getResBody(res); if (isNil(resBody)) { return resBody; } // server encountered an error, throw and try again if ('message' in resBody) { console.error('PocketIC server encountered an error', resBody.message); throw new Error(resBody.message); } // the server has started processing or is busy if ('state_label' in resBody) { // the server is too busy to process the request, throw and try again if (res.status === 409) { throw new Error('Server busy'); } // the server has started processing the request // this shouldn't happen for GET requests, throw and try again if (res.status === 202) { throw new Error('Server started processing'); } // something weird happened, throw and try again throw new Error('Unknown state'); } // the request was successful, exit the loop return resBody; }, { intervalMs: POLLING_INTERVAL_MS, timeoutMs: this.processingTimeoutMs }); } async jsonPost(init) { const reqBody = init.body ? new TextEncoder().encode(JSON.stringify(init.body)) : undefined; // poll the request until it is successful or times out return await poll(async () => { const res = await this.request({ method: 'POST', path: init.path, headers: { ...init.headers, ...JSON_HEADER }, body: reqBody, }); const resBody = await getResBody(res); if (isNil(resBody)) { return resBody; } // server encountered an error, throw and try again if ('message' in resBody) { console.error('PocketIC server encountered an error', resBody.message); throw new Error(resBody.message); } // the server has started processing or is busy if ('state_label' in resBody) { // the server is too busy to process the request, throw and try again if (res.status === 409) { throw new Error('Server busy'); } // the server has started processing the request, poll until it is done if (res.status === 202) { return await poll(async () => { const stateRes = await this.request({ method: 'GET', path: `/read_graph/${resBody.state_label}/${resBody.op_id}`, }); const stateBody = (await stateRes.json()); // the server encountered an error, throw and try again if (isNil(stateBody) || 'message' in stateBody || 'state_label' in stateBody) { throw new Error('Polling has not succeeded yet'); } // the request was successful, exit the loop return stateBody; }, { intervalMs: POLLING_INTERVAL_MS, timeoutMs: this.processingTimeoutMs, }); } // something weird happened, throw and try again throw new Error('Unknown state'); } // the request was successful, exit the loop return resBody; }, { intervalMs: POLLING_INTERVAL_MS, timeoutMs: this.processingTimeoutMs }); } } async function getResBody(res) { try { return (await res.clone().json()); } catch (error) { const message = await res.text(); console.error('Error parsing PocketIC server response body:', error); console.error('Original body:', message); throw new Error(message); } } const POLLING_INTERVAL_MS = 10; //# sourceMappingURL=http2-client.js.map