@zenfs/core
Version:
A filesystem, anywhere
129 lines (128 loc) • 3.7 kB
JavaScript
import { Errno, Exception, UV } from 'kerium';
import { warn } from 'kerium/log';
import { Readable, Writable } from 'readable-stream';
/**
* A ReadStream implementation that wraps an underlying global ReadableStream.
*/
export class ReadStream extends Readable {
pending = true;
_path = '<unknown>';
_bytesRead = 0;
reader;
ready;
constructor(opts = {}, handleOrPromise) {
super({ ...opts, encoding: opts.encoding ?? undefined });
this.ready = Promise.resolve(handleOrPromise)
.then(handle => {
this._path = handle['vfs'].path;
const internal = handle.readableWebStream({ start: opts.start, end: opts.end });
this.reader = internal.getReader();
this.pending = false;
})
.catch(err => {
this.destroy(err);
});
}
async _read() {
try {
await this.ready;
if (!this.reader)
return;
const { done, value } = await this.reader.read();
if (done) {
this.push(null);
return;
}
this._bytesRead += value.byteLength;
this.push(value);
}
catch (err) {
this.destroy(new Exception(Errno.EIO, err.toString()));
}
}
close(callback = () => null) {
try {
this.destroy();
this.emit('close');
callback(null);
}
catch (err) {
callback(new Exception(Errno.EIO, err.toString()));
}
}
get path() {
return this._path;
}
get bytesRead() {
return this._bytesRead;
}
wrap(oldStream) {
super.wrap(oldStream);
return this;
}
}
/**
* A WriteStream implementation that wraps an underlying global WritableStream.
*/
export class WriteStream extends Writable {
pending = true;
_path = '<unknown>';
_bytesWritten = 0;
writer;
ready;
constructor(opts = {}, handleOrPromise) {
super(opts);
this.ready = Promise.resolve(handleOrPromise)
.then(handle => {
this._path = handle['vfs'].path;
const internal = handle.writableWebStream({ start: opts.start });
this.writer = internal.getWriter();
this.pending = false;
})
.catch(err => this.destroy(err));
}
async _write(chunk, encoding, callback) {
await this.ready;
if (!this.writer)
return callback(warn(UV('EAGAIN', 'write', this._path)));
if (encoding != 'buffer')
return callback(warn(UV('ENOTSUP', 'write', this._path)));
const data = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
try {
await this.writer.write(data);
this._bytesWritten += chunk.byteLength;
callback();
}
catch (error) {
callback(new Exception(Errno.EIO, error.toString()));
}
}
async _final(callback) {
await this.ready;
if (!this.writer)
return callback();
try {
await this.writer.close();
callback();
}
catch (error) {
callback(new Exception(Errno.EIO, error.toString()));
}
}
close(callback = () => null) {
try {
this.destroy();
this.emit('close');
callback(null);
}
catch (error) {
callback(new Exception(Errno.EIO, error.toString()));
}
}
get path() {
return this._path;
}
get bytesWritten() {
return this._bytesWritten;
}
}