add watcher support to vfs mock

pull/468/merge
nightwing 2017-12-17 22:01:55 +04:00
rodzic e8ba27ec67
commit d22f15a549
1 zmienionych plików z 100 dodań i 30 usunięć

Wyświetl plik

@ -16,8 +16,10 @@ define(function(require, exports, module) {
var fsData = {}; var fsData = {};
var pathLib = require("path");
var Stream = require("stream").Stream; var Stream = require("stream").Stream;
var basename = require("path").basename; var basename = require("path").basename;
var EventEmitter = require("events").EventEmitter;
var noop = function() { console.error("not implemented"); }; var noop = function() { console.error("not implemented"); };
var silent = function() {}; var silent = function() {};
var connection = {}; var connection = {};
@ -57,14 +59,14 @@ define(function(require, exports, module) {
prev = data; prev = data;
data = data["!" + parts[i]]; data = data["!" + parts[i]];
if (data == null) { if (data == null) {
if (create && typeof prev != "string") if (create && !isFile(prev))
data = prev["!" + parts[i]] = {}; data = prev["!" + parts[i]] = {};
else else
return; return;
} }
} }
if (val) if (val != null)
data = prev["!" + parts[parts.length - 1]] = val; data = prev["!" + parts[parts.length - 1]] = { v: val, t: Date.now() };
return data; return data;
} }
@ -74,6 +76,14 @@ define(function(require, exports, module) {
return err; return err;
} }
function isFile(node) {
return typeof node == "string" || node && node.v != null;
}
function fileConets(node) {
return typeof node == "string" ? node : node && node.v;
}
function sendStream(data, callback) { function sendStream(data, callback) {
var stream = new Stream(); var stream = new Stream();
stream.readable = true; stream.readable = true;
@ -88,6 +98,22 @@ define(function(require, exports, module) {
stream.emit("end"); stream.emit("end");
} }
function readStream(callback) {
return function(err, meta) {
if (err) return callback(err);
var buffer = [];
meta.stream.on("data", function(data) {
if (typeof data == "string")
buffer += data;
else
buffer = buffer.concat(data);
});
meta.stream.on("end", function() {
callback(null, buffer);
});
};
}
function readBlob(blob, callback) { function readBlob(blob, callback) {
var reader = new FileReader(); var reader = new FileReader();
reader.onload = function() { reader.onload = function() {
@ -99,6 +125,37 @@ define(function(require, exports, module) {
reader.readAsText(blob); reader.readAsText(blob);
} }
var watcher = new EventEmitter();
watcher.addChange = function(path) {
plugin.stat(path, {}, function(err, stat) {
var dir = pathLib.dirname(path);
var name = pathLib.basename(path);
plugin.readdir(dir, {}, readStream(function(e, stats) {
watcher.emit(dir, "directory", name, stat, stats);
}));
watcher.emit(path, err ? "delete" : "change", name, stat);
});
};
watcher.watch = function(path, options, callback) {
if (!callback) callback = options;
setTimeout(function() {
var w = new EventEmitter();
var sendEvent = function(event, filename, stat, files) {
w.emit("change", event, filename, stat, files);
};
watcher.on(path, sendEvent);
w.close = function() {
watcher.off(path, sendEvent);
};
callback(null, { watcher: w });
});
};
watcher.unwatch = function(path, options, callback) {
if (!callback) callback = options;
watcher.removeAllListeners(path);
};
plugin.on("load", load); plugin.on("load", load);
plugin.on("unload", unload); plugin.on("unload", unload);
@ -146,10 +203,10 @@ define(function(require, exports, module) {
}); });
} }
var data = findNode(path); var data = findNode(path);
if (typeof data !== "string") if (!isFile(data))
return console.error("not implemented"); return console.error("not implemented");
var a = document.createElement('a'); var a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([data], { type: "text/plain" })); a.href = URL.createObjectURL(new Blob([fileConets(data)], { type: "text/plain" }));
a.download = filename || basename(path); a.download = filename || basename(path);
document.body.appendChild(a); document.body.appendChild(a);
@ -169,13 +226,14 @@ define(function(require, exports, module) {
setTimeout(function() { setTimeout(function() {
if (data == null) if (data == null)
return callback(ENOENT()); return callback(ENOENT());
var isFile = typeof data == "string"; var value = fileConets(data);
var isFileNode = value != null;
var stat = { var stat = {
name: name.substr(1), name: name,
size: isFile ? data.length : 1, size: isFileNode ? value.length : 1,
mtime: 0, mtime: data.t || 0,
ctime: 0, ctime: data.ct || data.t || 0,
mime: isFile ? "" : "folder" mime: isFileNode ? "" : "folder"
}; };
callback(null, stat); callback(null, stat);
}, 20); }, 20);
@ -183,23 +241,25 @@ define(function(require, exports, module) {
readfile: function(path, options, callback) { readfile: function(path, options, callback) {
var data = findNode(path); var data = findNode(path);
setTimeout(function() { setTimeout(function() {
if (typeof data != "string") var value = fileConets(data);
if (value == null)
return callback(ENOENT()); return callback(ENOENT());
sendStream(data, callback); sendStream(value, callback);
}, 20); }, 20);
}, },
readdir: function(path, options, callback) { readdir: function(path, options, callback) {
var data = findNode(path); var data = findNode(path);
setTimeout(function() { setTimeout(function() {
if (!data || typeof data == "string") if (!data || isFile(data))
return callback(ENOENT()); return callback(ENOENT());
var stats = Object.keys(data).map(function(n) { var stats = Object.keys(data).map(function(n) {
var isFile = typeof data[n] == "string"; var value = fileConets(data[n]);
var isFile = value != null;
return { return {
name: n.substr(1), name: n.substr(1),
size: isFile ? data[n].length : 1, size: isFile ? value.length : 1,
mtime: 0, mtime: data[n].t || 0,
ctime: 0, ctime: data[n].ct || data[n].t,
mime: isFile ? "" : "folder" mime: isFile ? "" : "folder"
}; };
}); });
@ -217,18 +277,22 @@ define(function(require, exports, module) {
options.stream.on("end", function(e) { options.stream.on("end", function(e) {
if (e) val += e; if (e) val += e;
setTimeout(function() { setTimeout(function() {
if (!parent || typeof parent[name] == "object") if (!parent)
return callback(ENOENT()); return callback(ENOENT());
parent[name] = val; if (parent[name] && !isFile(parent[name]))
return callback(new Error("EISDIR"));
parent[name] = { v: val, t: Date.now() };
watcher.addChange(path);
callback(null); callback(null);
}); });
}); });
}, },
mkdir: function(path, options, callback) { mkdir: function(path, options, callback) {
var data = findNode(path, true); var data = findNode(path, true);
setTimeout(function() { setTimeout(function() {
if (!data) if (!data)
return callback(ENOENT()); return callback(ENOENT());
watcher.addChange(path);
callback(); callback();
}); });
}, },
@ -237,6 +301,7 @@ define(function(require, exports, module) {
setTimeout(function() { setTimeout(function() {
if (!data) if (!data)
return callback(ENOENT()); return callback(ENOENT());
watcher.addChange(path);
callback(); callback();
}); });
}, },
@ -248,9 +313,10 @@ define(function(require, exports, module) {
var parent = findNode(parts.join("/")); var parent = findNode(parts.join("/"));
if (!parent || !parent[name]) if (!parent || !parent[name])
return callback(ENOENT()); return callback(ENOENT());
if (typeof parent[name] != "string") if (!isFile(parent[name]))
return callback(new Error("EISDIR")); return callback(new Error("EISDIR"));
delete parent[name]; delete parent[name];
watcher.addChange(path);
callback(); callback();
}); });
}, },
@ -261,9 +327,10 @@ define(function(require, exports, module) {
var parent = findNode(parts.join("/")); var parent = findNode(parts.join("/"));
if (!parent || !parent[name]) if (!parent || !parent[name])
return callback(ENOENT()); return callback(ENOENT());
if (typeof parent[name] == "string") if (isFile(parent[name]))
return callback(new Error("EISFILE")); return callback(new Error("EISFILE"));
delete parent[name]; delete parent[name];
watcher.addChange(path);
callback(); callback();
}); });
}, },
@ -284,6 +351,8 @@ define(function(require, exports, module) {
toParent[toName] = fromParent[fromName]; toParent[toName] = fromParent[fromName];
delete fromParent[fromName]; delete fromParent[fromName];
watcher.addChange(from);
watcher.addChange(to);
callback(null); callback(null);
}); });
}, },
@ -306,7 +375,8 @@ define(function(require, exports, module) {
toParent[toName] = fromParent[fromName]; toParent[toName] = fromParent[fromName];
toParts.push(toName.substr(1)); toParts.push(toName.substr(1));
callback(null, {to: toParts.join("/")}); watcher.addChange(to);
callback(null, { to: toParts.join("/") });
}); });
}, },
chmod: noop, chmod: noop,
@ -329,17 +399,17 @@ define(function(require, exports, module) {
readFileWithMetadata: function(path, options, callback) { readFileWithMetadata: function(path, options, callback) {
var data = findNode(path); var data = findNode(path);
var metadata = findNode("/.c9/metadata" + path); var metadata = findNode("/.c9/metadata" + path);
setTimeout(function() { var timer = setTimeout(function() {
if (typeof data != "string") if (!isFile(data))
return callback(ENOENT()); return callback(ENOENT());
// TODO metadata callback(null, fileConets(data), fileConets(metadata));
callback(null, data, metadata);
}); });
return { abort: function() {} }; return { abort: function() { clearTimeout(timer); } };
}, },
// Wrapper around fs.watch or fs.watchFile // Wrapper around fs.watch or fs.watchFile
watch: silent, watch: watcher.watch,
unwatch: watcher.unwatch,
// Network connection // Network connection
connect: noop, connect: noop,