reduct-js
Version:
ReductStore Client SDK for Javascript/NodeJS/Typescript
100 lines (99 loc) • 2.96 kB
JavaScript
import { Buffer } from "buffer";
//#region src/Record.ts
var isNodeReadableLike = (value) => {
if (!value || typeof value !== "object") return false;
const stream = value;
return typeof stream.readable === "boolean" && typeof stream.read === "function";
};
/**
* Represents a record in an entry for reading
*/
var ReadableRecord = class {
/**
* Constructor which should be call from Bucket
* @internal
*/
constructor(entry, time, size, last, head, stream, labels, contentType) {
this.labels = {};
this.time = time;
this.size = size;
this.last = last;
this.stream = stream;
this.labels = labels;
this.contentType = contentType;
this.entry = entry;
}
/**
* Read content of record
*/
async read() {
const reader = this.stream.getReader();
const chunks = [];
let done = false;
while (!done) {
const { value, done: isDone } = await reader.read();
done = isDone;
if (value) chunks.push(value);
}
const total = chunks.reduce((n, c) => n + c.length, 0);
const out = new Uint8Array(total);
let offset = 0;
for (const c of chunks) {
out.set(c, offset);
offset += c.length;
}
return Buffer.from(out);
}
/**
* Read content of record and convert to string
*/
async readAsString() {
return new TextDecoder().decode(await this.read());
}
};
/**
* Represents a record in an entry for writing
*/
var WritableRecord = class {
/**
* Constructor for stream
* @internal
*/
constructor(bucketName, entryName, options, httpClient) {
this.bucketName = bucketName;
this.entryName = entryName;
this.httpClient = httpClient;
this.options = options;
}
/**
* Write data to record asynchronously
* @param data stream or buffer with data
* @param size size of data in bytes (only for streams)
*/
async write(data, size) {
let contentLength = BigInt(size ?? 0);
let dataToSend = data;
if (data instanceof ReadableStream) {
if (size === void 0) throw new Error("Size must be set for stream");
} else if (data instanceof Buffer || typeof data === "string") contentLength = BigInt(data.length);
else if (isNodeReadableLike(data)) {
const stream = data;
if (stream.readable) dataToSend = new ReadableStream({ async pull(controller) {
const chunk = stream.read();
if (chunk) controller.enqueue(chunk);
else controller.close();
} });
else throw new Error("Invalid stream");
} else throw new Error("Invalid data type");
const { bucketName, entryName, options } = this;
const headers = {
"Content-Type": options.contentType ?? "application/octet-stream",
"Content-Length": contentLength.toString()
};
for (const [key, value] of Object.entries(options.labels ?? {})) headers[`x-reduct-label-${key}`] = value.toString();
if (options.ts === void 0) throw new Error("Timestamp must be set");
await this.httpClient.post(`/b/${bucketName}/${entryName}?ts=${options.ts}`, dataToSend, headers);
}
};
//#endregion
export { ReadableRecord, WritableRecord };