From cd70d4a9c073751796529cca3f09691a29d28126 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 20 Sep 2009 20:40:20 +0200 Subject: [PATCH] Add "/file.js" buffered disk I/O object. This is similar to the class node.File which was removed in 82cb1b5acb53000690448bf3d9b5d1f40ee66f76. Needs documentation. --- lib/file.js | 128 +++++++++++++++++++++++++++++ test/mjsunit/test-buffered-file.js | 38 +++++++++ 2 files changed, 166 insertions(+) create mode 100644 lib/file.js create mode 100644 test/mjsunit/test-buffered-file.js diff --git a/lib/file.js b/lib/file.js new file mode 100644 index 0000000000..f571ce9fe3 --- /dev/null +++ b/lib/file.js @@ -0,0 +1,128 @@ +exports.debugLevel = 0; // Increase to get more verbose debug output + +function debugMessage (msg) { + if (exports.debugLevel > 0) { + node.error(__filename + ": " + msg.toString()); + } +} + +function debugObject (obj) { + if (exports.debugLevel > 0) { + node.error(__filename + ": " + JSON.stringify(obj)); + } +} + +exports.File = function (filename, mode, options) { + var self = this; + + options = options || {}; + self.encoding = options.encoding || "utf8"; + + self.filename = filename; + + self.actionQueue = []; + self.currentAction = null; + + switch (mode) { + case "r": + self.flags = node.O_RDONLY; + break; + + case "r+": + self.flags = node.O_RDWR; + break; + + case "w": + self.flags = node.O_CREAT | node.O_TRUNC | node.O_WRONLY; + break; + + case "w+": + self.flags = node.O_CREAT | node.O_TRUNC | node.O_RDWR; + break; + + case "a": + self.flags = node.O_APPEND | node.O_CREAT | node.O_WRONLY; + break; + + case "a+": + self.flags = node.O_APPEND | node.O_CREAT | node.O_RDWR; + break; + + default: + throw new Error("Unknown mode"); + } + + self.open(self.filename, self.flags, 0666).addCallback(function (fd) { + debugMessage(self.filename + " opened. fd = " + fd); + self.fd = fd; + }).addErrback(function () { + self.emit("error", ["open"]); + }); +}; + +var proto = exports.File.prototype; + +proto._maybeDispatch = function () { + var self = this; + + if (self.currentAction) return; + self.currentAction = self.actionQueue.shift(); + if (!self.currentAction) return; + + debugObject(self.currentAction); + + var args = self.currentAction.args || []; + + if (self.currentAction.method != "open") { + args.unshift(self.fd); + } + + var method = self.currentAction.method; + + if (!args[3] && (method == "read" || method == "write")) { + args[3] = self.encoding; + } + + var promise = node.fs[method].apply(self, args); + + var userPromise = self.currentAction.promise; + + promise.addCallback(function () { + node.assert(self.currentAction.promise == userPromise); + userPromise.emitSuccess.apply(userPromise, arguments); + self.currentAction = null; + self._maybeDispatch(); + }).addErrback(function () { + debugMessage("Error in method " + method); + node.assert(self.currentAction.promise == userPromise); + userPromise.emitError.apply(userPromise, arguments); + self.currentAction = null; + self._maybeDispatch(); + }); +}; + +proto._queueAction = function (method, args) { + var userPromise = new node.Promise; + this.actionQueue.push({ method: method, args: args, promise: userPromise }); + this._maybeDispatch(); + return userPromise; +}; + +// FIXME the following can probably be DRY'd up with some fancy getter +// stuff. + +proto.open = function (filename, flags, mode) { + return this._queueAction("open", [filename, flags, mode]); +}; + +proto.write = function (data, pos, encoding) { + return this._queueAction("write", [data, pos, encoding]); +}; + +proto.read = function (length, pos, encoding) { + return this._queueAction("read", [length, pos, encoding]); +}; + +proto.close = function () { + return this._queueAction("close"); +}; diff --git a/test/mjsunit/test-buffered-file.js b/test/mjsunit/test-buffered-file.js new file mode 100644 index 0000000000..f6efc481b9 --- /dev/null +++ b/test/mjsunit/test-buffered-file.js @@ -0,0 +1,38 @@ +include("common.js"); + +var testTxt = node.path.join(fixturesDir, "test.txt"); + +var libDir = node.path.join(testDir, "../../lib"); +node.libraryPaths.unshift(libDir); +include("/file.js"); + +var fileUnlinked = false; + +var file = new File(testTxt, "w+"); +file.write("hello\n"); +file.write("world\n"); +setTimeout(function () { + file.write("hello\n"); + file.write("world\n"); + file.close().addCallback(function () { + node.error("file closed..."); + var out = node.fs.cat(testTxt).wait(); + print("the file contains: "); + p(out); + assertEquals("hello\nworld\nhello\nworld\n", out); + var file2 = new File(testTxt, "r"); + file2.read(5).addCallback(function (data) { + puts("read(5): " + JSON.stringify(data)); + assertEquals("hello", data); + node.fs.unlink(testTxt).addCallback(function () { + fileUnlinked = true; + }); + }); + file2.close(); + }); +}, 10); + +process.addListener("exit", function () { + assertTrue(fileUnlinked); + puts("done"); +});