total5 0.0.1-2 → 0.0.1-21
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/api.js +1 -1
- package/builders.js +323 -22
- package/bundles.js +2 -12
- package/cms.js +61 -11
- package/controller.js +141 -32
- package/filestorage.js +39 -19
- package/flow-flowstream.js +412 -246
- package/flow.js +62 -36
- package/flowstream.js +84 -15
- package/global.js +144 -3
- package/http.js +1 -1
- package/image.js +4 -0
- package/images.js +1 -1
- package/index.js +142 -48
- package/jsonschema.js +35 -27
- package/mail.js +9 -7
- package/markdown.js +756 -0
- package/minificators.js +1 -1
- package/nosql-builder.js +1 -1
- package/nosql.js +11 -0
- package/openclient.js +1 -1
- package/package.json +1 -1
- package/querybuilder.js +2 -3
- package/routing.js +113 -31
- package/sourcemap.js +1 -1
- package/test.js +48 -0
- package/tms.js +13 -18
- package/tmsclient.js +4 -0
- package/uibuilder.js +54 -19
- package/utils.js +72 -43
- package/viewengine.js +10 -11
- package/websocket.js +4 -3
- package/workers.js +2 -2
- package/CONTRIBUTING.md +0 -55
- package/helpers/index.js +0 -32
- package/templates.json +0 -74
- package/todo.txt +0 -11
- package/tools/beta.sh +0 -6
- package/tools/release.sh +0 -6
package/controller.js
CHANGED
|
@@ -11,17 +11,21 @@ const REG_MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Min
|
|
|
11
11
|
const REG_ENCODINGCLEANER = /[;\s]charset=utf-8/g;
|
|
12
12
|
|
|
13
13
|
const CHECK_DATA = { POST: 1, PUT: 1, PATCH: 1, DELETE: 1 };
|
|
14
|
-
const CHECK_COMPRESSION = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'text/xml': true, 'image/svg+xml': true, 'text/x-markdown': true, 'text/html': true };
|
|
14
|
+
const CHECK_COMPRESSION = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'application/xml': true, 'text/xml': true, 'image/svg+xml': true, 'text/x-markdown': true, 'text/html': true };
|
|
15
15
|
const CHECK_CHARSET = { 'text/plain': true, 'text/javascript': true, 'text/css': true, 'text/jsx': true, 'application/javascript': true, 'application/x-javascript': true, 'application/json': true, 'text/xml': true, 'text/x-markdown': true, 'text/html': true };
|
|
16
16
|
const CHECK_NOCACHE = { zip: 1, rar: 1 };
|
|
17
17
|
|
|
18
18
|
const GZIP_FILE = { memLevel: 9 };
|
|
19
19
|
const GZIP_STREAM = { memLevel: 1 };
|
|
20
20
|
|
|
21
|
+
const NOCACHE = 'private, no-cache, no-store, max-age=0';
|
|
22
|
+
|
|
21
23
|
function Controller(req, res) {
|
|
22
24
|
|
|
23
25
|
var ctrl = this;
|
|
24
26
|
|
|
27
|
+
req.controller = ctrl;
|
|
28
|
+
|
|
25
29
|
ctrl.req = req;
|
|
26
30
|
ctrl.res = res;
|
|
27
31
|
ctrl.method = ctrl.req.method;
|
|
@@ -36,6 +40,7 @@ function Controller(req, res) {
|
|
|
36
40
|
ctrl.url = ctrl.uri.key;
|
|
37
41
|
ctrl.released = false;
|
|
38
42
|
ctrl.downloaded = false;
|
|
43
|
+
ctrl.protocol = req.connection.encrypted || (req.headers['x-forwarded-protocol'] || req.headers['x-forwarded-proto']) === 'https' ? 'https' : 'http';
|
|
39
44
|
|
|
40
45
|
for (let path of ctrl.split)
|
|
41
46
|
ctrl.split2.push(path.toLowerCase());
|
|
@@ -57,7 +62,7 @@ function Controller(req, res) {
|
|
|
57
62
|
|
|
58
63
|
ctrl.response = {
|
|
59
64
|
status: 200,
|
|
60
|
-
cache: DEBUG,
|
|
65
|
+
cache: global.DEBUG != true,
|
|
61
66
|
minify: true,
|
|
62
67
|
// minifyjson: false
|
|
63
68
|
// encrypt: false
|
|
@@ -120,6 +125,10 @@ Controller.prototype = {
|
|
|
120
125
|
return this.headers['x-requested-with'] === 'XMLHttpRequest';
|
|
121
126
|
},
|
|
122
127
|
|
|
128
|
+
get extension() {
|
|
129
|
+
return this.ext;
|
|
130
|
+
},
|
|
131
|
+
|
|
123
132
|
get ua() {
|
|
124
133
|
if (this.$ua != null)
|
|
125
134
|
return this.$ua;
|
|
@@ -153,8 +162,32 @@ Controller.prototype = {
|
|
|
153
162
|
|
|
154
163
|
};
|
|
155
164
|
|
|
165
|
+
Controller.prototype.callback = function(err, value) {
|
|
166
|
+
|
|
167
|
+
var ctrl = this;
|
|
168
|
+
|
|
169
|
+
if (arguments.length == 0) {
|
|
170
|
+
return function(err, response) {
|
|
171
|
+
if (err)
|
|
172
|
+
ctrl.invalid(err);
|
|
173
|
+
else
|
|
174
|
+
ctrl.json(response);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (err)
|
|
179
|
+
ctrl.invalid(err);
|
|
180
|
+
else {
|
|
181
|
+
if (value === undefined)
|
|
182
|
+
ctrl.success();
|
|
183
|
+
else
|
|
184
|
+
ctrl.json(value);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
};
|
|
188
|
+
|
|
156
189
|
Controller.prototype.csrf = function() {
|
|
157
|
-
return
|
|
190
|
+
return F.def.onCSRFcreate(this);
|
|
158
191
|
};
|
|
159
192
|
|
|
160
193
|
Controller.prototype.redirect = function(value, permanent) {
|
|
@@ -177,9 +210,8 @@ Controller.prototype.html = function(value) {
|
|
|
177
210
|
|
|
178
211
|
ctrl.response.headers['content-type'] = 'text/html';
|
|
179
212
|
|
|
180
|
-
if (value != null)
|
|
213
|
+
if (value != null)
|
|
181
214
|
ctrl.response.value = ctrl.response.minify && F.config.$minifyhtml ? F.TMinificators.html(value) : value;
|
|
182
|
-
}
|
|
183
215
|
|
|
184
216
|
ctrl.flush();
|
|
185
217
|
F.stats.response.html++;
|
|
@@ -208,7 +240,7 @@ Controller.prototype.json = function(value, beautify, replacer) {
|
|
|
208
240
|
|
|
209
241
|
var response = ctrl.response;
|
|
210
242
|
response.headers['content-type'] = 'application/json';
|
|
211
|
-
response.headers['cache-control'] =
|
|
243
|
+
response.headers['cache-control'] = NOCACHE;
|
|
212
244
|
response.headers.vary = 'Accept-Encoding, Last-Modified, User-Agent';
|
|
213
245
|
response.headers.expires = '-1';
|
|
214
246
|
response.value = JSON.stringify(value, beautify ? '\t' : null, replacer);
|
|
@@ -224,7 +256,7 @@ Controller.prototype.jsonstring = function(value) {
|
|
|
224
256
|
|
|
225
257
|
var response = ctrl.response;
|
|
226
258
|
response.headers['content-type'] = 'application/json';
|
|
227
|
-
response.headers['cache-control'] =
|
|
259
|
+
response.headers['cache-control'] = NOCACHE;
|
|
228
260
|
response.headers.vary = 'Accept-Encoding, Last-Modified, User-Agent';
|
|
229
261
|
response.headers.expires = '-1';
|
|
230
262
|
response.value = value;
|
|
@@ -262,7 +294,7 @@ Controller.prototype.invalid = function(value) {
|
|
|
262
294
|
}
|
|
263
295
|
|
|
264
296
|
response.headers['content-type'] = 'application/json';
|
|
265
|
-
response.headers['cache-control'] =
|
|
297
|
+
response.headers['cache-control'] = NOCACHE;
|
|
266
298
|
response.headers.vary = 'Accept-Encoding, Last-Modified, User-Agent';
|
|
267
299
|
response.value = JSON.stringify(err.output(ctrl.language));
|
|
268
300
|
response.status = err.status === 408 ? 503 : err.status;
|
|
@@ -347,7 +379,7 @@ Controller.prototype.fallback = function(code, err) {
|
|
|
347
379
|
ctrl.response.status = 503;
|
|
348
380
|
if (!view) {
|
|
349
381
|
F.temporary.views.$pause = view = new F.TViewEngine.View();
|
|
350
|
-
view.compiled = F.TViewEngine.compile('$pause', F.Fs.readFileSync(F.Path.join(F.config.$
|
|
382
|
+
view.compiled = F.TViewEngine.compile('$pause', F.Fs.readFileSync(F.Path.join(F.config.$total5, 'pause.html'), 'utf8'), false);
|
|
351
383
|
}
|
|
352
384
|
view.model = F.paused;
|
|
353
385
|
} else {
|
|
@@ -355,7 +387,7 @@ Controller.prototype.fallback = function(code, err) {
|
|
|
355
387
|
view = F.temporary.views.$error;
|
|
356
388
|
if (!view) {
|
|
357
389
|
F.temporary.views.$error = view = new F.TViewEngine.View();
|
|
358
|
-
view.compiled = F.TViewEngine.compile('$error', F.Fs.readFileSync(F.Path.join(F.config.$
|
|
390
|
+
view.compiled = F.TViewEngine.compile('$error', F.Fs.readFileSync(F.Path.join(F.config.$total5, 'error.html'), 'utf8'), false);
|
|
359
391
|
}
|
|
360
392
|
view.model = { code: code, status: F.TUtils.httpstatus(code), error: err ? (DEBUG ? err.toString() : '') : '' };
|
|
361
393
|
}
|
|
@@ -566,6 +598,16 @@ Controller.prototype.proxy = function(opt) {
|
|
|
566
598
|
|
|
567
599
|
};
|
|
568
600
|
|
|
601
|
+
Controller.prototype.done = function(arg) {
|
|
602
|
+
var ctrl = this;
|
|
603
|
+
return function(err, response) {
|
|
604
|
+
if (err)
|
|
605
|
+
ctrl.invalid(err);
|
|
606
|
+
else
|
|
607
|
+
ctrl.json(DEF.onSuccess(arg === true ? response : arg));
|
|
608
|
+
};
|
|
609
|
+
};
|
|
610
|
+
|
|
569
611
|
Controller.prototype.success = function(value) {
|
|
570
612
|
F.TUtils.success.value = value;
|
|
571
613
|
this.json(F.TUtils.success);
|
|
@@ -735,20 +777,21 @@ Controller.prototype.free = function() {
|
|
|
735
777
|
ctrl.payload = null;
|
|
736
778
|
|
|
737
779
|
// Potential problem
|
|
738
|
-
ctrl.body = null;
|
|
739
|
-
ctrl.params = null;
|
|
740
|
-
ctrl.query = null;
|
|
780
|
+
// ctrl.body = null;
|
|
781
|
+
// ctrl.params = null;
|
|
782
|
+
// ctrl.query = null;
|
|
741
783
|
|
|
742
784
|
if (ctrl.preventclearfiles != true)
|
|
743
785
|
ctrl.clear();
|
|
744
786
|
|
|
745
787
|
// Clear resources
|
|
788
|
+
ctrl.req.controller = null;
|
|
746
789
|
|
|
747
790
|
};
|
|
748
791
|
|
|
749
792
|
Controller.prototype.hostname = function(path) {
|
|
750
793
|
var ctrl = this;
|
|
751
|
-
return ctrl.
|
|
794
|
+
return ctrl.protocol + '://' + ctrl.headers.host + (path ? path : '');
|
|
752
795
|
};
|
|
753
796
|
|
|
754
797
|
Controller.prototype.$route = function() {
|
|
@@ -860,16 +903,33 @@ function readfile(filename, callback) {
|
|
|
860
903
|
});
|
|
861
904
|
}
|
|
862
905
|
|
|
863
|
-
function
|
|
906
|
+
Controller.prototype.notmodified = function(date) {
|
|
907
|
+
var ctrl = this;
|
|
864
908
|
if (ctrl.headers['if-modified-since'] === date) {
|
|
865
909
|
ctrl.response.status = 304;
|
|
866
|
-
ctrl.response.headers['cache-control'] = 'public, max-age=
|
|
910
|
+
ctrl.response.headers['cache-control'] = 'public, must-revalidate, max-age=' + F.config.$httpmaxage; // 5 min.
|
|
867
911
|
ctrl.response.headers['last-modified'] = date;
|
|
868
912
|
ctrl.flush();
|
|
869
913
|
F.stats.response.notmodified++;
|
|
870
914
|
return true;
|
|
871
915
|
}
|
|
872
|
-
}
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
Controller.prototype.httpcache = function(date) {
|
|
919
|
+
var ctrl = this;
|
|
920
|
+
|
|
921
|
+
if (date instanceof Date)
|
|
922
|
+
date = date.toUTCString();
|
|
923
|
+
|
|
924
|
+
if (!ctrl.response.headers.expires)
|
|
925
|
+
ctrl.response.headers.expires = F.config.$httpexpire;
|
|
926
|
+
|
|
927
|
+
if (!ctrl.response.headers['cache-control'])
|
|
928
|
+
ctrl.response.headers['cache-control'] = 'public, must-revalidate, max-age=' + F.config.$httpmaxage; // 5 minute cache for revalidate (304)
|
|
929
|
+
|
|
930
|
+
ctrl.response.headers['last-modified'] = date;
|
|
931
|
+
ctrl.response.headers.etag = '858' + F.config.$httpetag;
|
|
932
|
+
};
|
|
873
933
|
|
|
874
934
|
function multipart(ctrl) {
|
|
875
935
|
|
|
@@ -890,7 +950,7 @@ function multipart(ctrl) {
|
|
|
890
950
|
}
|
|
891
951
|
|
|
892
952
|
var boundary = type.substring(index + 9, end);
|
|
893
|
-
var parser = F.TUtils.multipartparser(boundary, ctrl, function(err, meta) {
|
|
953
|
+
var parser = F.TUtils.multipartparser(boundary, ctrl.req, function(err, meta) {
|
|
894
954
|
|
|
895
955
|
F.stats.performance.download += meta.size / 1024 / 1024;
|
|
896
956
|
|
|
@@ -909,6 +969,7 @@ function multipart(ctrl) {
|
|
|
909
969
|
if (index !== -1)
|
|
910
970
|
file.filename = file.filename.substring(index + 1);
|
|
911
971
|
|
|
972
|
+
file.ext = F.TUtils.getExtension(file.filename);
|
|
912
973
|
ctrl.files.push(file);
|
|
913
974
|
}
|
|
914
975
|
|
|
@@ -936,9 +997,10 @@ function multipart(ctrl) {
|
|
|
936
997
|
}
|
|
937
998
|
|
|
938
999
|
function authorize(ctrl) {
|
|
939
|
-
if (
|
|
1000
|
+
if (F.def.onAuthorize) {
|
|
940
1001
|
var opt = new F.TBuilders.Options(ctrl);
|
|
941
1002
|
opt.TYPE = 'auth'; // important
|
|
1003
|
+
opt.query = ctrl.query;
|
|
942
1004
|
opt.next = opt.callback;
|
|
943
1005
|
opt.$callback = function(err, user) {
|
|
944
1006
|
let auth = user ? 1 : 2;
|
|
@@ -953,7 +1015,7 @@ function authorize(ctrl) {
|
|
|
953
1015
|
ctrl.fallback(401);
|
|
954
1016
|
}
|
|
955
1017
|
};
|
|
956
|
-
|
|
1018
|
+
F.def.onAuthorize(opt);
|
|
957
1019
|
} else
|
|
958
1020
|
execute(ctrl);
|
|
959
1021
|
}
|
|
@@ -967,16 +1029,34 @@ function execute(ctrl) {
|
|
|
967
1029
|
ctrl.params[param.name] = value;
|
|
968
1030
|
}
|
|
969
1031
|
|
|
1032
|
+
if (!ctrl.language && F.def.onLocalize)
|
|
1033
|
+
ctrl.language = F.def.onLocalize(ctrl);
|
|
1034
|
+
|
|
970
1035
|
if (ctrl.route.middleware.length) {
|
|
971
1036
|
middleware(ctrl);
|
|
972
1037
|
} else {
|
|
973
1038
|
if (ctrl.route.api) {
|
|
974
1039
|
let body = ctrl.body;
|
|
975
1040
|
if (body && typeof(body) === 'object' && body.schema && typeof(body.schema) === 'string') {
|
|
1041
|
+
|
|
1042
|
+
let index = body.schema.indexOf('?');
|
|
1043
|
+
let query = null;
|
|
1044
|
+
|
|
1045
|
+
if (index !== -1) {
|
|
1046
|
+
query = body.schema.substring(index + 1);
|
|
1047
|
+
body.schema = body.schema.substring(0, index);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
976
1050
|
let schema = body.schema.split('/');
|
|
977
1051
|
let endpoint = ctrl.route.api[schema[0]];
|
|
978
|
-
let params = {};
|
|
979
1052
|
if (endpoint) {
|
|
1053
|
+
|
|
1054
|
+
if ((endpoint.auth === 1 && ctrl.user == null) || (endpoint.auth === 2 && ctrl.user)) {
|
|
1055
|
+
ctrl.fallback(401);
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
let params = {};
|
|
980
1060
|
if (endpoint.params) {
|
|
981
1061
|
for (let m of endpoint.params)
|
|
982
1062
|
params[m.name] = schema[m.index] || '';
|
|
@@ -984,7 +1064,8 @@ function execute(ctrl) {
|
|
|
984
1064
|
body = body.data;
|
|
985
1065
|
if (!body || typeof(body) === 'object') {
|
|
986
1066
|
ctrl.params = params;
|
|
987
|
-
|
|
1067
|
+
ctrl.query = query ? query.parseEncoded() : {};
|
|
1068
|
+
F.action(endpoint.actions, body || {}, ctrl).autorespond();
|
|
988
1069
|
return;
|
|
989
1070
|
}
|
|
990
1071
|
}
|
|
@@ -994,6 +1075,10 @@ function execute(ctrl) {
|
|
|
994
1075
|
if (ctrl.route.actions) {
|
|
995
1076
|
F.action(ctrl.route.actions, ctrl.body, ctrl).autorespond();
|
|
996
1077
|
} else {
|
|
1078
|
+
if (ctrl.route.view) {
|
|
1079
|
+
ctrl.view(ctrl.route.view);
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
997
1082
|
let action = ctrl.route.action;
|
|
998
1083
|
if (!action)
|
|
999
1084
|
action = auto_view;
|
|
@@ -1004,7 +1089,7 @@ function execute(ctrl) {
|
|
|
1004
1089
|
}
|
|
1005
1090
|
|
|
1006
1091
|
function auto_view(ctrl) {
|
|
1007
|
-
ctrl.view(ctrl.split[0] || 'index'
|
|
1092
|
+
ctrl.view(ctrl.split[0] || 'index');
|
|
1008
1093
|
}
|
|
1009
1094
|
|
|
1010
1095
|
function send_html(ctrl, path) {
|
|
@@ -1023,17 +1108,24 @@ function send_html(ctrl, path) {
|
|
|
1023
1108
|
readfile(path, function(err, output) {
|
|
1024
1109
|
|
|
1025
1110
|
if (err) {
|
|
1026
|
-
|
|
1111
|
+
|
|
1112
|
+
if (!DEBUG)
|
|
1113
|
+
F.temporary.notfound[ctrl.uri.key] = 1;
|
|
1114
|
+
|
|
1027
1115
|
ctrl.fallback(404);
|
|
1028
1116
|
return;
|
|
1029
1117
|
}
|
|
1030
1118
|
|
|
1119
|
+
if (!ctrl.language && F.def.onLocalize)
|
|
1120
|
+
ctrl.language = F.def.onLocalize(ctrl);
|
|
1121
|
+
|
|
1031
1122
|
output.body = F.translate(ctrl.language, output.body);
|
|
1032
1123
|
|
|
1033
1124
|
if (ctrl.response.minify && F.config.$minifyhtml)
|
|
1034
1125
|
output.body = F.TMinificators.html(output.body);
|
|
1035
1126
|
|
|
1036
1127
|
if (DEBUG) {
|
|
1128
|
+
ctrl.response.headers['cache-control'] = NOCACHE;
|
|
1037
1129
|
ctrl.response.headers['last-modified'] = output.date;
|
|
1038
1130
|
ctrl.response.headers['content-type'] = 'text/html';
|
|
1039
1131
|
ctrl.response.value = output.body;
|
|
@@ -1069,7 +1161,10 @@ function send_css(ctrl, path) {
|
|
|
1069
1161
|
readfile(path, function(err, output) {
|
|
1070
1162
|
|
|
1071
1163
|
if (err) {
|
|
1072
|
-
|
|
1164
|
+
|
|
1165
|
+
if (!DEBUG)
|
|
1166
|
+
F.temporary.notfound[ctrl.uri.key] = 1;
|
|
1167
|
+
|
|
1073
1168
|
ctrl.fallback(404);
|
|
1074
1169
|
return;
|
|
1075
1170
|
}
|
|
@@ -1078,6 +1173,7 @@ function send_css(ctrl, path) {
|
|
|
1078
1173
|
output.body = F.TMinificators.css(output.body);
|
|
1079
1174
|
|
|
1080
1175
|
if (DEBUG) {
|
|
1176
|
+
ctrl.response.headers['cache-control'] = NOCACHE;
|
|
1081
1177
|
ctrl.response.headers['last-modified'] = output.date;
|
|
1082
1178
|
ctrl.response.headers['content-type'] = 'text/css';
|
|
1083
1179
|
ctrl.response.value = output.body;
|
|
@@ -1113,7 +1209,10 @@ function send_js(ctrl, path) {
|
|
|
1113
1209
|
readfile(path, function(err, output) {
|
|
1114
1210
|
|
|
1115
1211
|
if (err) {
|
|
1116
|
-
|
|
1212
|
+
|
|
1213
|
+
if (!DEBUG)
|
|
1214
|
+
F.temporary.notfound[ctrl.uri.key] = 1;
|
|
1215
|
+
|
|
1117
1216
|
ctrl.fallback(404);
|
|
1118
1217
|
return;
|
|
1119
1218
|
}
|
|
@@ -1122,6 +1221,7 @@ function send_js(ctrl, path) {
|
|
|
1122
1221
|
output.body = F.TMinificators.js(output.body);
|
|
1123
1222
|
|
|
1124
1223
|
if (DEBUG) {
|
|
1224
|
+
ctrl.response.headers['cache-control'] = NOCACHE;
|
|
1125
1225
|
ctrl.response.headers['last-modified'] = output.date;
|
|
1126
1226
|
ctrl.response.headers['content-type'] = 'text/javascript';
|
|
1127
1227
|
ctrl.response.value = output.body;
|
|
@@ -1152,7 +1252,7 @@ function send_file(ctrl, path, ext) {
|
|
|
1152
1252
|
var cache = F.temporary.tmp[ctrl.uri.key];
|
|
1153
1253
|
|
|
1154
1254
|
// HTTP Cache
|
|
1155
|
-
if (ctrl.response.cache && cache && notmodified(
|
|
1255
|
+
if (ctrl.response.cache && cache && ctrl.notmodified(cache.date))
|
|
1156
1256
|
return;
|
|
1157
1257
|
|
|
1158
1258
|
var accept = ctrl.headers['accept-encoding'];
|
|
@@ -1165,18 +1265,24 @@ function send_file(ctrl, path, ext) {
|
|
|
1165
1265
|
|
|
1166
1266
|
if (err) {
|
|
1167
1267
|
|
|
1168
|
-
if (ctrl.response.cache)
|
|
1268
|
+
if (!DEBUG && ctrl.response.cache)
|
|
1169
1269
|
F.temporary.notfound[ctrl.uri.key] = true;
|
|
1170
1270
|
|
|
1171
1271
|
ctrl.fallback(404);
|
|
1172
1272
|
return;
|
|
1173
1273
|
}
|
|
1174
1274
|
|
|
1175
|
-
if (httpcache)
|
|
1176
|
-
ctrl.response.headers.expires
|
|
1177
|
-
|
|
1275
|
+
if (httpcache) {
|
|
1276
|
+
if (!ctrl.response.headers.expires)
|
|
1277
|
+
ctrl.response.headers.expires = F.config.$httpexpire;
|
|
1278
|
+
if (!ctrl.response.headers['cache-control'])
|
|
1279
|
+
ctrl.response.headers['cache-control'] = 'public, must-revalidate, max-age=' + F.config.$httpmaxage; // 5 minute cache for revalidate (304)
|
|
1280
|
+
} else if (ctrl.response.headers.expires)
|
|
1178
1281
|
delete ctrl.response.headers.expires;
|
|
1179
1282
|
|
|
1283
|
+
if (!httpcache)
|
|
1284
|
+
ctrl.response.headers['cache-control'] = NOCACHE;
|
|
1285
|
+
|
|
1180
1286
|
if (!cache)
|
|
1181
1287
|
cache = { date: stats.mtime.toUTCString(), size: stats.size };
|
|
1182
1288
|
|
|
@@ -1273,6 +1379,9 @@ function HttpFile(meta) {
|
|
|
1273
1379
|
}
|
|
1274
1380
|
|
|
1275
1381
|
HttpFile.prototype = {
|
|
1382
|
+
get extension() {
|
|
1383
|
+
return this.ext;
|
|
1384
|
+
},
|
|
1276
1385
|
get isImage() {
|
|
1277
1386
|
return this.type.indexOf('image/') !== -1;
|
|
1278
1387
|
},
|
|
@@ -1313,7 +1422,7 @@ HttpFile.prototype.$move = function(filename, callback) {
|
|
|
1313
1422
|
} else {
|
|
1314
1423
|
if (!err) {
|
|
1315
1424
|
self.path = filename;
|
|
1316
|
-
self.
|
|
1425
|
+
self.removable = false;
|
|
1317
1426
|
}
|
|
1318
1427
|
callback && callback(err);
|
|
1319
1428
|
}
|
package/filestorage.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const IMAGES = { jpg: 1, png: 1, gif: 1, svg: 1, jpeg: 1, heic: 1, heif: 1, webp: 1, tiff: 1, bmp: 1 };
|
|
8
8
|
const HEADERSIZE = 2000;
|
|
9
9
|
const MKDIR = { recursive: true };
|
|
10
|
+
const READDIR = { withFileTypes: true };
|
|
10
11
|
const GZIP_FILE = { memLevel: 9 };
|
|
11
12
|
|
|
12
13
|
const REG_RANGE = /bytes=/;
|
|
@@ -94,14 +95,14 @@ FP.readjson = function(id, callback) {
|
|
|
94
95
|
});
|
|
95
96
|
};
|
|
96
97
|
|
|
97
|
-
FP.save = FP.insert = function(id, name, filename,
|
|
98
|
+
FP.save = FP.insert = function(id, name, filename, custom, callback, expire, headers) {
|
|
98
99
|
var self = this;
|
|
99
100
|
|
|
100
|
-
if (
|
|
101
|
+
if (typeof(custom) === 'function') {
|
|
101
102
|
headers = expire;
|
|
102
|
-
expire =
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
expire = callback;
|
|
104
|
+
callback = custom;
|
|
105
|
+
custom = null;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
if (callback)
|
|
@@ -435,7 +436,7 @@ FP._readbuffer = function(id, callback) {
|
|
|
435
436
|
FP.browse = function(callback) {
|
|
436
437
|
var db = NOSQL(this.logger).find();
|
|
437
438
|
if (callback)
|
|
438
|
-
db
|
|
439
|
+
db.main.callback = callback;
|
|
439
440
|
return db;
|
|
440
441
|
};
|
|
441
442
|
|
|
@@ -743,11 +744,11 @@ FP._clear = function(callback) {
|
|
|
743
744
|
return self;
|
|
744
745
|
};
|
|
745
746
|
|
|
746
|
-
FP.stream = function(onfile, callback, workers) {
|
|
747
|
+
FP.stream = function(onfile, callback, workers = 2) {
|
|
747
748
|
|
|
748
749
|
var self = this;
|
|
749
750
|
|
|
750
|
-
F.Fs.readdir(self.directory, function(err, response) {
|
|
751
|
+
F.Fs.readdir(self.directory, READDIR, function(err, response) {
|
|
751
752
|
|
|
752
753
|
if (err) {
|
|
753
754
|
callback();
|
|
@@ -758,15 +759,33 @@ FP.stream = function(onfile, callback, workers) {
|
|
|
758
759
|
|
|
759
760
|
response.wait(function(item, next) {
|
|
760
761
|
|
|
761
|
-
if (item.
|
|
762
|
+
if (!item.isDirectory()) {
|
|
763
|
+
next();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
if (item.name.length !== 4) {
|
|
762
768
|
next();
|
|
763
769
|
return;
|
|
764
770
|
}
|
|
765
771
|
|
|
766
|
-
F.Fs.readdir(F.Path.join(self.directory, item), function(err, files) {
|
|
772
|
+
F.Fs.readdir(F.Path.join(self.directory, item.name), READDIR, function(err, files) {
|
|
767
773
|
if (files instanceof Array) {
|
|
768
774
|
files.wait(function(item, next) {
|
|
769
|
-
|
|
775
|
+
|
|
776
|
+
if (!item.isFile()) {
|
|
777
|
+
next();
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
let index = item.name.lastIndexOf('.');
|
|
782
|
+
|
|
783
|
+
if (item.name.substring(index) !== '.file') {
|
|
784
|
+
next();
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
let id = item.name.substring(0, index);
|
|
770
789
|
self.read(id, function(err, meta) {
|
|
771
790
|
if (meta) {
|
|
772
791
|
meta.id = id;
|
|
@@ -976,14 +995,8 @@ FP.http = function(ctrl, opt) {
|
|
|
976
995
|
var date = obj.date ? obj.date.toUTCString() : '';
|
|
977
996
|
var response = ctrl.response;
|
|
978
997
|
|
|
979
|
-
if (!opt.download && ctrl.
|
|
980
|
-
response.status = 304;
|
|
981
|
-
response.headers['cache-control'] = 'public, max-age=11111111';
|
|
982
|
-
response.headers['last-modified'] = date;
|
|
983
|
-
ctrl.flush();
|
|
984
|
-
F.stats.response.notmodified++;
|
|
998
|
+
if (!opt.download && date && ctrl.notmodified(date))
|
|
985
999
|
return;
|
|
986
|
-
}
|
|
987
1000
|
|
|
988
1001
|
// Resized image?
|
|
989
1002
|
if (!DEBUG && F.temporary.path[ctrl.uri.key]) {
|
|
@@ -1047,7 +1060,10 @@ FP.http = function(ctrl, opt) {
|
|
|
1047
1060
|
|
|
1048
1061
|
response.status = 206;
|
|
1049
1062
|
response.headers['accept-ranges'] = 'bytes';
|
|
1050
|
-
|
|
1063
|
+
|
|
1064
|
+
if (!opt.download && !DEBUG && date)
|
|
1065
|
+
ctrl.httpcache(date);
|
|
1066
|
+
|
|
1051
1067
|
response.headers['content-length'] = length;
|
|
1052
1068
|
response.headers['content-range'] = 'bytes ' + beg + '-' + end + '/' + obj.size;
|
|
1053
1069
|
response.headers['content-type'] = obj.type;
|
|
@@ -1060,6 +1076,10 @@ FP.http = function(ctrl, opt) {
|
|
|
1060
1076
|
|
|
1061
1077
|
} else {
|
|
1062
1078
|
var stream = F.Fs.createReadStream(filename, { start: HEADERSIZE });
|
|
1079
|
+
|
|
1080
|
+
if (!opt.download && !DEBUG && date)
|
|
1081
|
+
ctrl.httpcache(date);
|
|
1082
|
+
|
|
1063
1083
|
ctrl.stream(obj.type, stream);
|
|
1064
1084
|
}
|
|
1065
1085
|
}
|