diff --git a/src/common/axios.ts b/src/common/http.ts
similarity index 62%
rename from src/common/axios.ts
rename to src/common/http.ts
index 07e053f3..68072ba5 100644
--- a/src/common/axios.ts
+++ b/src/common/http.ts
@@ -14,34 +14,48 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import { AxiosInstance, AxiosRequestHeaders } from 'axios';
+import { AxiosInstance } from 'axios';
+import { RetryConfig } from 'retry-axios';
import { Readable } from 'stream';
+import { ReadableStream } from 'stream/web';
+import {
+ TurboHTTPServiceInterface,
+ TurboSignedRequestHeaders,
+} from '../types/turbo.js';
import { createAxiosInstance } from '../utils/axiosClient.js';
import { FailedRequestError } from '../utils/errors.js';
-export class TurboHTTPService implements TurboHTTPService {
+export class TurboHTTPService implements TurboHTTPServiceInterface {
protected axios: AxiosInstance;
- constructor({ url = 'https://payment.ardrive.dev', retryConfig }: any) {
+ constructor({
+ url,
+ retryConfig,
+ }: {
+ url: string;
+ retryConfig?: RetryConfig;
+ }) {
this.axios = createAxiosInstance({
axiosConfig: {
- baseURL: `${url}/v1`,
+ baseURL: url,
},
retryConfig,
});
}
async get({
- url,
+ endpoint,
+ allowedStatuses = [200, 202],
headers,
}: {
- url: string;
- headers?: Record;
+ endpoint: string;
+ allowedStatuses?: number[];
+ headers?: Partial;
}): Promise {
- const { status, statusText, data } = await this.axios.get(url, {
+ const { status, statusText, data } = await this.axios.get(endpoint, {
headers,
});
- if (status !== 200) {
+ if (!allowedStatuses.includes(status)) {
throw new FailedRequestError(status, statusText);
}
@@ -49,24 +63,25 @@ export class TurboHTTPService implements TurboHTTPService {
}
async post({
- url,
+ endpoint,
+ allowedStatuses = [200, 202],
headers,
data,
}: {
- url: string;
- headers: AxiosRequestHeaders;
- data: Readable | ReadableStream | Buffer;
+ endpoint: string;
+ allowedStatuses?: number[];
+ headers?: Partial & Record;
+ data: Readable | Buffer | ReadableStream;
}): Promise {
const {
status,
statusText,
data: response,
- } = await this.axios.post(url, {
+ } = await this.axios.post(endpoint, data, {
headers,
- data,
});
- if (status !== 200) {
+ if (!allowedStatuses.includes(status)) {
throw new FailedRequestError(status, statusText);
}
diff --git a/src/common/payment.ts b/src/common/payment.ts
index f159e677..55e4a254 100644
--- a/src/common/payment.ts
+++ b/src/common/payment.ts
@@ -14,8 +14,6 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import { AxiosInstance } from 'axios';
-
import {
Currency,
TurboAuthenticatedPaymentServiceInterface,
@@ -30,39 +28,27 @@ import {
TurboUnauthenticatedPaymentServiceInterfaceConfiguration,
TurboWalletSigner,
} from '../types/turbo.js';
-import { createAxiosInstance } from '../utils/axiosClient.js';
-import { FailedRequestError } from '../utils/errors.js';
+import { TurboHTTPService } from './http.js';
export class TurboUnauthenticatedPaymentService
implements TurboUnauthenticatedPaymentServiceInterface
{
- protected readonly axios: AxiosInstance;
+ protected readonly httpService: TurboHTTPService;
constructor({
url = 'https://payment.ardrive.dev',
retryConfig,
}: TurboUnauthenticatedPaymentServiceInterfaceConfiguration) {
- this.axios = createAxiosInstance({
- axiosConfig: {
- baseURL: `${url}/v1`,
- },
+ this.httpService = new TurboHTTPService({
+ url: `${url}/v1`,
retryConfig,
});
}
async getFiatRates(): Promise {
- const {
- status,
- statusText,
- data: rates,
- } = await this.axios.get('/rates');
-
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
-
- // TODO: should we return just the fiat rates instead of the whole response?
- return rates;
+ return this.httpService.get({
+ endpoint: '/rates',
+ });
}
async getFiatToAR({
@@ -70,45 +56,21 @@ export class TurboUnauthenticatedPaymentService
}: {
currency: Currency;
}): Promise {
- const {
- status,
- statusText,
- data: rate,
- } = await this.axios.get(`/rates/${currency}`);
-
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
-
- return rate;
+ return this.httpService.get({
+ endpoint: `/rates/${currency}`,
+ });
}
async getSupportedCountries(): Promise {
- const {
- status,
- statusText,
- data: countries,
- } = await this.axios.get('/countries');
-
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
-
- return countries;
+ return this.httpService.get({
+ endpoint: '/countries',
+ });
}
async getSupportedCurrencies(): Promise {
- const {
- status,
- statusText,
- data: currencies,
- } = await this.axios.get('/currencies');
-
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
-
- return currencies;
+ return this.httpService.get({
+ endpoint: '/currencies',
+ });
}
async getUploadCosts({
@@ -117,43 +79,19 @@ export class TurboUnauthenticatedPaymentService
bytes: number[];
}): Promise {
const fetchPricePromises = bytes.map((byteCount: number) =>
- this.axios.get(`/price/bytes/${byteCount}`),
+ this.httpService.get({
+ endpoint: `/price/bytes/${byteCount}`,
+ }),
);
- const responses = await Promise.all(fetchPricePromises);
- const wincCostsForBytes = responses.map(
- ({
- status,
- statusText,
- data,
- }: {
- status: number;
- statusText: string;
- data: TurboPriceResponse;
- }) => {
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
- return data;
- },
- );
-
+ const wincCostsForBytes: TurboPriceResponse[] =
+ await Promise.all(fetchPricePromises);
return wincCostsForBytes;
}
async getWincForFiat({ amount, currency }): Promise {
- const {
- status,
- statusText,
- data: wincForFiat,
- } = await this.axios.get(
- `/price/${currency}/${amount}`,
- );
-
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
-
- return wincForFiat;
+ return this.httpService.get({
+ endpoint: `/price/${currency}/${amount}`,
+ });
}
}
@@ -161,7 +99,7 @@ export class TurboUnauthenticatedPaymentService
export class TurboAuthenticatedPaymentService
implements TurboAuthenticatedPaymentServiceInterface
{
- protected readonly axios: AxiosInstance;
+ protected readonly httpService: TurboHTTPService;
protected readonly signer: TurboWalletSigner;
protected readonly publicPaymentService: TurboUnauthenticatedPaymentServiceInterface;
@@ -171,18 +109,15 @@ export class TurboAuthenticatedPaymentService
retryConfig,
signer,
}: TurboAuthenticatedPaymentServiceInterfaceConfiguration) {
- this.signer = signer;
- // TODO: abstract this away to TurboHTTPService class
- this.axios = createAxiosInstance({
- axiosConfig: {
- baseURL: `${url}/v1`,
- },
+ this.httpService = new TurboHTTPService({
+ url: `${url}/v1`,
retryConfig,
});
this.publicPaymentService = new TurboUnauthenticatedPaymentService({
url,
retryConfig,
});
+ this.signer = signer;
}
getFiatRates(): Promise {
@@ -214,25 +149,13 @@ export class TurboAuthenticatedPaymentService
async getBalance(): Promise {
const headers = await this.signer.generateSignedRequestHeaders();
-
- const {
- status,
- statusText,
- data: balance,
- } = await this.axios.get('/balance', {
+ const balance = await this.httpService.get({
+ endpoint: '/balance',
headers,
+ allowedStatuses: [200, 404],
});
- if (status === 404) {
- return {
- winc: '0',
- };
- }
-
- if (status !== 200) {
- throw new FailedRequestError(status, statusText);
- }
-
- return balance;
+ // 404's don't return a balance, so default to 0
+ return balance.winc ? balance : { winc: '0' };
}
}
diff --git a/src/common/upload.ts b/src/common/upload.ts
index 9c5dc2c4..bfba096b 100644
--- a/src/common/upload.ts
+++ b/src/common/upload.ts
@@ -14,8 +14,6 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import { AxiosInstance } from 'axios';
-
import {
TurboAuthenticatedUploadServiceConfiguration,
TurboAuthenticatedUploadServiceInterface,
@@ -26,23 +24,19 @@ import {
TurboUploadDataItemResponse,
TurboWalletSigner,
} from '../types/turbo.js';
-import { createAxiosInstance } from '../utils/axiosClient.js';
-import { FailedRequestError } from '../utils/errors.js';
+import { TurboHTTPService } from './http.js';
export class TurboUnauthenticatedUploadService
implements TurboUnauthenticatedUploadServiceInterface
{
- protected axios: AxiosInstance;
+ protected httpService: TurboHTTPService;
constructor({
url = 'https://upload.ardrive.dev',
retryConfig,
}: TurboUnauthenticatedUploadServiceInterfaceConfiguration) {
- // TODO: abstract to TurboHTTPRequestService class
- this.axios = createAxiosInstance({
- axiosConfig: {
- baseURL: `${url}/v1`,
- },
+ this.httpService = new TurboHTTPService({
+ url: `${url}/v1`,
retryConfig,
});
}
@@ -51,28 +45,20 @@ export class TurboUnauthenticatedUploadService
dataItemStreamFactory,
}: TurboSignedDataItemFactory): Promise {
// TODO: add p-limit constraint or replace with separate upload class
- const { status, data, statusText } =
- await this.axios.post(
- `/tx`,
- dataItemStreamFactory(),
- {
- headers: {
- 'content-type': 'application/octet-stream',
- },
- },
- );
-
- if (![202, 200].includes(status)) {
- throw new FailedRequestError(status, statusText);
- }
- return data;
+ return this.httpService.post({
+ endpoint: `/tx`,
+ data: dataItemStreamFactory(),
+ headers: {
+ 'content-type': 'application/octet-stream',
+ },
+ });
}
}
export class TurboAuthenticatedUploadService
implements TurboAuthenticatedUploadServiceInterface
{
- protected axios: AxiosInstance;
+ protected httpService: TurboHTTPService;
protected signer: TurboWalletSigner;
constructor({
@@ -80,11 +66,8 @@ export class TurboAuthenticatedUploadService
retryConfig,
signer,
}: TurboAuthenticatedUploadServiceConfiguration) {
- // TODO: abstract to TurboHTTPRequestService class
- this.axios = createAxiosInstance({
- axiosConfig: {
- baseURL: `${url}/v1`,
- },
+ this.httpService = new TurboHTTPService({
+ url: `${url}/v1`,
retryConfig,
});
this.signer = signer;
@@ -94,21 +77,13 @@ export class TurboAuthenticatedUploadService
dataItemStreamFactory,
}: TurboSignedDataItemFactory): Promise {
// TODO: add p-limit constraint or replace with separate upload class
- const { status, data, statusText } =
- await this.axios.post(
- `/tx`,
- dataItemStreamFactory(),
- {
- headers: {
- 'content-type': 'application/octet-stream',
- },
- },
- );
-
- if (![202, 200].includes(status)) {
- throw new FailedRequestError(status, statusText);
- }
- return data;
+ return this.httpService.post({
+ endpoint: `/tx`,
+ data: dataItemStreamFactory(),
+ headers: {
+ 'content-type': 'application/octet-stream',
+ },
+ });
}
async uploadFile({
@@ -118,20 +93,12 @@ export class TurboAuthenticatedUploadService
fileStreamFactory,
});
// TODO: add p-limit constraint or replace with separate upload class
- const { status, data, statusText } =
- await this.axios.post(
- `/tx`,
- signedDataItem,
- {
- headers: {
- 'content-type': 'application/octet-stream',
- },
- },
- );
-
- if (![202, 200].includes(status)) {
- throw new FailedRequestError(status, statusText);
- }
- return data;
+ return this.httpService.post({
+ endpoint: `/tx`,
+ data: signedDataItem,
+ headers: {
+ 'content-type': 'application/octet-stream',
+ },
+ });
}
}
diff --git a/src/types/turbo.ts b/src/types/turbo.ts
index dd534345..4007c802 100644
--- a/src/types/turbo.ts
+++ b/src/types/turbo.ts
@@ -114,6 +114,7 @@ export type FileStreamFactory =
export type SignedDataStreamFactory = FileStreamFactory;
export type TurboFileFactory = {
fileStreamFactory: FileStreamFactory; // TODO: allow multiple files
+ abortController?: AbortController;
// bundle?: boolean; // TODO: add bundling into BDIs
};
@@ -121,9 +122,27 @@ export type TurboSignedDataItemFactory = {
dataItemStreamFactory: SignedDataStreamFactory; // TODO: allow multiple data items
};
-export interface TurboHTTPRequestService {
- get(url: string): Promise;
- post(url: string, data: Readable | Buffer): Promise;
+export interface TurboHTTPServiceInterface {
+ get({
+ endpoint,
+ headers,
+ allowedStatuses,
+ }: {
+ endpoint: string;
+ headers?: Partial & Record;
+ allowedStatuses?: number[];
+ }): Promise;
+ post({
+ endpoint,
+ headers,
+ allowedStatuses,
+ data,
+ }: {
+ endpoint: string;
+ headers?: Partial & Record;
+ allowedStatuses?: number[];
+ data: Readable | ReadableStream | Buffer;
+ }): Promise;
}
export interface TurboWalletSigner {