FileHandle.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.FileHandle = void 0;
  4. const util_1 = require("./util");
  5. const events_1 = require("events");
  6. class FileHandle extends events_1.EventEmitter {
  7. constructor(fs, fd) {
  8. super();
  9. this.refs = 1;
  10. this.closePromise = null;
  11. this.position = 0;
  12. this.readableWebStreamLocked = false;
  13. this.fs = fs;
  14. this.fd = fd;
  15. }
  16. getAsyncId() {
  17. // Return a unique async ID for this file handle
  18. // In a real implementation, this would be provided by the underlying system
  19. return this.fd;
  20. }
  21. appendFile(data, options) {
  22. return (0, util_1.promisify)(this.fs, 'appendFile')(this.fd, data, options);
  23. }
  24. chmod(mode) {
  25. return (0, util_1.promisify)(this.fs, 'fchmod')(this.fd, mode);
  26. }
  27. chown(uid, gid) {
  28. return (0, util_1.promisify)(this.fs, 'fchown')(this.fd, uid, gid);
  29. }
  30. close() {
  31. if (this.fd === -1) {
  32. return Promise.resolve();
  33. }
  34. if (this.closePromise) {
  35. return this.closePromise;
  36. }
  37. this.refs--;
  38. if (this.refs === 0) {
  39. const currentFd = this.fd;
  40. this.fd = -1;
  41. this.closePromise = (0, util_1.promisify)(this.fs, 'close')(currentFd).finally(() => {
  42. this.closePromise = null;
  43. });
  44. }
  45. else {
  46. this.closePromise = new Promise((resolve, reject) => {
  47. this.closeResolve = resolve;
  48. this.closeReject = reject;
  49. }).finally(() => {
  50. this.closePromise = null;
  51. this.closeReject = undefined;
  52. this.closeResolve = undefined;
  53. });
  54. }
  55. this.emit('close');
  56. return this.closePromise;
  57. }
  58. datasync() {
  59. return (0, util_1.promisify)(this.fs, 'fdatasync')(this.fd);
  60. }
  61. createReadStream(options) {
  62. return this.fs.createReadStream('', Object.assign(Object.assign({}, options), { fd: this }));
  63. }
  64. createWriteStream(options) {
  65. return this.fs.createWriteStream('', Object.assign(Object.assign({}, options), { fd: this }));
  66. }
  67. readableWebStream(options = {}) {
  68. const { type = 'bytes', autoClose = false } = options;
  69. let position = 0;
  70. if (this.fd === -1) {
  71. throw new Error('The FileHandle is closed');
  72. }
  73. if (this.closePromise) {
  74. throw new Error('The FileHandle is closing');
  75. }
  76. if (this.readableWebStreamLocked) {
  77. throw new Error('An error will be thrown if this method is called more than once or is called after the FileHandle is closed or closing.');
  78. }
  79. this.readableWebStreamLocked = true;
  80. this.ref();
  81. const unlockAndCleanup = () => {
  82. this.readableWebStreamLocked = false;
  83. this.unref();
  84. if (autoClose) {
  85. this.close().catch(() => {
  86. // Ignore close errors in cleanup
  87. });
  88. }
  89. };
  90. return new ReadableStream({
  91. type: type === 'bytes' ? 'bytes' : undefined,
  92. autoAllocateChunkSize: 16384,
  93. pull: async (controller) => {
  94. var _a;
  95. try {
  96. const view = (_a = controller.byobRequest) === null || _a === void 0 ? void 0 : _a.view;
  97. if (!view) {
  98. // Fallback for when BYOB is not available
  99. const buffer = new Uint8Array(16384);
  100. const result = await this.read(buffer, 0, buffer.length, position);
  101. if (result.bytesRead === 0) {
  102. controller.close();
  103. unlockAndCleanup();
  104. return;
  105. }
  106. position += result.bytesRead;
  107. controller.enqueue(buffer.slice(0, result.bytesRead));
  108. return;
  109. }
  110. const result = await this.read(view, view.byteOffset, view.byteLength, position);
  111. if (result.bytesRead === 0) {
  112. controller.close();
  113. unlockAndCleanup();
  114. return;
  115. }
  116. position += result.bytesRead;
  117. controller.byobRequest.respond(result.bytesRead);
  118. }
  119. catch (error) {
  120. controller.error(error);
  121. unlockAndCleanup();
  122. }
  123. },
  124. cancel: async () => {
  125. unlockAndCleanup();
  126. },
  127. });
  128. }
  129. async read(buffer, offset, length, position) {
  130. const readPosition = position !== null && position !== undefined ? position : this.position;
  131. const result = await (0, util_1.promisify)(this.fs, 'read', bytesRead => ({ bytesRead, buffer }))(this.fd, buffer, offset, length, readPosition);
  132. // Update internal position only if position was null/undefined
  133. if (position === null || position === undefined) {
  134. this.position += result.bytesRead;
  135. }
  136. return result;
  137. }
  138. readv(buffers, position) {
  139. return (0, util_1.promisify)(this.fs, 'readv', bytesRead => ({ bytesRead, buffers }))(this.fd, buffers, position);
  140. }
  141. readFile(options) {
  142. return (0, util_1.promisify)(this.fs, 'readFile')(this.fd, options);
  143. }
  144. stat(options) {
  145. return (0, util_1.promisify)(this.fs, 'fstat')(this.fd, options);
  146. }
  147. sync() {
  148. return (0, util_1.promisify)(this.fs, 'fsync')(this.fd);
  149. }
  150. truncate(len) {
  151. return (0, util_1.promisify)(this.fs, 'ftruncate')(this.fd, len);
  152. }
  153. utimes(atime, mtime) {
  154. return (0, util_1.promisify)(this.fs, 'futimes')(this.fd, atime, mtime);
  155. }
  156. async write(buffer, offset, length, position) {
  157. const useInternalPosition = typeof position !== 'number';
  158. const writePosition = useInternalPosition ? this.position : position;
  159. const result = await (0, util_1.promisify)(this.fs, 'write', bytesWritten => ({ bytesWritten, buffer }))(this.fd, buffer, offset, length, writePosition);
  160. // Update internal position only if position was null/undefined
  161. if (useInternalPosition) {
  162. this.position += result.bytesWritten;
  163. }
  164. return result;
  165. }
  166. writev(buffers, position) {
  167. return (0, util_1.promisify)(this.fs, 'writev', bytesWritten => ({ bytesWritten, buffers }))(this.fd, buffers, position);
  168. }
  169. writeFile(data, options) {
  170. return (0, util_1.promisify)(this.fs, 'writeFile')(this.fd, data, options);
  171. }
  172. // Implement Symbol.asyncDispose if available (ES2023+)
  173. async [Symbol.asyncDispose]() {
  174. await this.close();
  175. }
  176. ref() {
  177. this.refs++;
  178. }
  179. unref() {
  180. this.refs--;
  181. if (this.refs === 0) {
  182. this.fd = -1;
  183. if (this.closeResolve) {
  184. (0, util_1.promisify)(this.fs, 'close')(this.fd).then(this.closeResolve, this.closeReject);
  185. }
  186. }
  187. }
  188. }
  189. exports.FileHandle = FileHandle;
  190. //# sourceMappingURL=FileHandle.js.map