UNPKG

reduct-js

Version:

ReductStore Client SDK for Javascript/NodeJS/Typescript

116 lines (115 loc) 3.58 kB
import { Buffer } from "buffer"; /** * Represents a record in an entry for reading */ export class ReadableRecord { /** * Constructor which should be call from Bucket * @internal */ constructor(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; } /** * 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 */ export class WritableRecord { /** * 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 === undefined) { throw new Error("Size must be set for stream"); } } else if (data instanceof Buffer || typeof data === "string") { contentLength = BigInt(data.length); } else if (data["readable"] !== undefined) { // a hack for Node.js streams 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 === undefined) { throw new Error("Timestamp must be set"); } await this.httpClient.post(`/b/${bucketName}/${entryName}?ts=${options.ts}`, dataToSend, headers); } }