UNPKG

@jsonjoy.com/json-pack

Version:

High-performance JSON serialization library

271 lines 11.4 kB
"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