hfs 0.1.6 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +674 -0
- package/README.md +102 -8
- package/admin/assets/index.dcc78777.css +1 -0
- package/admin/assets/index.f056db34.js +282 -0
- package/admin/assets/sha512.3c0e384c.js +8 -0
- package/admin/index.html +17 -0
- package/admin/logo.svg +36 -0
- package/frontend/assets/index.55c710c2.js +85 -0
- package/frontend/assets/index.ee805a6c.css +1 -0
- package/frontend/assets/sha512.634b743e.js +8 -0
- package/frontend/fontello.css +77 -0
- package/frontend/fontello.woff2 +0 -0
- package/frontend/index.html +18 -0
- package/package.json +93 -28
- package/plugins/antibrute/plugin.js +38 -0
- package/plugins/download-counter/plugin.js +47 -0
- package/plugins/download-counter/public/hits.js +5 -0
- package/plugins/updater-disabled/plugin.js +44 -0
- package/plugins/vhosting/plugin.js +42 -0
- package/src/QuickZipStream.js +285 -0
- package/src/ThrottledStream.js +93 -0
- package/src/adminApis.js +169 -0
- package/src/api.accounts.js +59 -0
- package/src/api.auth.js +130 -0
- package/src/api.file_list.js +103 -0
- package/src/api.helpers.js +32 -0
- package/src/api.monitor.js +102 -0
- package/src/api.plugins.js +125 -0
- package/src/api.vfs.js +164 -0
- package/src/apiMiddleware.js +136 -0
- package/src/block.js +33 -0
- package/src/commands.js +105 -0
- package/src/config.js +172 -0
- package/src/connections.js +57 -0
- package/src/const.js +83 -0
- package/src/crypt.js +21 -0
- package/src/debounceAsync.js +48 -0
- package/src/events.js +9 -0
- package/src/frontEndApis.js +38 -0
- package/src/github.js +102 -0
- package/src/index.js +53 -0
- package/src/listen.js +226 -0
- package/src/log.js +137 -0
- package/src/middlewares.js +154 -0
- package/src/misc.js +160 -0
- package/src/pbkdf2.js +74 -0
- package/src/perm.js +176 -0
- package/src/plugins.js +338 -0
- package/src/serveFile.js +104 -0
- package/src/serveGuiFiles.js +113 -0
- package/src/sse.js +29 -0
- package/src/throttler.js +91 -0
- package/src/update.js +69 -0
- package/src/util-files.js +141 -0
- package/src/util-generators.js +30 -0
- package/src/util-http.js +30 -0
- package/src/vfs.js +227 -0
- package/src/watchLoad.js +73 -0
- package/src/zip.js +69 -0
- package/.npmignore +0 -19
- package/admin-server.js +0 -212
- package/cli.js +0 -33
- package/file-server.js +0 -100
- package/lib/common.js +0 -10
- package/lib/extending.js +0 -158
- package/lib/mime.js +0 -19
- package/lib/misc.js +0 -75
- package/lib/serving.js +0 -81
- package/lib/vfs.js +0 -403
- package/main.js +0 -24
- package/note.txt +0 -104
- package/speedtest.js +0 -21
- package/static/backend.css +0 -14
- package/static/backend.html +0 -32
- package/static/backend.js +0 -694
- package/static/extending.js +0 -187
- package/static/frontend.css +0 -29
- package/static/frontend.html +0 -23
- package/static/frontend.js +0 -230
- package/static/icons/files/archive.png +0 -0
- package/static/icons/files/audio.png +0 -0
- package/static/icons/files/file.png +0 -0
- package/static/icons/files/folder.png +0 -0
- package/static/icons/files/image.png +0 -0
- package/static/icons/files/link.png +0 -0
- package/static/icons/files/video.png +0 -0
- package/static/jquery.js +0 -4
- package/static/jquery.rule-1.0.2.js +0 -273
- package/static/misc.js +0 -194
- package/static/tpl.js +0 -17
- package/todo.txt +0 -25
package/lib/vfs.js
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @author Massimo Melina <a@rejetto.com>
|
|
3
|
-
*/
|
|
4
|
-
require('./common');
|
|
5
|
-
|
|
6
|
-
exports.Vfs = Vfs = function(){
|
|
7
|
-
this.root = new FileNode(NK.FIXED);
|
|
8
|
-
this.root.name = '/';
|
|
9
|
-
}; // Vfs
|
|
10
|
-
|
|
11
|
-
Vfs.prototype.fromUrl = function(url, cb) {
|
|
12
|
-
assert(cb, 'no cb');
|
|
13
|
-
assert( typeof url === 'string', 'url');
|
|
14
|
-
var separator = 0;
|
|
15
|
-
var run = this.root;
|
|
16
|
-
while (separator < url.length-1) {
|
|
17
|
-
var from = separator+1;
|
|
18
|
-
var nextSep = url.indexOf('/', from);
|
|
19
|
-
if (nextSep < 0) {
|
|
20
|
-
nextSep = url.length;
|
|
21
|
-
}
|
|
22
|
-
var piece = url.substring(from, nextSep);
|
|
23
|
-
if (piece && !run.isFolder() // something has left but we cannot go deeper
|
|
24
|
-
|| run.hasDeleted(piece)) {
|
|
25
|
-
cb(false);
|
|
26
|
-
return this;
|
|
27
|
-
}
|
|
28
|
-
var child = run.getChildByName(piece);
|
|
29
|
-
if (!child && run.isOnDisk()) { // if not in the VFS tree, try to fill the gap with the disk
|
|
30
|
-
run.createFileNodeFromRelativeUri(url.substring(from), function(newNode){
|
|
31
|
-
cb(newNode || false);
|
|
32
|
-
});
|
|
33
|
-
return this;
|
|
34
|
-
}
|
|
35
|
-
if (!child) { // we did our best
|
|
36
|
-
cb(false);
|
|
37
|
-
return this;
|
|
38
|
-
}
|
|
39
|
-
run = child;
|
|
40
|
-
separator = nextSep;
|
|
41
|
-
}
|
|
42
|
-
cb(run);
|
|
43
|
-
return this;
|
|
44
|
-
}; // fromUrl
|
|
45
|
-
|
|
46
|
-
exports.FileNode = FileNode = function(nodeKind, name, more, cb) {
|
|
47
|
-
this.nodeKind = nodeKind;
|
|
48
|
-
this.itemKind = FK.VIRTUAL_FOLDER;
|
|
49
|
-
this.set( name||'', cb );
|
|
50
|
-
this.extend(more||{});
|
|
51
|
-
//this.children = []; // as a list. An object with fast by-name access would be nice, but it would not work for case-insensitive OSs
|
|
52
|
-
this.deletedItems = [];
|
|
53
|
-
this.permissions = {};
|
|
54
|
-
}; // FileNode
|
|
55
|
-
|
|
56
|
-
/* Node kinds
|
|
57
|
-
FIXED: is a node manually entered in the tree.
|
|
58
|
-
MOD: it was a TEMP or SEMITEMP node, then modified some way (name, permissions, etc).
|
|
59
|
-
SEMITEMP: it's a folder between 2 non-temp nodes. It's just storing the file structure between these two.
|
|
60
|
-
TEMP: a node created on the fly, from the disk, for occasional usage.
|
|
61
|
-
*/
|
|
62
|
-
NK = FileNode.NODE_KIND = Enum('FIXED TEMP SEMITEMP MOD');
|
|
63
|
-
FK = FileNode.FILE_KIND = Enum('FILE FOLDER VIRTUAL_FILE VIRTUAL_FOLDER LINK');
|
|
64
|
-
|
|
65
|
-
FileNode.prototype.__defineSetter__('name', function(v){
|
|
66
|
-
this.customName = (v === this.getExpectedName()) ? null : v;
|
|
67
|
-
this.reconsiderNodeKind();
|
|
68
|
-
});
|
|
69
|
-
FileNode.prototype.__defineGetter__('name', function(){
|
|
70
|
-
return this.customName || this.getExpectedName();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
FileNode.prototype.__defineSetter__('parent', function(v){
|
|
74
|
-
var p = this._parent;
|
|
75
|
-
if (p && p.children) {
|
|
76
|
-
var idx = p.children.indexOf(this);
|
|
77
|
-
p.children.splice(idx, idx+1); // unbind from old parent
|
|
78
|
-
}
|
|
79
|
-
this._parent = v; // bind this way
|
|
80
|
-
if (!v || this.isTemp()) return; // TEMP are linked one-way
|
|
81
|
-
if (!v.children) v.children = [];
|
|
82
|
-
v.children.push(this); // bind other way
|
|
83
|
-
});
|
|
84
|
-
FileNode.prototype.__defineGetter__('parent', function(){
|
|
85
|
-
return this._parent;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
FileNode.prototype.getExpectedName = function(){
|
|
89
|
-
return this.isUnit() ? this.resource
|
|
90
|
-
: path.basename(this.resource);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
FileNode.prototype.resourceAncestorOf = function(child){
|
|
94
|
-
return isPathAndSubpath(this.resource, child.resource);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
function isPathAndSubpath(path_, sub) {
|
|
98
|
-
path_ = path.resolve(path_);
|
|
99
|
-
sub = path.resolve(sub);
|
|
100
|
-
return misc.sameFileName(path_, sub.substr(0, path_.length));
|
|
101
|
-
} // isPathAndSubpath
|
|
102
|
-
|
|
103
|
-
FileNode.prototype.getFolder = function(cb){
|
|
104
|
-
var p = this.parent;
|
|
105
|
-
var parentTreeIsNotParentFolder = false;
|
|
106
|
-
if (this.isTemp()) {
|
|
107
|
-
var rel = this.resourceOnlyRelativeTo(p);
|
|
108
|
-
parentTreeIsNotParentFolder = rel && isPath(rel);
|
|
109
|
-
}
|
|
110
|
-
if (parentTreeIsNotParentFolder) {
|
|
111
|
-
return new FileNode(NK.TEMP, path.dirname(this.resource), {parent:p}, cb); // we must create a temp node
|
|
112
|
-
}
|
|
113
|
-
if (cb) cb(p);
|
|
114
|
-
return p;
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
/** calculates the path relative to other, but only if other is an ancestor
|
|
118
|
-
* @param {FileNode}
|
|
119
|
-
* @return {string} relative path
|
|
120
|
-
*/
|
|
121
|
-
FileNode.prototype.resourceOnlyRelativeTo = function(other){
|
|
122
|
-
return other.resourceAncestorOf(this)
|
|
123
|
-
? this.resource.substr(other.resource.length+1)
|
|
124
|
-
: false;
|
|
125
|
-
}; // resourceOnlyRelativeTo
|
|
126
|
-
|
|
127
|
-
/** calculates the path relative to other, or return the absolute path if they are not related
|
|
128
|
-
* @param {FileNode}
|
|
129
|
-
* @return {string} path, possibly relative
|
|
130
|
-
*/
|
|
131
|
-
FileNode.prototype.resourceRelativeTo = function(other){
|
|
132
|
-
return this.resourceOnlyRelativeTo(other) || this.resource
|
|
133
|
-
}; // resourceRelativeTo
|
|
134
|
-
|
|
135
|
-
FileNode.prototype.isRoot = function() { return !this.parent };
|
|
136
|
-
FileNode.prototype.isFolder = function() { return this.itemKind.isIn(FK.FOLDER, FK.VIRTUAL_FOLDER) };
|
|
137
|
-
FileNode.prototype.isFile = function() { return this.itemKind.isIn(FK.FILE, FK.VIRTUAL_FILE) };
|
|
138
|
-
FileNode.prototype.isLink = function() { return this.itemKind === FK.LINK };
|
|
139
|
-
FileNode.prototype.isOnDisk = function() { return this.itemKind.isIn(FK.FILE, FK.FOLDER) };
|
|
140
|
-
FileNode.prototype.isVirtual = function() { return this.itemKind.isIn(FK.VIRTUAL_FILE, FK.VIRTUAL_FOLDER) };
|
|
141
|
-
FileNode.prototype.isTemp = function() { return this.nodeKind === NK.TEMP };
|
|
142
|
-
|
|
143
|
-
FileNode.prototype.toString = function() { return "FileNode({name})".format(this) };
|
|
144
|
-
|
|
145
|
-
FileNode.prototype.isUnit = function() {
|
|
146
|
-
return misc.isWindows
|
|
147
|
-
&& this.resource
|
|
148
|
-
&& this.resource.length === 2
|
|
149
|
-
&& this.resource[1] === ':';
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
FileNode.prototype.setPath = function(what, cb/*optional*/) {
|
|
153
|
-
this.resource = path.normalize(what);
|
|
154
|
-
this.stats = null; // 'null' stands for non-calculated
|
|
155
|
-
this.itemKind = null; // we don't know yet
|
|
156
|
-
var x = this;
|
|
157
|
-
fs.stat(this.resource, function onStat(err,stats){
|
|
158
|
-
x.stats = err ? false : stats; // 'false' stands for 'error'
|
|
159
|
-
x.itemKind = (!err && stats.isDirectory()) ? FK.FOLDER : FK.FILE;
|
|
160
|
-
if (cb) cb(x);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
return this;
|
|
164
|
-
}; // setPath
|
|
165
|
-
|
|
166
|
-
function isPath(s) { return s.match(/[\\\/]/) } // we know it's a path because of the slashes
|
|
167
|
-
|
|
168
|
-
FileNode.prototype.set = function(what, cb/*optional*/) {
|
|
169
|
-
if (isPath(what)) {
|
|
170
|
-
this.setPath(what, cb);
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
this.name = what;
|
|
174
|
-
this.resource = null;
|
|
175
|
-
this.itemKind = FK.VIRTUAL_FOLDER;
|
|
176
|
-
if (cb) cb(this);
|
|
177
|
-
}
|
|
178
|
-
return this;
|
|
179
|
-
}; // set
|
|
180
|
-
|
|
181
|
-
FileNode.prototype.add = function(what, cb/*optional*/) {
|
|
182
|
-
var restored = isPath(what)
|
|
183
|
-
&& this.deletedItems
|
|
184
|
-
&& isPathAndSubpath(this.resource, what)
|
|
185
|
-
&& this.restoreDeleted(path.basename(what));
|
|
186
|
-
new FileNode(restored ? NK.TEMP : NK.FIXED, what, {parent:this}, cb); // create child
|
|
187
|
-
return this;
|
|
188
|
-
}; // add
|
|
189
|
-
|
|
190
|
-
// return child as it is in the tree. Temp items will not be created.
|
|
191
|
-
FileNode.prototype.getChildByName = function(name) {
|
|
192
|
-
if (!this.children) return false;
|
|
193
|
-
for (var i=0, a=this.children, l=a.length; i<l; ++i) {
|
|
194
|
-
var v = a[i];
|
|
195
|
-
if (v.testName(name)) {
|
|
196
|
-
return v;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return false;
|
|
200
|
-
}; // getChildByName
|
|
201
|
-
|
|
202
|
-
// return children as an array. This is not only to ensure it's a copy (to protect the real property) but also to hide the detail that children is an array (in case this changes in the future)
|
|
203
|
-
FileNode.prototype.getChildren = function() {
|
|
204
|
-
var a = this.children;
|
|
205
|
-
return a ? a.slice() : [];
|
|
206
|
-
}; // getChildren
|
|
207
|
-
|
|
208
|
-
// compares filenames accordingly to the operating system's case policy
|
|
209
|
-
FileNode.prototype.testName = function(name) {
|
|
210
|
-
if (name instanceof FileNode) {
|
|
211
|
-
name = name.name;
|
|
212
|
-
}
|
|
213
|
-
assert(typeof name === 'string', 'bad name');
|
|
214
|
-
return misc.sameFileName(name, this.name);
|
|
215
|
-
}; // testName
|
|
216
|
-
|
|
217
|
-
FileNode.prototype.idxDeleted = function(name) {
|
|
218
|
-
name = name.excludeTrailing('/');
|
|
219
|
-
for (var i=0, a=this.deletedItems, l=a.length; i<l; ++i) {
|
|
220
|
-
if (misc.sameFileName(name, a[i].excludeTrailing('/'))) {
|
|
221
|
-
return i;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return false;
|
|
225
|
-
}; // idxDeleted
|
|
226
|
-
|
|
227
|
-
FileNode.prototype.hasDeleted = function(name) {
|
|
228
|
-
return this.idxDeleted(name) !== false;
|
|
229
|
-
}; // hasDeleted
|
|
230
|
-
|
|
231
|
-
FileNode.prototype.restoreDeleted = function(name) {
|
|
232
|
-
var i = this.idxDeleted(name);
|
|
233
|
-
if (i === false) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
this.deletedItems.splice(i,1); // remove from the array
|
|
237
|
-
return true;
|
|
238
|
-
}; // restoreDeleted
|
|
239
|
-
|
|
240
|
-
FileNode.prototype.createFileNodeFromRelativeUri = function(uri, cb) {
|
|
241
|
-
assert(cb, 'cb');
|
|
242
|
-
var p = path.join(this.resource, decodeURI(uri).excludeTrailing('/'));
|
|
243
|
-
var _this = this;
|
|
244
|
-
fs.exists(p, function(yes){
|
|
245
|
-
if (yes) {
|
|
246
|
-
new FileNode(NK.TEMP, p, {parent:_this}, cb);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
cb(null);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
return this;
|
|
253
|
-
}; // createFileNodeFromRelativeUri
|
|
254
|
-
|
|
255
|
-
// used for serialization
|
|
256
|
-
FileNode.prototype.toJSON = function(){
|
|
257
|
-
var o = misc.clone(this);
|
|
258
|
-
delete o.parent; // avoid circular reference
|
|
259
|
-
o.name = this.name;
|
|
260
|
-
if (this.children) {
|
|
261
|
-
// children will be replaced by an array of names
|
|
262
|
-
var names = [];
|
|
263
|
-
for (var i=0, a=this.children, l=a.length; i<l; ++i) { // must work on this.children and not on o.children, that's not cloned correctly
|
|
264
|
-
names.push(a[i].name);
|
|
265
|
-
}
|
|
266
|
-
o.children = names;
|
|
267
|
-
}
|
|
268
|
-
return o;
|
|
269
|
-
}; // toJSON
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
FileNode.prototype.dir = function(cb) {
|
|
273
|
-
var _this = this; // used inside some callbacks that override this
|
|
274
|
-
var directoryLoaded = arguments[1]; // used internally
|
|
275
|
-
if (!directoryLoaded) {
|
|
276
|
-
if (this.isOnDisk()) { // for real folders we must first load files
|
|
277
|
-
fs.readdir(this.resource, function onReaddir(err, files) { // read them
|
|
278
|
-
assert(!err, 'err'); // ** handle it!
|
|
279
|
-
_this.dir(cb, files); // restart
|
|
280
|
-
});
|
|
281
|
-
return; // recurring, break this flow
|
|
282
|
-
}
|
|
283
|
-
directoryLoaded = []; // this is a virtual this, so there is no directory to load from disk
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
// create FileNodes for every file found in the directory, except the deleted ones
|
|
288
|
-
var toNode = function(filename,cb){
|
|
289
|
-
_this.hasDeleted(filename)
|
|
290
|
-
? cb(null,false) // don't create a filenode, so this file will be skipped
|
|
291
|
-
: _this.createFileNodeFromRelativeUri(filename, cb.bind(this,null)); // the just-created filenode is appended as parameter to the cb's calling
|
|
292
|
-
};
|
|
293
|
-
async.map(directoryLoaded, toNode, function(err, mappedNodes){
|
|
294
|
-
// collect all items in an object to avoid duplicates (by using filename as key)
|
|
295
|
-
var items = {};
|
|
296
|
-
// first the items from the disk
|
|
297
|
-
for (var a=directoryLoaded, i=a.length; i--;) {
|
|
298
|
-
var fnode = mappedNodes[i];
|
|
299
|
-
if (fnode) {
|
|
300
|
-
items[a[i]] = fnode;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
// then items from the VFS, so they eventually overwrite
|
|
304
|
-
if (_this.children) {
|
|
305
|
-
_this.children.forEach(function(e){
|
|
306
|
-
items[e.name] = e;
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
// now collect more data about items (through fs.stat)
|
|
310
|
-
async.forEach(items.getProperties(), function(it,doneThis) {
|
|
311
|
-
if (!it.isOnDisk()) return doneThis(); // no need to work this item
|
|
312
|
-
fs.stat(it.resource, function onStat(err,stats){
|
|
313
|
-
if (err) { // if we can't stat() it ...
|
|
314
|
-
delete items[it.name]; // ... we don't want it
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
it.stats = stats; // bind the data
|
|
318
|
-
it.itemKind = stats.isDirectory() ? FK.FOLDER : FK.FILE; // determine item's nature
|
|
319
|
-
}
|
|
320
|
-
doneThis(); // notify async
|
|
321
|
-
});//stat
|
|
322
|
-
}, cb.bind(this, items)); // finally returns (asynchronously)
|
|
323
|
-
});
|
|
324
|
-
}; // dir
|
|
325
|
-
|
|
326
|
-
FileNode.prototype.reconsiderNodeKind = function() {
|
|
327
|
-
var anyMod = this.resource && (this.customName || this.permissions || this.deletedItems); // is this node storing any modification
|
|
328
|
-
|
|
329
|
-
switch (this.nodeKind) {
|
|
330
|
-
case NK.FIXED:
|
|
331
|
-
return; // we'll never change this
|
|
332
|
-
case NK.MOD:
|
|
333
|
-
if (anyMod) return; // no change needed
|
|
334
|
-
// we should not be MOD anymore. We must be SEMITEMP if any child is non-temp, otherwise TEMP.
|
|
335
|
-
anyNonTemp = false;
|
|
336
|
-
for (var i=0, a=this.children, l=a.length; i<l; ++i) {
|
|
337
|
-
if (anyNonTemp = (!a[i].isTemp())) break;
|
|
338
|
-
}
|
|
339
|
-
if (anyNonTemp) {
|
|
340
|
-
this.nodeKind = NK.SEMITEMP;
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
this.nodeKind = NK.TEMP;
|
|
344
|
-
// becoming TEMP, we must remove the reference hold by the parent
|
|
345
|
-
var v = this.parent;
|
|
346
|
-
if (!v) return;
|
|
347
|
-
v = v.children;
|
|
348
|
-
var i = v && v.indexOf(this);
|
|
349
|
-
assert(v && i>=0, 'mod-nodes should be always linked to their parents');
|
|
350
|
-
v.splice(i, 1);
|
|
351
|
-
this.parent.reconsiderNodeKind();
|
|
352
|
-
return;
|
|
353
|
-
case NK.TEMP:
|
|
354
|
-
case NK.SEMITEMP:
|
|
355
|
-
if (!anyMod) return;
|
|
356
|
-
this.nodeKind = NK.MOD; // we got some mods, so this is now a MOD
|
|
357
|
-
// create a filenode for each subfolder between "this" and its parent
|
|
358
|
-
var p = this.parent;
|
|
359
|
-
assert(p, 'parent');
|
|
360
|
-
var v = this.resourceRelativeTo(p); // path relative to the parent
|
|
361
|
-
v = v.split(/[\\/]/); // to pieces
|
|
362
|
-
v.pop(); // take out last piece, already incarnated by "this"
|
|
363
|
-
v.forEach(function(v) {
|
|
364
|
-
p = new FileNode(NK.SEMITEMP, v, {parent:p}); // make a new node, and link it to the last one
|
|
365
|
-
});
|
|
366
|
-
this.parent = p; // now link to the last node
|
|
367
|
-
if (p.isTemp()) {
|
|
368
|
-
p.nodeKind = NK.SEMITEMP;
|
|
369
|
-
}
|
|
370
|
-
return;
|
|
371
|
-
default:
|
|
372
|
-
assert(0, 'bad nodeKind');
|
|
373
|
-
}
|
|
374
|
-
}; // reconsiderNodeKind
|
|
375
|
-
|
|
376
|
-
FileNode.prototype.getURI = function(trailingSlashForFolders) {
|
|
377
|
-
if (this.isRoot()) return '/';
|
|
378
|
-
return this.parent.getURI()
|
|
379
|
-
+ encodeURI(this.name)
|
|
380
|
-
+ (this.isFolder() ? '/' : '');
|
|
381
|
-
}; // getURI
|
|
382
|
-
|
|
383
|
-
FileNode.prototype.delete = function(cb){
|
|
384
|
-
switch (this.nodeKind) {
|
|
385
|
-
case NK.TEMP:
|
|
386
|
-
var _this = this;
|
|
387
|
-
this.getFolder(function(fldr){
|
|
388
|
-
assert(fldr, 'root?');
|
|
389
|
-
if (fldr.hasDeleted(_this.resource)) return; // we have it already in
|
|
390
|
-
fldr.deletedItems.push(
|
|
391
|
-
path.basename(_this.resource) + (_this.isFolder() ? '/' : '')
|
|
392
|
-
);
|
|
393
|
-
fldr.reconsiderNodeKind();
|
|
394
|
-
});
|
|
395
|
-
break;
|
|
396
|
-
case NK.MOD:
|
|
397
|
-
case NK.FIXED:
|
|
398
|
-
this.parent = null;
|
|
399
|
-
break;
|
|
400
|
-
default:
|
|
401
|
-
assert(0, 'bad nodeKind');
|
|
402
|
-
}
|
|
403
|
-
}; // delete
|
package/main.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @author Massimo Melina <a@rejetto.com>
|
|
3
|
-
*/
|
|
4
|
-
require('./lib/common');
|
|
5
|
-
debug();
|
|
6
|
-
GLOBAL.vfs = new vfsLib.Vfs();
|
|
7
|
-
vfs.root.set('C:\\vedere').add('c:\\data\\pics\\fantasy');
|
|
8
|
-
vfs.root.add('2', function(node){ node.add('3') });
|
|
9
|
-
|
|
10
|
-
var fileServer = require('./file-server');
|
|
11
|
-
var listenOn = {port:8, ip:'0.0.0.0'};
|
|
12
|
-
fileServer.start(listenOn);
|
|
13
|
-
|
|
14
|
-
var adminServer = require('./admin-server');
|
|
15
|
-
var adminOn = {port:88, ip:'127.0.0.1'};
|
|
16
|
-
adminServer.start(adminOn);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// still trying
|
|
20
|
-
function debug(){
|
|
21
|
-
require('net').createServer(function(sock){
|
|
22
|
-
require('repl').start('debug> ', sock, undefined, true);
|
|
23
|
-
}).listen('6969');
|
|
24
|
-
}
|
package/note.txt
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
=== FEASIBILITY
|
|
2
|
-
distribution: how? size?
|
|
3
|
-
https://github.com/wearefractal/npkg
|
|
4
|
-
npm install hfs
|
|
5
|
-
system integration
|
|
6
|
-
some of these features are expected to not be possible with Node, but must be verified.
|
|
7
|
-
Those who are not possible will be achieved with a different executable communicating with node possibly via socket.
|
|
8
|
-
background notifications
|
|
9
|
-
Windows' tray icons
|
|
10
|
-
automatic handling starting/restaring of the server
|
|
11
|
-
Windows' services
|
|
12
|
-
easy way to add to the VFS, possibly starting HFS if it's not running
|
|
13
|
-
Windows' shell context menu
|
|
14
|
-
|
|
15
|
-
=== DESIGN
|
|
16
|
-
- GUI: all web
|
|
17
|
-
- admin on different port, to eventually accept connection only in local
|
|
18
|
-
- executable helper to get some features:
|
|
19
|
-
- tray icon for
|
|
20
|
-
- start/stop
|
|
21
|
-
- easy access to administration
|
|
22
|
-
- notification
|
|
23
|
-
- shell context menu
|
|
24
|
-
- add files via right click
|
|
25
|
-
- Windows' service
|
|
26
|
-
- webservices
|
|
27
|
-
- it should be possible to build an ajax-based webapp, like a straight template like for HFS 2.2
|
|
28
|
-
- both webservices and template engine
|
|
29
|
-
- does the webapp need a template engine at all or should it all be done via ajax?
|
|
30
|
-
- login
|
|
31
|
-
- folder list
|
|
32
|
-
- navigate folders (get folder by folder, or whole tree for speed?)
|
|
33
|
-
- search
|
|
34
|
-
- select & action (archive, delete, rename...)
|
|
35
|
-
- the web apps must perfectly working offline, don't rely on online resources (or do it just as an option or gracefully degrade)
|
|
36
|
-
|
|
37
|
-
=== GUI
|
|
38
|
-
libraries to evaluate
|
|
39
|
-
extjs
|
|
40
|
-
amplesdk http://www.amplesdk.com/examples/markup/xul/
|
|
41
|
-
pergola http://www.dotuscomus.com/pergola/examples.html
|
|
42
|
-
|
|
43
|
-
=== FRONT END
|
|
44
|
-
login (cookie based)
|
|
45
|
-
|
|
46
|
-
switch on url resource type
|
|
47
|
-
case 'file': serve file
|
|
48
|
-
case 'link': redirect
|
|
49
|
-
case 'folder':
|
|
50
|
-
switch ($format)
|
|
51
|
-
case nothing: serve front-end web app, with this folder already selected
|
|
52
|
-
case 'tar': serve archive
|
|
53
|
-
case 'zip': serve archive
|
|
54
|
-
default: unknown
|
|
55
|
-
|
|
56
|
-
http://superdit.com/2011/06/01/extjs-simple-file-browser/
|
|
57
|
-
|
|
58
|
-
=== VFS
|
|
59
|
-
- able to
|
|
60
|
-
- add virtual items, (will override others with same name)
|
|
61
|
-
- add real items, (override)
|
|
62
|
-
- renamed, (a real item with customName. Remember that an existance check is always done)
|
|
63
|
-
- deleted, (this make the item with same resource to be skipped)
|
|
64
|
-
these are not child nodes, but are the names are kept in an object of the folder
|
|
65
|
-
- various options set (like hidden, permission, log, counting, comment, realm, icon)
|
|
66
|
-
- file node permissions by account (values: anyone, anonymous, any account, account list)
|
|
67
|
-
- NOT the old "access", it's just download+browse
|
|
68
|
-
- visible (this will make this item appear or not in lists, but won't prevent download)
|
|
69
|
-
default: anyone
|
|
70
|
-
- browse (only folders: prevent display of items inside, but with a message, not as if the folder was empty [recursive])
|
|
71
|
-
default: anyone
|
|
72
|
-
- download/stream [recursive]
|
|
73
|
-
default: anyone
|
|
74
|
-
- archive [recursive]
|
|
75
|
-
default: anyone
|
|
76
|
-
- upload (only folders [recursive])
|
|
77
|
-
default: no one
|
|
78
|
-
- delete [recursive]
|
|
79
|
-
default: no one
|
|
80
|
-
- options and metadata
|
|
81
|
-
- log (allow logging of this item [recursive])
|
|
82
|
-
default: yes
|
|
83
|
-
- logMask (only folders [recursive])
|
|
84
|
-
default: *
|
|
85
|
-
- count as download [recursive]
|
|
86
|
-
default: yes
|
|
87
|
-
- count as download Mask (only folders [recursive])
|
|
88
|
-
default: *
|
|
89
|
-
- upload mask (only folders [recursive])
|
|
90
|
-
default: *
|
|
91
|
-
- visibility mask (only folders [recursive])
|
|
92
|
-
default: *
|
|
93
|
-
- download mask (only folders [recursive])
|
|
94
|
-
default: *
|
|
95
|
-
- default file mask (only folders [recursive])
|
|
96
|
-
default: index.htm*;default.html*
|
|
97
|
-
- ?(leave it to future versions) auto-hide empty folders (folders only)
|
|
98
|
-
default: no
|
|
99
|
-
- hide extension [recursive]
|
|
100
|
-
default: no
|
|
101
|
-
- comment
|
|
102
|
-
- icon
|
|
103
|
-
- ? message when not allowed
|
|
104
|
-
- permissions and options have default values that are enforced when not assigned, to not clutter the stored data structure
|
package/speedtest.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileOverview This should show the best performance we can expect
|
|
3
|
-
* @author Massimo Melina <a@rejetto.com>
|
|
4
|
-
*/
|
|
5
|
-
var v = process.argv;
|
|
6
|
-
var myGigFile = v.length >= 3 ? v[2] : '/bigfile.avi';
|
|
7
|
-
|
|
8
|
-
var http = require('http');
|
|
9
|
-
var fs = require('fs');
|
|
10
|
-
|
|
11
|
-
var srv = http.createServer(function(httpReq,httpRes){
|
|
12
|
-
console.log('serving');
|
|
13
|
-
|
|
14
|
-
httpRes.writeHead(200);
|
|
15
|
-
fs.createReadStream(myGigFile).pipe(httpRes);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
var port = 888;
|
|
19
|
-
srv.listen(port, '0.0.0.0', function onListen(){
|
|
20
|
-
console.log('listening on '+port);
|
|
21
|
-
});
|
package/static/backend.css
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
body { font:10pt verdana, arial, sans-serif; }
|
|
2
|
-
a img { border:0; } /* conform IE */
|
|
3
|
-
#vfs ul { list-style:none; padding:0; }
|
|
4
|
-
#vfs ul ul { list-style:none; padding-left:3em; }
|
|
5
|
-
#vfs li { border:2px solid transparent; padding:0.1em 0.2em }
|
|
6
|
-
#vfs li.selected { background:#ddf; border-color:#99f; }
|
|
7
|
-
#vfs li.hovered { background:#eee; }
|
|
8
|
-
#vfs .expansion-button { margin-right:0.5em; cursor:pointer; }
|
|
9
|
-
#vfs .expansion-button.hovered { background-color:#ddd; }
|
|
10
|
-
#vfs li.collapsed>ul { display:none; }
|
|
11
|
-
#vfs .no-children { color:#888; }
|
|
12
|
-
#vfs .no-children:before,
|
|
13
|
-
#vfs .no-children:after { content:"..."; }
|
|
14
|
-
#vfs li .icon img { height:1.5em; margin-right:0.5em; vertical-align:middle; }
|
package/static/backend.html
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<title>HFS 3 back end</title>
|
|
6
|
-
<link rel="stylesheet" type="text/css" href="/~/backend.css" />
|
|
7
|
-
|
|
8
|
-
<!--[if lt IE 9 ]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]-->
|
|
9
|
-
<script src='/socket.io/socket.io.js'></script>
|
|
10
|
-
<script src='/~/jquery.js'></script>
|
|
11
|
-
<script src='/~/extending.js'></script>
|
|
12
|
-
<script src='/~/misc.js'></script>
|
|
13
|
-
<script src='/~/backend.js'></script>
|
|
14
|
-
</head>
|
|
15
|
-
<body>
|
|
16
|
-
<h1>Back end</h1>
|
|
17
|
-
<div id='pane-vfs'>
|
|
18
|
-
<h2>Virtual File System</h2>
|
|
19
|
-
<div id='vfs-buttons'>
|
|
20
|
-
<button id='bindItem'>bind to disk</button>
|
|
21
|
-
<button id='addItem'>add item</button>
|
|
22
|
-
<button id='renameItem'>rename</button>
|
|
23
|
-
<button id='deleteItem'>delete</button>
|
|
24
|
-
</div>
|
|
25
|
-
<div id='vfs'>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
<form>
|
|
29
|
-
<input id='just-for-focus-tests' />
|
|
30
|
-
</form>
|
|
31
|
-
</body>
|
|
32
|
-
</html>
|