@inweb/client
Version:
JavaScript REST API client for the Open Cloud Server
186 lines (174 loc) • 6.61 kB
text/typescript
///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
// This application incorporates Open Design Alliance software pursuant to a
// license agreement with Open Design Alliance.
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
// All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
import { IHttpClient } from "./IHttpClient";
import { $fetch } from "./Fetch";
import { $xmlhttp } from "./XMLHttp";
export class HttpClient implements IHttpClient {
public serverUrl: string;
public headers: HeadersInit = {};
public signInUserId = "";
public signInUserIsAdmin = false;
constructor(serverUrl: string) {
this.serverUrl = serverUrl;
}
get(relativePath: string, init: RequestInit = {}): Promise<Response> {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "GET",
headers: { ...this.headers, ...init.headers },
});
}
post(relativePath: string, body?: BodyInit | object, init: RequestInit = {}): Promise<Response> {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "POST",
headers: { ...this.headers, ...init.headers },
body,
});
}
put(relativePath: string, body?: BodyInit | object, init: RequestInit = {}): Promise<Response> {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "PUT",
headers: { ...this.headers, ...init.headers },
body,
});
}
delete(relativePath: string, init: RequestInit = {}): Promise<Response> {
return $fetch(`${this.serverUrl}${relativePath}`, {
...init,
method: "DELETE",
headers: { ...this.headers, ...init.headers },
});
}
uploadFile(
relativePath: string,
file: File,
onProgress?: (progress: number) => void,
init: RequestInit = {}
): Promise<XMLHttpRequest> {
const data = new FormData();
data.append("file", file);
return $xmlhttp(`${this.serverUrl}${relativePath}`, {
method: "POST",
headers: { ...this.headers, ...init.headers },
body: data,
uploadProgress: onProgress,
});
}
// async downloadFile(
// relativePath: string,
// onProgress?: (progress: number, chunk: Uint8Array) => void,
// init: RequestInit = {}
// ): Promise<Response> {
// const response = await this.get(relativePath, init);
// const teedOff = response.body.tee();
// if (onProgress) {
// const contentLength = response.headers.get("Content-Length");
// const total = parseInt(contentLength, 10) || 1;
// let loaded = 0;
// const reader = teedOff[0].getReader();
// reader.read().then(function processChunk({ done, value }) {
// if (done) return;
// loaded += value.length;
// onProgress(loaded / total, value);
// reader.read().then(processChunk);
// });
// }
// return new Response(teedOff[1]);
// }
async downloadFile(
relativePath: string,
onProgress?: (progress: number, chunk: Uint8Array) => void,
init: RequestInit = {}
): Promise<Response> {
const response = await this.get(relativePath, init);
const contentLength = response.headers.get("Content-Length");
const total = parseInt(contentLength || "", 10) || 1;
return new Response(
new ReadableStream({
async start(controller) {
const reader = response.body.getReader();
let loaded = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
controller.enqueue(value);
loaded += value.length;
if (onProgress) onProgress(loaded / total, value);
}
controller.close();
},
})
);
}
async downloadFileRange(
relativePath: string,
reserved: number,
ranges: Array<{ begin: number; end: number; requestId: number }>,
onProgress?: (progress: number, chunk: Uint8Array, requestId: number) => void,
init: RequestInit = {}
): Promise<Response> {
const headers = { ...init.headers };
headers["Range"] = "bytes=" + ranges.map((x) => `${x.begin}-${x.end}`).join(",");
const response = await this.get(relativePath, { ...init, headers });
const contentLength = response.headers.get("content-length");
const total = parseInt(contentLength || "", 10) || 1;
return new Response(
new ReadableStream({
async start(controller) {
const reader = response.body.getReader();
let loaded = 0;
let rangedIndex = 0;
let rangePos = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
controller.enqueue(value);
loaded += value.length;
let chunkLeft = value.length;
let chunkPos = 0;
while (chunkLeft > 0) {
const range = ranges[rangedIndex];
const rangeLeft = range.end - range.begin - rangePos;
if (chunkLeft < rangeLeft) {
const chunk = value.subarray(chunkPos, chunkPos + chunkLeft);
if (onProgress) onProgress(loaded / total, chunk, range.requestId);
rangePos += chunkLeft;
chunkLeft = 0;
} else {
const chunk = value.subarray(chunkPos, chunkPos + rangeLeft);
if (onProgress) onProgress(loaded / total, chunk, range.requestId);
chunkPos += rangeLeft;
chunkLeft -= rangeLeft;
rangedIndex++;
rangePos = 0;
}
}
}
controller.close();
},
})
);
}
}