@jsonjoy.com/json-pack
Version:
High-performance JSON serialization library
271 lines • 11.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NfsFsFileHandle = void 0;
const events_1 = require("events");
const stream_1 = require("stream");
const builder_1 = require("../builder");
/**
* Implements Node.js-like FileHandle interface for NFS v4 file operations.
*/
class NfsFsFileHandle extends events_1.EventEmitter {
constructor(fd, path, client, stateid, openOwner) {
super();
this.path = path;
this.client = client;
this.stateid = stateid;
this.openOwner = openOwner;
this.closed = false;
this.fd = fd;
}
getAsyncId() {
return this.fd;
}
async close() {
if (this.closed)
return;
this.closed = true;
await this.client.closeStateid(this.openOwner, this.stateid);
this.emit('close');
}
async stat(options) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.stat(this.path, options);
}
async appendFile(data, options) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.appendFile(this.path, data, options);
}
async chmod(mode) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.chmod(this.path, mode);
}
async chown(uid, gid) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.chown(this.path, uid, gid);
}
async datasync() {
if (this.closed)
throw new Error('File handle is closed');
}
async read(buffer, offset, length, position) {
if (this.closed)
throw new Error('File handle is closed');
const readPos = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
const readOps = [builder_1.nfs.READ(readPos, length, this.stateid)];
const response = await this.client.fs.compound(readOps);
if (response.status !== 0 /* Nfsv4Stat.NFS4_OK */) {
throw new Error(`Failed to read file: ${response.status}`);
}
const readRes = response.resarray[0];
if (readRes.status !== 0 /* Nfsv4Stat.NFS4_OK */ || !readRes.resok) {
throw new Error(`Failed to read file: ${readRes.status}`);
}
const data = readRes.resok.data;
const bytesToCopy = Math.min(data.length, length);
for (let i = 0; i < bytesToCopy; i++) {
buffer[offset + i] = data[i];
}
return { bytesRead: bytesToCopy, buffer };
}
async readFile(options) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.readFile(this.path, options);
}
async truncate(len) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.truncate(this.path, len);
}
async utimes(atime, mtime) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.utimes(this.path, atime, mtime);
}
async write(buffer, offset, length, position) {
if (this.closed)
throw new Error('File handle is closed');
const actualOffset = offset ?? 0;
const actualLength = length ?? buffer.byteLength - actualOffset;
const writePos = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
let data;
if (buffer instanceof Uint8Array) {
data = Uint8Array.prototype.slice.call(buffer, actualOffset, actualOffset + actualLength);
}
else if (Buffer.isBuffer(buffer)) {
data = new Uint8Array(buffer.buffer, buffer.byteOffset + actualOffset, actualLength);
}
else if (buffer instanceof DataView) {
data = new Uint8Array(buffer.buffer, buffer.byteOffset + actualOffset, actualLength);
}
else {
data = new Uint8Array(buffer.buffer, buffer.byteOffset + actualOffset, actualLength);
}
const writeOps = [builder_1.nfs.WRITE(this.stateid, writePos, 2 /* Nfsv4StableHow.FILE_SYNC4 */, data)];
const response = await this.client.fs.compound(writeOps);
if (response.status !== 0 /* Nfsv4Stat.NFS4_OK */) {
throw new Error(`Failed to write file: ${response.status}`);
}
const writeRes = response.resarray[0];
if (writeRes.status !== 0 /* Nfsv4Stat.NFS4_OK */ || !writeRes.resok) {
throw new Error(`Failed to write file: ${writeRes.status}`);
}
const resultBuffer = buffer instanceof Uint8Array || Buffer.isBuffer(buffer) ? buffer : new Uint8Array(buffer.buffer);
return { bytesWritten: writeRes.resok.count, buffer: resultBuffer };
}
async writeFile(data, options) {
if (this.closed)
throw new Error('File handle is closed');
return this.client.writeFile(this.path, data, options);
}
async readv(buffers, position) {
if (this.closed)
throw new Error('File handle is closed');
let currentPosition = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
let totalBytesRead = 0;
for (const buffer of buffers) {
const readOps = [builder_1.nfs.READ(currentPosition, buffer.byteLength, this.stateid)];
const response = await this.client.fs.compound(readOps);
if (response.status !== 0 /* Nfsv4Stat.NFS4_OK */) {
throw new Error(`Failed to read file: ${response.status}`);
}
const readRes = response.resarray[0];
if (readRes.status !== 0 /* Nfsv4Stat.NFS4_OK */ || !readRes.resok) {
throw new Error(`Failed to read file: ${readRes.status}`);
}
const data = readRes.resok.data;
const bytesToCopy = Math.min(data.length, buffer.byteLength);
const uint8View = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
for (let i = 0; i < bytesToCopy; i++) {
uint8View[i] = data[i];
}
totalBytesRead += bytesToCopy;
currentPosition += BigInt(bytesToCopy);
if (readRes.resok.eof || bytesToCopy < buffer.byteLength)
break;
}
return { bytesRead: totalBytesRead, buffers };
}
async writev(buffers, position) {
if (this.closed)
throw new Error('File handle is closed');
let currentPosition = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
let totalBytesWritten = 0;
for (const buffer of buffers) {
const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
const writeOps = [builder_1.nfs.WRITE(this.stateid, currentPosition, 2 /* Nfsv4StableHow.FILE_SYNC4 */, data)];
const response = await this.client.fs.compound(writeOps);
if (response.status !== 0 /* Nfsv4Stat.NFS4_OK */) {
throw new Error(`Failed to write file: ${response.status}`);
}
const writeRes = response.resarray[0];
if (writeRes.status !== 0 /* Nfsv4Stat.NFS4_OK */ || !writeRes.resok) {
throw new Error(`Failed to write file: ${writeRes.status}`);
}
totalBytesWritten += writeRes.resok.count;
currentPosition += BigInt(writeRes.resok.count);
}
return { bytesWritten: totalBytesWritten, buffers };
}
readableWebStream(options) {
if (this.closed)
throw new Error('File handle is closed');
const stream = this.createReadStream(options);
return stream_1.Readable.toWeb(stream);
}
createReadStream(options) {
if (this.closed)
throw new Error('File handle is closed');
const start = options?.start ?? 0;
const end = options?.end;
const highWaterMark = options?.highWaterMark ?? 64 * 1024;
let position = typeof start === 'number' ? start : 0;
const endPosition = typeof end === 'number' ? end : Infinity;
let reading = false;
const self = this;
const stream = new stream_1.Readable({
highWaterMark,
async read(size) {
if (reading)
return;
reading = true;
try {
while (true) {
if (position >= endPosition) {
this.push(null);
break;
}
const bytesToRead = Math.min(size, endPosition - position);
if (bytesToRead <= 0) {
this.push(null);
break;
}
const buffer = Buffer.alloc(bytesToRead);
const result = await self.read(buffer, 0, bytesToRead, position);
if (result.bytesRead === 0) {
this.push(null);
break;
}
position += result.bytesRead;
const chunk = buffer.slice(0, result.bytesRead);
if (!this.push(chunk))
break;
if (result.bytesRead < bytesToRead) {
this.push(null);
break;
}
}
}
catch (err) {
this.destroy(err);
}
finally {
reading = false;
}
},
});
stream.path = this.path;
return stream;
}
createWriteStream(options) {
if (this.closed)
throw new Error('File handle is closed');
const start = options?.start ?? 0;
const highWaterMark = options?.highWaterMark ?? 64 * 1024;
let position = typeof start === 'number' ? start : 0;
const self = this;
const stream = new stream_1.Writable({
highWaterMark,
async write(chunk, encoding, callback) {
try {
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
const result = await self.write(buffer, 0, buffer.length, position);
position += result.bytesWritten;
callback();
}
catch (err) {
callback(err);
}
},
async writev(chunks, callback) {
try {
const buffers = chunks.map(({ chunk }) => (Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
const result = await self.writev(buffers, position);
position += result.bytesWritten;
callback();
}
catch (err) {
callback(err);
}
},
});
stream.path = this.path;
return stream;
}
}
exports.NfsFsFileHandle = NfsFsFileHandle;
//# sourceMappingURL=NfsFsFileHandle.js.map