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/admin-server.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileOverview This serves the back-end GUI and all it needs to perform server-side actions.
|
|
3
|
-
* @author Massimo Melina <a@rejetto.com>
|
|
4
|
-
*/
|
|
5
|
-
var http = require('http');
|
|
6
|
-
var socket_io = require('socket.io');
|
|
7
|
-
var serving = require('./lib/serving');
|
|
8
|
-
|
|
9
|
-
exports.start = function(listenOn) {
|
|
10
|
-
srv.listen(listenOn.port, listenOn.ip, function(){
|
|
11
|
-
dbg('listening on port '+listenOn.port);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
var srv = http.createServer(function(httpReq,httpRes){
|
|
16
|
-
if (!serving.parseUrl(httpReq)) return;
|
|
17
|
-
|
|
18
|
-
/*
|
|
19
|
-
var peer = httpReq.socket.address(); // bug: currently peer.port is our listening port, while we want to show the port of the socket serving the connection
|
|
20
|
-
dbg('serving '+peer.address+':'+peer.port+' '+httpReq.url);
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
if (serving.serveStatic(httpReq, httpRes)) return; // access to the special 'static' folder
|
|
24
|
-
if (httpReq.uri == '/') {
|
|
25
|
-
serving.serveFile('static/backend.html', httpRes);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
serve404(httpRes); // we serve nothing else
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
srv.on('error', function(err){
|
|
32
|
-
switch (err.code) {
|
|
33
|
-
case 'EADDRINUSE':
|
|
34
|
-
return dbg('port '+listenOn.port+' busy');
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
/* converts FileNode to an object that's ready to be streamed to the back-end.
|
|
39
|
-
@param {number} depth specifies how many levels of children should be included in the structure.
|
|
40
|
-
@param {function} cb is necessary if you specify a depth that's more than zero
|
|
41
|
-
@return the object representing the FileNode if no depth is specified. Otherwise the returning turns into
|
|
42
|
-
an async fashion and you need to specify a callback to retrieve the result.
|
|
43
|
-
*/
|
|
44
|
-
function nodeToObject(fnode, depth, cb) {
|
|
45
|
-
assert(!cb || typeof cb == 'function', 'cb');
|
|
46
|
-
if (!fnode) {
|
|
47
|
-
if (cb) cb(false);
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
assert(fnode instanceof vfsLib.FileNode, 'fnode');
|
|
51
|
-
|
|
52
|
-
var res = ceLib.extenduptolevel({name:fnode.name}, fnode, 1); // make a copy of the whole object without recurring, and overwriting the getter 'name'
|
|
53
|
-
delete res._parent; // this makes a circular reference
|
|
54
|
-
delete res.children; // in case we want the true listing, not just the children
|
|
55
|
-
delete res.customName;
|
|
56
|
-
// save bandwidth by not sending some empty properties
|
|
57
|
-
if (res.deletedItems
|
|
58
|
-
&& !res.deletedItems.length) {
|
|
59
|
-
delete res.deletedItems;
|
|
60
|
-
}
|
|
61
|
-
if (!res.resource) {
|
|
62
|
-
delete res.resource;
|
|
63
|
-
}
|
|
64
|
-
// depth is not required, or not possible, our job ends here
|
|
65
|
-
if (!depth
|
|
66
|
-
|| !fnode.isFolder()) {
|
|
67
|
-
if (cb) cb(res);
|
|
68
|
-
return res;
|
|
69
|
-
}
|
|
70
|
-
// this is necessarily an async procedure: require a callback
|
|
71
|
-
assert(cb, 'cb');
|
|
72
|
-
// recur on children
|
|
73
|
-
fnode.dir(function(items){
|
|
74
|
-
res.children = [];
|
|
75
|
-
async.forEach(items.getProperties(), function(e, doneThis){
|
|
76
|
-
nodeToObject(e, depth-1, function(obj){
|
|
77
|
-
res.children.push(obj);
|
|
78
|
-
doneThis();
|
|
79
|
-
});
|
|
80
|
-
}, cb.bind(this,res));
|
|
81
|
-
});
|
|
82
|
-
} // nodeToObject
|
|
83
|
-
|
|
84
|
-
/*
|
|
85
|
-
SET UP SOCKET.IO
|
|
86
|
-
*/
|
|
87
|
-
|
|
88
|
-
var io = exports.io = socket_io.listen(srv);
|
|
89
|
-
serving.setupSocketIO(io);
|
|
90
|
-
io.sockets.on('connection', function(socket){
|
|
91
|
-
|
|
92
|
-
socket.on('vfs.get', function onGet(data, cb) {
|
|
93
|
-
if (serving.ioError(!data ? data
|
|
94
|
-
: typeof data.uri != 'string' ? 'uri'
|
|
95
|
-
: null, cb)) return;
|
|
96
|
-
|
|
97
|
-
vfs.fromUrl(data.uri, function(fnode) {
|
|
98
|
-
nodeToObject(fnode, data.depth, cb);
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// set properties of a vfs item
|
|
103
|
-
socket.on('vfs.set', function onSet(data, cb){
|
|
104
|
-
// assertions
|
|
105
|
-
if (serving.ioError(!data ? 'data'
|
|
106
|
-
: typeof data.uri != 'string' ? 'uri'
|
|
107
|
-
: null, cb)) return;
|
|
108
|
-
|
|
109
|
-
vfs.fromUrl(data.uri, function(fnode) {
|
|
110
|
-
if (!fnode) {
|
|
111
|
-
serving.ioError('not found');
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (data.name) {
|
|
115
|
-
if (serving.ioError(typeof data.name != 'string' ? 'name' : null, cb)) return;
|
|
116
|
-
fnode.name = data.name;
|
|
117
|
-
serving.ioOk(cb);
|
|
118
|
-
}
|
|
119
|
-
else if (data.resource) {
|
|
120
|
-
if (serving.ioError(typeof data.resource != 'string' ? 'resource' : null, cb)) return;
|
|
121
|
-
fnode.set(data.resource, serving.ioOk.bind(this,cb));
|
|
122
|
-
}
|
|
123
|
-
notifyVfsChange(socket, fnode.getURI().excludeTrailing('/'));
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// add an item to the vfs
|
|
128
|
-
socket.on('vfs.add', function onAdd(data, cb){
|
|
129
|
-
// assertions
|
|
130
|
-
if (serving.ioError(!data ? 'data'
|
|
131
|
-
: typeof data.uri !== 'string' ? 'uri'
|
|
132
|
-
: typeof data.resource !== 'string' ? 'resource'
|
|
133
|
-
: null, cb)) return;
|
|
134
|
-
|
|
135
|
-
vfs.fromUrl(data.uri, function(fnode) {
|
|
136
|
-
if (!fnode) {
|
|
137
|
-
serving.ioError('uri not found', cb);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
var already = fnode.getChildByName(path.basename(data.resource)); // check if it already exists
|
|
141
|
-
if (already) {
|
|
142
|
-
serving.ioError('already exists', cb);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
fnode.add(data.resource, function(newNode){
|
|
146
|
-
serving.ioOk(cb, {item:nodeToObject(newNode)});
|
|
147
|
-
notifyVfsChange(socket, data.uri);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// delete item, make it non-existent in the VFS
|
|
153
|
-
socket.on('vfs.delete', function onRemove(data, cb){
|
|
154
|
-
// assertions
|
|
155
|
-
if (serving.ioError(!data ? 'data'
|
|
156
|
-
: typeof data.uri !== 'string' ? 'uri'
|
|
157
|
-
: null, cb)) return;
|
|
158
|
-
|
|
159
|
-
vfs.fromUrl(data.uri, function(fnode){
|
|
160
|
-
if (!fnode) {
|
|
161
|
-
serving.ioError('uri not found', cb)
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
fnode.getFolder(function(folder){
|
|
165
|
-
fnode.delete();
|
|
166
|
-
// if we just deleted a dynamic item, the GUI may need an extra refresh
|
|
167
|
-
serving.ioOk(cb, {
|
|
168
|
-
dynamicItem: fnode.isTemp() && path.basename(fnode.resource)+(fnode.isFolder() ? '/' : ''), // trailing slash to denote folders
|
|
169
|
-
folderDeletedCount: folder.deletedItems ? folder.deletedItems.length : 0
|
|
170
|
-
});
|
|
171
|
-
notifyVfsChange(socket, folder.getURI());
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// restore a temp item that was deleted
|
|
177
|
-
socket.on('vfs.restore', function onRestore(data, cb){
|
|
178
|
-
// assertions
|
|
179
|
-
if (serving.ioError(!data ? 'data'
|
|
180
|
-
: typeof data.uri !== 'string' ? 'uri'
|
|
181
|
-
: typeof data.resource !== 'string' ? 'resource'
|
|
182
|
-
: null, cb)) return;
|
|
183
|
-
|
|
184
|
-
vfs.fromUrl(data.uri, function(fnode){
|
|
185
|
-
if (!fnode) {
|
|
186
|
-
serving.ioError('uri not found', cb)
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
if (!fnode.restoreDeleted(data.resource)) {
|
|
190
|
-
serving.ioError('failed');
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
fnode.createFileNodeFromRelativeUri(data.resource, function(child){
|
|
194
|
-
serving.ioOk(cb, {item:child});
|
|
195
|
-
notifyVfsChange(socket, fnode.getURI());
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
socket.on('info.get', function onInfo(data, cb){
|
|
201
|
-
serving.ioOk(cb, {caseSensitiveFileNames:misc.caseSensitiveFileNames});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
notifyVfsChange = function(socket, uri) {
|
|
207
|
-
dbg('vfs.changed');
|
|
208
|
-
[socket.broadcast, require('./file-server').io.sockets].forEach(function(o){
|
|
209
|
-
o.emit('vfs.changed', {uri:uri});
|
|
210
|
-
});
|
|
211
|
-
}; // notifyVfsChange
|
|
212
|
-
|
package/cli.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileOverview command line interface to the server
|
|
3
|
-
* @author Massimo Melina <a@rejetto.com>
|
|
4
|
-
*/
|
|
5
|
-
require('./lib/common');
|
|
6
|
-
var socket_io = require('socket.io-client');
|
|
7
|
-
|
|
8
|
-
// read arguments
|
|
9
|
-
var v = process.argv;
|
|
10
|
-
if (v.length < 3) { // quick help
|
|
11
|
-
log('Usage: node '+path.basename(v[1])+' <path>');
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
var fpath = v[2];
|
|
15
|
-
var under = v.length < 4 ? '/' : v[3];
|
|
16
|
-
|
|
17
|
-
// connect to admin-server
|
|
18
|
-
var socket = socket_io.connect('http://localhost:88');
|
|
19
|
-
socket.on('connect', function () {
|
|
20
|
-
// ask to add this file
|
|
21
|
-
socket.emit('vfs.add', {uri:under, resource:fpath, depth:1}, function(data){
|
|
22
|
-
if (!data) {
|
|
23
|
-
log('communication error');
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
if (!data.ok) {
|
|
27
|
-
log('error: '+(data.error || 'generic'));
|
|
28
|
-
process.exit(2);
|
|
29
|
-
}
|
|
30
|
-
socket.disconnect();
|
|
31
|
-
process.exit(0);
|
|
32
|
-
});
|
|
33
|
-
});
|
package/file-server.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileOverview This serves the front-end GUI and all it needs to perform server-side actions.
|
|
3
|
-
* @author Massimo Melina <a@rejetto.com>
|
|
4
|
-
*/
|
|
5
|
-
var http = require('http');
|
|
6
|
-
var socket_io = require('socket.io');
|
|
7
|
-
var serving = require('./lib/serving');
|
|
8
|
-
|
|
9
|
-
exports.start = function(listenOn) {
|
|
10
|
-
listeningOn = listenOn;
|
|
11
|
-
srv.listen(listenOn.port, listenOn.ip, function onListen(){
|
|
12
|
-
dbg('listening on port '+listenOn.port);
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/*
|
|
17
|
-
SET UP THE HTTP SERVER
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
var listeningOn; // keep track of the tcp coordinates we are currently accepting requests
|
|
21
|
-
|
|
22
|
-
var srv = http.createServer(function(httpReq,httpRes){
|
|
23
|
-
if (!serving.parseUrl(httpReq)) return;
|
|
24
|
-
|
|
25
|
-
var peer = httpReq.socket.address();
|
|
26
|
-
dbg('serving '+peer.address+':'+peer.port+' '+httpReq.url);
|
|
27
|
-
|
|
28
|
-
serving.serveStatic(httpReq, httpRes)
|
|
29
|
-
|| serveFromVFS(httpReq, httpRes);
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
srv.on('error', function(err){
|
|
34
|
-
switch (err.code) {
|
|
35
|
-
case 'EADDRINUSE':
|
|
36
|
-
return dbg('port '+listeningOn.port+' busy');
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
/*
|
|
41
|
-
SET UP SOCKET.IO
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
var io = exports.io = socket_io.listen(srv);
|
|
45
|
-
serving.setupSocketIO(io);
|
|
46
|
-
io.sockets.on('connection', function(socket){
|
|
47
|
-
//** sequences like these may be better with Step(). Try
|
|
48
|
-
socket.on('get list', function onGetList(data, cb){
|
|
49
|
-
vfs.fromUrl(data.path, function(fnode) {
|
|
50
|
-
getReplyForFolder(fnode, serving.ioOk.bind(this,cb));
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
//////////////////////////////
|
|
56
|
-
|
|
57
|
-
function getReplyForFolder(folder, cb) {
|
|
58
|
-
if (!folder) {
|
|
59
|
-
return cb({error:'not found'});
|
|
60
|
-
}
|
|
61
|
-
folder.dir(function(items){
|
|
62
|
-
assert(items, 'items');
|
|
63
|
-
// convert items to a simpler format
|
|
64
|
-
items.forEach(function(f,name){
|
|
65
|
-
// we'll use short key names to save bandwidth on common fieldnames.
|
|
66
|
-
var it = items[name] = {};
|
|
67
|
-
// type
|
|
68
|
-
it.t = f.itemKind.replace('virtual ',''); // this is a quick and dirty method to get value as file|folder|link
|
|
69
|
-
// size
|
|
70
|
-
if (f.isOnDisk())
|
|
71
|
-
it.s = f.stats.size;
|
|
72
|
-
});//forEach
|
|
73
|
-
|
|
74
|
-
cb({items:items});
|
|
75
|
-
});//dir
|
|
76
|
-
} // getReplyForFolder
|
|
77
|
-
|
|
78
|
-
function serveFromVFS(httpReq, httpRes) {
|
|
79
|
-
vfs.fromUrl(httpReq.uri, function urlCB(node){
|
|
80
|
-
if (!node) {
|
|
81
|
-
httpRes.writeHead(404);
|
|
82
|
-
return httpRes.end();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (node.isFile()) {
|
|
86
|
-
return serving.serveFile(node.resource, httpRes, node.stats.size);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
assert(node.isFolder(), 'must be folder');
|
|
90
|
-
// force trailing slash
|
|
91
|
-
if (httpReq.url.substr(-1) != '/') {
|
|
92
|
-
httpRes.writeHead(301, {
|
|
93
|
-
'Location': httpReq.url+'/'
|
|
94
|
-
});
|
|
95
|
-
return httpRes.end();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
serving.serveFile('static/frontend.html', httpRes)
|
|
99
|
-
});
|
|
100
|
-
} // serveFromVFS
|
package/lib/common.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
require('./extending');
|
|
2
|
-
GLOBAL.path = require('path');
|
|
3
|
-
GLOBAL.util = require('util');
|
|
4
|
-
GLOBAL.os = require('os');
|
|
5
|
-
GLOBAL.fs = require('fs');
|
|
6
|
-
GLOBAL.assert = require('assert');
|
|
7
|
-
GLOBAL.ceLib = require('cloneextend');
|
|
8
|
-
GLOBAL.misc = require('./misc');
|
|
9
|
-
GLOBAL.vfsLib = require('./vfs');
|
|
10
|
-
GLOBAL.async = require('async');
|
package/lib/extending.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
///////// EXTENDING FUNCTION
|
|
2
|
-
|
|
3
|
-
/** as function.bind(), but additional parameters are prepended instead of appended
|
|
4
|
-
* @return {function} proxied function
|
|
5
|
-
*/
|
|
6
|
-
Function.prototype.prebind = function(){
|
|
7
|
-
var args = Array.prototype.slice.call(arguments);
|
|
8
|
-
var scope = args.shift();
|
|
9
|
-
var fun = this;
|
|
10
|
-
return function(){
|
|
11
|
-
var moreArgs = Array.prototype.slice.call(arguments);
|
|
12
|
-
fun.apply(scope, moreArgs.concat(args));
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
///////// EXTENDING STRING
|
|
17
|
-
|
|
18
|
-
/* return a new string filling "this" with arguments' values.
|
|
19
|
-
The filling is done in place of strings in this form {key} or this other form {key|parameter}.
|
|
20
|
-
If first argument is an object, then "key" is used as field name (i.e. property) of the object.
|
|
21
|
-
Otherwise "key" should be a number, and it's the argument's index (zero-based).
|
|
22
|
-
As stated before, keys can have a parameter. If such parameter is in the form \d*-\d* then these numbers
|
|
23
|
-
denote a range of characters to extract (i.e. a substring). Otherwise the parameter is a property name for
|
|
24
|
-
the value (that must be an object or an array in this case).
|
|
25
|
-
*/
|
|
26
|
-
String.prototype.format = function() {
|
|
27
|
-
var args = arguments;
|
|
28
|
-
if (typeof args[0] == 'object')
|
|
29
|
-
args = args[0];
|
|
30
|
-
return this.replace(/\{([-_ a-z0-9]+)(\|([^}]+))?\}/gi, function(){
|
|
31
|
-
var ret = args[arguments[1]];
|
|
32
|
-
var par = arguments[3];
|
|
33
|
-
if (par) {
|
|
34
|
-
var v = /(\d*)-(\d*)/.exec(par); // is it in the "range" form?
|
|
35
|
-
if (v) ret = ret.substring(v[1]-1 || 0, v[2] || ret.length); // extract the substring in range
|
|
36
|
-
else ret = ret[par]; // get property
|
|
37
|
-
}
|
|
38
|
-
return ret;
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
String.prototype.repeat = function(n) {
|
|
43
|
-
var r = '';
|
|
44
|
-
for (var i=0; i<n; i++) r += this;
|
|
45
|
-
return r;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
String.prototype.count = function(sub) {
|
|
49
|
-
return this.split(sub).length-1;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
String.prototype.ss = function(from, to) {
|
|
53
|
-
return this.substring(from<0 ? this.length-from : from, to<0 ? this.length+to : to);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
String.prototype.pad = function(lngt, filler) {
|
|
57
|
-
return (filler || ' ').repeat(Math.max(0,lngt - this.length)) + this;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
String.prototype.escapeRegExp = function() {
|
|
61
|
-
return this.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
String.prototype.startsBy = function(sub, caseInsensitive) {
|
|
65
|
-
return 0 <= this.search(new RegExp('^'+sub.escapeRegExp(), caseInsensitive ? 'i' : ''));
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
String.prototype.endsBy = function(sub, caseInsensitive) {
|
|
69
|
-
return 0 <= this.search(new RegExp(sub.escapeRegExp()+'$', caseInsensitive ? 'i' : ''));
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
String.prototype.includeLeading = function(sub) { return this.startsBy(sub) ? this : sub+this };
|
|
73
|
-
String.prototype.includeTrailing = function(sub) { return this.endsBy(sub) ? this : this+sub };
|
|
74
|
-
// if in the following function the casting to string is not made, the resulting typeof is 'object' instead of 'string' (causing problems in some cases, e.g. using path.join)
|
|
75
|
-
String.prototype.excludeLeading = function(sub) { return this.startsBy(sub) ? this.slice(sub.length) : ''+this };
|
|
76
|
-
String.prototype.excludeTrailing = function(sub) { return this.endsBy(sub) ? this.slice(0,-sub.length) : ''+this };
|
|
77
|
-
|
|
78
|
-
// handy shortcuts
|
|
79
|
-
String.prototype.low = String.prototype.toLowerCase;
|
|
80
|
-
String.prototype.up = String.prototype.toUpperCase;
|
|
81
|
-
|
|
82
|
-
// case insensitive test
|
|
83
|
-
String.prototype.same = function(s){
|
|
84
|
-
return typeof s === 'string'
|
|
85
|
-
&& this.length === s.length
|
|
86
|
-
&& this.low() === s.low()
|
|
87
|
-
}; // String.same
|
|
88
|
-
|
|
89
|
-
String.prototype.in = function(s) {
|
|
90
|
-
switch (typeof s) {
|
|
91
|
-
case 'array':
|
|
92
|
-
case 'string': return s.indexOf(this) >= 0;
|
|
93
|
-
default: return false;
|
|
94
|
-
}
|
|
95
|
-
}; // String.in
|
|
96
|
-
|
|
97
|
-
///////// EXTENDING OBJECT
|
|
98
|
-
|
|
99
|
-
function extendObject(key, value) {
|
|
100
|
-
Object.defineProperty(Object.prototype, key, {
|
|
101
|
-
enumerable: false,
|
|
102
|
-
value: value
|
|
103
|
-
});
|
|
104
|
-
} // extendObject
|
|
105
|
-
|
|
106
|
-
extendObject('getKeyOf', function(value) {
|
|
107
|
-
for (var i in this)
|
|
108
|
-
if (this.hasOwnProperty(i)
|
|
109
|
-
&& this[i] === value)
|
|
110
|
-
return i;
|
|
111
|
-
return null;
|
|
112
|
-
}); // Object.getKeyOf
|
|
113
|
-
|
|
114
|
-
extendObject('forEach', function(cb) {
|
|
115
|
-
for (var i in this)
|
|
116
|
-
if (this.hasOwnProperty(i))
|
|
117
|
-
cb.call(this, this[i], i);
|
|
118
|
-
}); // Object.forEach
|
|
119
|
-
|
|
120
|
-
extendObject('isIn', function(vals) {
|
|
121
|
-
if (arguments.length == 1) {
|
|
122
|
-
return Array.isArray(vals)
|
|
123
|
-
? vals.indexOf(this) >= 0
|
|
124
|
-
: vals.keyOf(this) !== null;
|
|
125
|
-
}
|
|
126
|
-
for (var i in arguments)
|
|
127
|
-
if (arguments[i] == this)
|
|
128
|
-
return true;
|
|
129
|
-
return false;
|
|
130
|
-
}); // Object.isIn
|
|
131
|
-
|
|
132
|
-
extendObject('extend', function(from) {
|
|
133
|
-
var props = Object.getOwnPropertyNames(from);
|
|
134
|
-
var dest = this;
|
|
135
|
-
props.forEach(function(name) {
|
|
136
|
-
var setter = dest.__lookupSetter__(name);
|
|
137
|
-
if (setter) {
|
|
138
|
-
setter.call(dest, from[name]);
|
|
139
|
-
}
|
|
140
|
-
else if (name in dest) {
|
|
141
|
-
var destination = Object.getOwnPropertyDescriptor(from, name);
|
|
142
|
-
Object.defineProperty(dest, name, destination);
|
|
143
|
-
}
|
|
144
|
-
else {
|
|
145
|
-
dest[name] = from[name];
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
return this;
|
|
149
|
-
}); // Object.extend
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
extendObject('getProperties', function(){
|
|
153
|
-
var res = [];
|
|
154
|
-
for (var i in this)
|
|
155
|
-
if (this.hasOwnProperty(i))
|
|
156
|
-
res.push(this[i]);
|
|
157
|
-
return res;
|
|
158
|
-
}); // Object.getProperties
|
package/lib/mime.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
var types = exports.types = {
|
|
2
|
-
'jpg,jpeg': 'image/jpeg',
|
|
3
|
-
'gif': 'image/gif',
|
|
4
|
-
'png': 'image/png',
|
|
5
|
-
'css': 'text/css',
|
|
6
|
-
'js' : 'text/javascript',
|
|
7
|
-
'avi': 'video/avi',
|
|
8
|
-
'html': 'text/html',
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
exports.fromFile = function(file){
|
|
12
|
-
var ext = path.extname(file).substr(1).low();
|
|
13
|
-
for (var w in types) {
|
|
14
|
-
if (w.split(',').indexOf(ext) >= 0) {
|
|
15
|
-
return types[w];
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return false;
|
|
19
|
-
}; // fromFile
|
package/lib/misc.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
//// PROJECT-WIDE FUNCTIONS
|
|
2
|
-
|
|
3
|
-
ceLib = require('cloneextend');
|
|
4
|
-
|
|
5
|
-
////// FIRST, UTILITIES WE WANT TO BE GLOBAL
|
|
6
|
-
|
|
7
|
-
GLOBAL.ABCifB = function(a,b,c) { return b ? ''+a+b+(c||'') : ''; }
|
|
8
|
-
|
|
9
|
-
// like console.log but better: outputs multiple parameters and returns first one, so you can concatenate
|
|
10
|
-
GLOBAL.log = function() {
|
|
11
|
-
var last;
|
|
12
|
-
for (var k in arguments) {
|
|
13
|
-
console.log(last = arguments[k]);
|
|
14
|
-
}
|
|
15
|
-
return last;
|
|
16
|
-
}; // log
|
|
17
|
-
|
|
18
|
-
// outputs to console and to a file (that's cleared at first writing). If 2 parameters are supplied, the first is a label to the data.
|
|
19
|
-
GLOBAL.dbg = function(/*pre, */s) {
|
|
20
|
-
var pre = '';
|
|
21
|
-
if (arguments.length === 2) {
|
|
22
|
-
pre = arguments[0]+': ';
|
|
23
|
-
s = arguments[1];
|
|
24
|
-
}
|
|
25
|
-
var self = arguments.callee;
|
|
26
|
-
if (!self.once) {
|
|
27
|
-
self.once = 1;
|
|
28
|
-
self.fn = 'dbg.txt';
|
|
29
|
-
try { fs.unlinkSync(self.fn); } // this happens only once, who cares if it's blocking
|
|
30
|
-
catch(err) {}
|
|
31
|
-
}
|
|
32
|
-
var stream = fs.createWriteStream(self.fn, {flags:'a'});
|
|
33
|
-
stream.write(pre+s+"\n");
|
|
34
|
-
stream.end();
|
|
35
|
-
console.log('DBG) ', pre, s);
|
|
36
|
-
return s;
|
|
37
|
-
}; // dbg
|
|
38
|
-
|
|
39
|
-
// used as a weaker assert() that doesn't stop execution
|
|
40
|
-
GLOBAL.warning = function(condition, message){ if (!condition) dbg('Condition not met',message) };
|
|
41
|
-
|
|
42
|
-
/*
|
|
43
|
-
meant to implement Enum's. You can pass every value as a separate parameter, or as a single parameter with space as a separator.
|
|
44
|
-
It returns an object with enum's values as keys, and coupled values are a "nicer".
|
|
45
|
-
*/
|
|
46
|
-
GLOBAL.Enum = function() {
|
|
47
|
-
var a = (arguments.length === 1) ? arguments[0].split(' ') : arguments;
|
|
48
|
-
var res = {};
|
|
49
|
-
for (var i=0,l=a.length; i<l; ++i) {
|
|
50
|
-
res[a[i]] = a[i].toLowerCase().replace('_',' '); // valore descrittivo, utile per eventuali output
|
|
51
|
-
}
|
|
52
|
-
return res;
|
|
53
|
-
}; // Enum
|
|
54
|
-
|
|
55
|
-
// type-independent size calculation (currently accepting array's and object's)
|
|
56
|
-
GLOBAL.sizeOf = function(o) {
|
|
57
|
-
if (util.isArray(o))
|
|
58
|
-
return o.length;
|
|
59
|
-
return Object.keys(o).length;
|
|
60
|
-
}; // sizeOf
|
|
61
|
-
|
|
62
|
-
exports.clone = ceLib.clone;
|
|
63
|
-
//exports.extend = ceLib.extend.bind(ceLib); we are currently using {}.extend instead of this
|
|
64
|
-
|
|
65
|
-
exports.isWindows = os.platform() === 'win32';
|
|
66
|
-
exports.caseSensitiveFileNames = !exports.isWindows;
|
|
67
|
-
|
|
68
|
-
exports.sameFileName = function(a,b) {
|
|
69
|
-
return exports.caseSensitiveFileNames ? a === b : a && a.same(b);
|
|
70
|
-
}; // sameFileName
|
|
71
|
-
|
|
72
|
-
exports.round = function(v, decimals) {
|
|
73
|
-
decimals = Math.pow(10, decimals||0);
|
|
74
|
-
return Math.round(v*decimals)/decimals;
|
|
75
|
-
} // round
|
package/lib/serving.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
require('./common');
|
|
2
|
-
var mime = require('./mime');
|
|
3
|
-
var url = require('url');
|
|
4
|
-
|
|
5
|
-
exports.serveFile = serveFile = function(file, httpRes, size, mime_) {
|
|
6
|
-
fs.exists(file, function(exists) {
|
|
7
|
-
if (!exists) {
|
|
8
|
-
serve404(httpRes);
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
var stream = fs.createReadStream(file);
|
|
12
|
-
var headers = {
|
|
13
|
-
'Content-Type': mime_ || mime.fromFile(file) || 'application/octet-stream'
|
|
14
|
-
};
|
|
15
|
-
if (size) {
|
|
16
|
-
headers['Content-Length'] = size;
|
|
17
|
-
}
|
|
18
|
-
httpRes.writeHead(200, headers);
|
|
19
|
-
stream.pipe(httpRes);
|
|
20
|
-
});
|
|
21
|
-
}; // serveFile
|
|
22
|
-
|
|
23
|
-
exports.serve404 = serve404 = function(httpRes) {
|
|
24
|
-
httpRes.writeHead(404);
|
|
25
|
-
httpRes.end();
|
|
26
|
-
} // serve404
|
|
27
|
-
|
|
28
|
-
exports.serveStatic = function(httpReq, httpRes) {
|
|
29
|
-
if (httpReq.uri.substr(0,3) === '/~/') {
|
|
30
|
-
serveFile('static'+httpReq.uri.substr(2), httpRes);
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
return false;
|
|
34
|
-
}; // serveStatic
|
|
35
|
-
|
|
36
|
-
exports.parseUrl = function(httpReq) {
|
|
37
|
-
httpReq.parsedUrl = url.parse(httpReq.url, true);
|
|
38
|
-
with (httpReq.parsedUrl) pathname = decodeURI(pathname);
|
|
39
|
-
httpReq.uri = httpReq.parsedUrl.pathname; // a shortcut, since this is often accessed
|
|
40
|
-
|
|
41
|
-
// check for directory crossing
|
|
42
|
-
if (httpReq.uri.indexOf('..') >= 0) {
|
|
43
|
-
httpRes.writeHead(500);
|
|
44
|
-
httpRes.end('Xdir');
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return true;
|
|
49
|
-
}; // parseUrl
|
|
50
|
-
|
|
51
|
-
// a standardized way to report an assertions' errors over socket.io
|
|
52
|
-
exports.ioError = function(message, cb, more) {
|
|
53
|
-
if (!cb) return;
|
|
54
|
-
assert(typeof cb === 'function', 'cb');
|
|
55
|
-
if (message) {
|
|
56
|
-
if (cb) cb({ok:false, error:message}.extend(more||{}));
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
return false;
|
|
60
|
-
}; // ioError
|
|
61
|
-
|
|
62
|
-
exports.ioOk = ioOk = function(cb, more) {
|
|
63
|
-
if (!cb) return;
|
|
64
|
-
assert(typeof cb === 'function', 'cb');
|
|
65
|
-
cb({ok:true}.extend(more||{}));
|
|
66
|
-
}; // ioOk
|
|
67
|
-
|
|
68
|
-
exports.setupSocketIO = function(io) {
|
|
69
|
-
io.enable('browser client minification'); // send minified client
|
|
70
|
-
io.enable('browser client etag'); // apply etag caching logic based on version number
|
|
71
|
-
io.enable('browser client gzip'); // gzip the file
|
|
72
|
-
io.set('log level', 1); // reduce logging
|
|
73
|
-
// this next command is giving a warning. Disabled for now.
|
|
74
|
-
/*io.set('transports', [ // enable all transports (optional if you want flashsocket)
|
|
75
|
-
'websocket'
|
|
76
|
-
, 'flashsocket'
|
|
77
|
-
, 'htmlfile'
|
|
78
|
-
, 'xhr-polling'
|
|
79
|
-
, 'jsonp-polling'
|
|
80
|
-
]);*/
|
|
81
|
-
}; // setupSocketIO
|