hfs 0.55.1 → 0.55.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/admin/assets/{index-ErTf5p78.js → index-B4HJwRLS.js} +86 -86
- package/admin/assets/{sha512-CqnbmZS9.js → sha512-iUmyklA_.js} +1 -1
- package/admin/index.html +1 -1
- package/admin/prism.css +4 -0
- package/admin/prism.js +10 -0
- package/frontend/assets/{index-legacy-BoMy1vEB.js → index-legacy-BFUS5Ol_.js} +7 -7
- package/frontend/assets/{sha512-legacy-CP10jckG.js → sha512-legacy-HnxdKRIz.js} +1 -1
- package/frontend/index.html +1 -1
- package/package.json +1 -1
- package/src/argv.js +8 -0
- package/src/commands.js +2 -1
- package/src/config.js +3 -6
- package/src/consoleLog.js +2 -2
- package/src/const.js +10 -8
- package/src/cross-const.js +3 -1
- package/src/cross.js +0 -19
- package/src/github.js +2 -1
- package/src/i18n.js +2 -0
- package/src/listen.js +2 -1
- package/src/serveGuiAndSharedFiles.js +1 -0
- package/src/update.js +5 -4
- package/src/upload.js +32 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
System.register(["./index-legacy-
|
|
1
|
+
System.register(["./index-legacy-BFUS5Ol_.js"],(function(h,t){"use strict";var i,s;return{setters:[function(h){i=h.g,s=h.c}],execute:function(){function t(h,t){for(var i=function(){var i=t[s];if("string"!=typeof i&&!Array.isArray(i)){var r=function(t){if("default"!==t&&!(t in h)){var s=Object.getOwnPropertyDescriptor(i,t);s&&Object.defineProperty(h,t,s.get?s:{enumerable:!0,get:function(){return i[t]}})}};for(var e in i)r(e)}},s=0;s<t.length;s++)i();return Object.freeze(Object.defineProperty(h,Symbol.toStringTag,{value:"Module"}))}var r={exports:{}};
|
|
2
2
|
/*
|
|
3
3
|
* [js-sha512]{@link https://github.com/emn178/js-sha512}
|
|
4
4
|
*
|
package/frontend/index.html
CHANGED
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
document.getElementById('root').innerHTML = 'Loading...'
|
|
23
23
|
</script>
|
|
24
24
|
<script crossorigin id="vite-legacy-polyfill" src="/assets/polyfills-legacy-DMrMt_pQ.js"></script>
|
|
25
|
-
<script crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-
|
|
25
|
+
<script crossorigin id="vite-legacy-entry" data-src="/assets/index-legacy-BFUS5Ol_.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
|
|
26
26
|
</body>
|
|
27
27
|
</html>
|
package/package.json
CHANGED
package/src/argv.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.argv = void 0;
|
|
7
|
+
const minimist_1 = __importDefault(require("minimist"));
|
|
8
|
+
exports.argv = (0, minimist_1.default)(process.argv.slice(2));
|
package/src/commands.js
CHANGED
|
@@ -17,7 +17,8 @@ const fileAttr_1 = require("./fileAttr");
|
|
|
17
17
|
const github_1 = require("./github");
|
|
18
18
|
const cross_1 = require("./cross");
|
|
19
19
|
const api_monitor_1 = __importDefault(require("./api.monitor"));
|
|
20
|
-
|
|
20
|
+
const argv_1 = require("./argv");
|
|
21
|
+
if (!argv_1.argv.updating)
|
|
21
22
|
try {
|
|
22
23
|
/*
|
|
23
24
|
is this try-block useful in case the stdin is unavailable?
|
package/src/config.js
CHANGED
|
@@ -38,12 +38,13 @@ const path_1 = require("path");
|
|
|
38
38
|
const events_1 = __importDefault(require("./events"));
|
|
39
39
|
const promises_1 = require("fs/promises");
|
|
40
40
|
const immer_1 = __importStar(require("immer"));
|
|
41
|
+
const argv_1 = require("./argv");
|
|
41
42
|
(0, immer_1.setAutoFreeze)(false); // we still want to mess with objects later (eg: account.belongs)
|
|
42
43
|
// keep definition of config properties
|
|
43
44
|
const configProps = {};
|
|
44
45
|
let started = false; // this will tell the difference for subscribeConfig()s that are called before or after config is loaded
|
|
45
46
|
let state = {}; // current state of config properties
|
|
46
|
-
const filePath = (0, misc_1.with_)(
|
|
47
|
+
const filePath = (0, misc_1.with_)(argv_1.argv.config || process.env.HFS_CONFIG, p => {
|
|
47
48
|
if (!p)
|
|
48
49
|
return const_1.CONFIG_FILE;
|
|
49
50
|
p = (0, path_1.resolve)(const_1.ORIGINAL_CWD, p);
|
|
@@ -139,7 +140,7 @@ function setConfig(newCfg, save) {
|
|
|
139
140
|
const version = lodash_1.default.isString(newCfg.version) ? new Version(newCfg.version) : undefined;
|
|
140
141
|
const considerEnvs = !process.env['HFS_ENV_BOOTSTRAP'] || !started && lodash_1.default.isEmpty(newCfg);
|
|
141
142
|
// first time we consider also CLI args
|
|
142
|
-
const argCfg = !started && lodash_1.default.pickBy((0, misc_1.newObj)(configProps, (x, k) => { var _a; return (_a =
|
|
143
|
+
const argCfg = !started && lodash_1.default.pickBy((0, misc_1.newObj)(configProps, (x, k) => { var _a; return (_a = argv_1.argv[k]) !== null && _a !== void 0 ? _a : (0, misc_1.tryJson)(considerEnvs ? process.env['HFS_' + k.toUpperCase().replaceAll('-', '_')] : '', lodash_1.default.identity); }), x => x !== undefined);
|
|
143
144
|
if (!lodash_1.default.isEmpty(argCfg)) {
|
|
144
145
|
(0, exports.saveConfigAsap)(); // don't set `save` argument, as it would interfere below at check `save===false`
|
|
145
146
|
Object.assign(newCfg, argCfg);
|
|
@@ -196,10 +197,6 @@ const saveDebounced = (0, misc_1.debounceAsync)(async () => {
|
|
|
196
197
|
const aWeekAgo = Date.now() - misc_1.DAY * 7;
|
|
197
198
|
if (await (0, promises_1.stat)(bak).then(x => aWeekAgo > Number(x.mtime || x.ctime), () => true))
|
|
198
199
|
await (0, promises_1.copyFile)(filePath, bak).catch(() => { }); // ignore errors
|
|
199
|
-
if (lodash_1.default.isEmpty(state)) {
|
|
200
|
-
console.error('saving empty config');
|
|
201
|
-
debugger;
|
|
202
|
-
}
|
|
203
200
|
await exports.configFile.save(stringify({ ...state, version: const_1.VERSION }))
|
|
204
201
|
.catch(err => console.error('Failed at saving config file, please ensure it is writable.', String(err)));
|
|
205
202
|
});
|
package/src/consoleLog.js
CHANGED
|
@@ -7,9 +7,9 @@ exports.consoleLog = void 0;
|
|
|
7
7
|
const events_1 = __importDefault(require("./events"));
|
|
8
8
|
const cross_1 = require("./cross");
|
|
9
9
|
const fs_1 = require("fs");
|
|
10
|
-
const
|
|
10
|
+
const argv_1 = require("./argv");
|
|
11
11
|
exports.consoleLog = [];
|
|
12
|
-
const f =
|
|
12
|
+
const f = argv_1.argv.consoleFile ? (0, fs_1.createWriteStream)(argv_1.argv.consoleFile, 'utf-8') : null;
|
|
13
13
|
for (const k of ['log', 'warn', 'error']) {
|
|
14
14
|
const original = console[k];
|
|
15
15
|
console[k] = (...args) => {
|
package/src/const.js
CHANGED
|
@@ -30,31 +30,31 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
30
30
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
31
31
|
};
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.CONFIG_FILE = exports.MIME_AUTO = exports.APP_PATH = exports.IS_BINARY = exports.IS_MAC = exports.IS_WINDOWS = exports.HFS_REPO_BRANCH = exports.RUNNING_BETA = exports.VERSION = exports.BUILD_TIMESTAMP = exports.HFS_STARTED = exports.ORIGINAL_CWD = exports.DEV = exports.ARGS_FILE = exports.
|
|
33
|
+
exports.CONFIG_FILE = exports.MIME_AUTO = exports.APP_PATH = exports.IS_BINARY = exports.IS_MAC = exports.IS_WINDOWS = exports.HFS_REPO_BRANCH = exports.RUNNING_BETA = exports.VERSION = exports.BUILD_TIMESTAMP = exports.HFS_STARTED = exports.ORIGINAL_CWD = exports.DEV = exports.ARGS_FILE = exports.COMPATIBLE_API_VERSION = exports.API_VERSION = void 0;
|
|
34
34
|
const minimist_1 = __importDefault(require("minimist"));
|
|
35
35
|
const fs = __importStar(require("fs"));
|
|
36
36
|
const os_1 = require("os");
|
|
37
37
|
const lodash_1 = __importDefault(require("lodash"));
|
|
38
38
|
const path_1 = require("path");
|
|
39
39
|
const cross_1 = require("./cross");
|
|
40
|
+
const argv_1 = require("./argv");
|
|
40
41
|
__exportStar(require("./cross-const"), exports);
|
|
41
42
|
exports.API_VERSION = 10.3;
|
|
42
43
|
exports.COMPATIBLE_API_VERSION = 1; // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
|
|
43
|
-
exports.argv = (0, minimist_1.default)(process.argv.slice(2));
|
|
44
44
|
// you can add arguments with this file, currently used for the update process on mac/linux
|
|
45
45
|
exports.ARGS_FILE = (0, path_1.join)((0, os_1.homedir)(), 'hfs-args');
|
|
46
46
|
try {
|
|
47
47
|
const s = fs.readFileSync(exports.ARGS_FILE, 'utf-8');
|
|
48
48
|
console.log('additional arguments', s);
|
|
49
|
-
lodash_1.default.defaults(
|
|
49
|
+
lodash_1.default.defaults(argv_1.argv, (0, minimist_1.default)(JSON.parse(s)));
|
|
50
50
|
fs.unlinkSync(exports.ARGS_FILE);
|
|
51
51
|
}
|
|
52
52
|
catch (_a) { }
|
|
53
|
-
exports.DEV = process.env.DEV ||
|
|
53
|
+
exports.DEV = process.env.DEV || argv_1.argv.dev ? 'DEV' : '';
|
|
54
54
|
exports.ORIGINAL_CWD = process.cwd();
|
|
55
55
|
exports.HFS_STARTED = new Date();
|
|
56
56
|
const PKG_PATH = (0, path_1.join)(__dirname, '..', 'package.json');
|
|
57
|
-
exports.BUILD_TIMESTAMP = "2025-01-
|
|
57
|
+
exports.BUILD_TIMESTAMP = "2025-01-05T19:25:48.693Z";
|
|
58
58
|
const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf8'));
|
|
59
59
|
exports.VERSION = pkg.version;
|
|
60
60
|
exports.RUNNING_BETA = exports.VERSION.includes('-');
|
|
@@ -75,12 +75,12 @@ console.log(`© Massimo Melina <a@rejetto.com> - License https://www.gnu.org/lic
|
|
|
75
75
|
console.log('started', (0, cross_1.formatTimestamp)(exports.HFS_STARTED), exports.DEV);
|
|
76
76
|
console.log('version', exports.VERSION || '-');
|
|
77
77
|
console.log('build', exports.BUILD_TIMESTAMP || '-');
|
|
78
|
-
console.debug('arguments',
|
|
78
|
+
console.debug('arguments', argv_1.argv);
|
|
79
79
|
// still considering whether to use ".hfs" with Windows users, who may be less accustomed to it
|
|
80
|
-
const dir =
|
|
80
|
+
const dir = argv_1.argv.cwd || useHomeDir() && (0, path_1.join)((0, os_1.homedir)(), '.hfs');
|
|
81
81
|
if (dir) {
|
|
82
82
|
try {
|
|
83
|
-
fs.mkdirSync(dir);
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
84
|
}
|
|
85
85
|
catch (e) {
|
|
86
86
|
if (e.code !== 'EEXIST')
|
|
@@ -88,6 +88,8 @@ if (dir) {
|
|
|
88
88
|
}
|
|
89
89
|
process.chdir(dir);
|
|
90
90
|
}
|
|
91
|
+
else if (process.cwd().startsWith(process.env.windir + '\\')) // this happens if you run hfs from task scheduler
|
|
92
|
+
process.chdir(exports.APP_PATH);
|
|
91
93
|
console.log('working directory (cwd)', process.cwd());
|
|
92
94
|
if (exports.APP_PATH !== process.cwd())
|
|
93
95
|
console.log('app', exports.APP_PATH);
|
package/src/cross-const.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HTTP_MESSAGES = exports.HTTP_SERVICE_UNAVAILABLE = exports.HTTP_SERVER_ERROR = exports.HTTP_TOO_MANY_REQUESTS = exports.HTTP_FAILED_DEPENDENCY = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_PAYLOAD_TOO_LARGE = exports.HTTP_PRECONDITION_FAILED = exports.HTTP_CONFLICT = exports.HTTP_NOT_ACCEPTABLE = exports.HTTP_METHOD_NOT_ALLOWED = exports.HTTP_NOT_FOUND = exports.HTTP_FORBIDDEN = exports.HTTP_UNAUTHORIZED = exports.HTTP_BAD_REQUEST = exports.HTTP_NOT_MODIFIED = exports.HTTP_TEMPORARY_REDIRECT = exports.HTTP_MOVED_PERMANENTLY = exports.HTTP_PARTIAL_CONTENT = exports.HTTP_NO_CONTENT = exports.HTTP_OK = exports.HFS_REPO = exports.PLUGIN_CUSTOM_REST_PREFIX = exports.NBSP = exports.PORT_DISABLED = exports.PLUGINS_PUB_URI = exports.API_URI = exports.ADMIN_URI = exports.FRONTEND_URI = exports.SPECIAL_URI = void 0;
|
|
3
|
+
exports.HTTP_MESSAGES = exports.HTTP_SERVICE_UNAVAILABLE = exports.HTTP_SERVER_ERROR = exports.HTTP_TOO_MANY_REQUESTS = exports.HTTP_FAILED_DEPENDENCY = exports.HTTP_FOOL = exports.HTTP_RANGE_NOT_SATISFIABLE = exports.HTTP_PAYLOAD_TOO_LARGE = exports.HTTP_PRECONDITION_FAILED = exports.HTTP_CONFLICT = exports.HTTP_NOT_ACCEPTABLE = exports.HTTP_METHOD_NOT_ALLOWED = exports.HTTP_NOT_FOUND = exports.HTTP_FORBIDDEN = exports.HTTP_UNAUTHORIZED = exports.HTTP_BAD_REQUEST = exports.HTTP_NOT_MODIFIED = exports.HTTP_TEMPORARY_REDIRECT = exports.HTTP_MOVED_PERMANENTLY = exports.HTTP_PARTIAL_CONTENT = exports.HTTP_NO_CONTENT = exports.HTTP_OK = exports.UPLOAD_STATUS = exports.UPLOAD_RESUMABLE = exports.HFS_REPO = exports.PLUGIN_CUSTOM_REST_PREFIX = exports.NBSP = exports.PORT_DISABLED = exports.PLUGINS_PUB_URI = exports.API_URI = exports.ADMIN_URI = exports.FRONTEND_URI = exports.SPECIAL_URI = void 0;
|
|
4
4
|
exports.SPECIAL_URI = '/~/';
|
|
5
5
|
exports.FRONTEND_URI = exports.SPECIAL_URI + 'frontend/';
|
|
6
6
|
exports.ADMIN_URI = exports.SPECIAL_URI + 'admin/';
|
|
@@ -10,6 +10,8 @@ exports.PORT_DISABLED = -1;
|
|
|
10
10
|
exports.NBSP = '\xA0';
|
|
11
11
|
exports.PLUGIN_CUSTOM_REST_PREFIX = '_';
|
|
12
12
|
exports.HFS_REPO = 'rejetto/hfs';
|
|
13
|
+
exports.UPLOAD_RESUMABLE = 'upload.resumable';
|
|
14
|
+
exports.UPLOAD_STATUS = 'upload.status';
|
|
13
15
|
exports.HTTP_OK = 200;
|
|
14
16
|
exports.HTTP_NO_CONTENT = 204;
|
|
15
17
|
exports.HTTP_PARTIAL_CONTENT = 206;
|
package/src/cross.js
CHANGED
|
@@ -534,22 +534,3 @@ const BROWSERS = {
|
|
|
534
534
|
Xbox: /xbox/i,
|
|
535
535
|
UC: /UCBrowser/i,
|
|
536
536
|
};
|
|
537
|
-
Object.defineProperties(Object.prototype, {
|
|
538
|
-
_L: {
|
|
539
|
-
enumerable: false,
|
|
540
|
-
writable: true,
|
|
541
|
-
value(msg = '') {
|
|
542
|
-
const val = this instanceof Number || this instanceof String || this instanceof Boolean ? this.valueOf() : this;
|
|
543
|
-
console.log('**', msg, val);
|
|
544
|
-
return val;
|
|
545
|
-
}
|
|
546
|
-
},
|
|
547
|
-
_D: {
|
|
548
|
-
enumerable: false,
|
|
549
|
-
writable: true,
|
|
550
|
-
value(msg = '') {
|
|
551
|
-
debugger;
|
|
552
|
-
return this._L(msg);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
});
|
package/src/github.js
CHANGED
|
@@ -15,6 +15,7 @@ const promises_1 = require("fs/promises");
|
|
|
15
15
|
const path_1 = require("path");
|
|
16
16
|
const fs_1 = require("fs");
|
|
17
17
|
const persistence_1 = require("./persistence");
|
|
18
|
+
const argv_1 = require("./argv");
|
|
18
19
|
const DIST_ROOT = 'dist';
|
|
19
20
|
exports.downloading = {};
|
|
20
21
|
function downloadProgress(repo, status) {
|
|
@@ -236,7 +237,7 @@ exports.blacklistedInstalledPlugins = [];
|
|
|
236
237
|
// centralized hosted information, to be used as little as possible
|
|
237
238
|
const FN = 'central.json';
|
|
238
239
|
let builtIn = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', FN), 'utf8'));
|
|
239
|
-
exports.getProjectInfo = (0, misc_1.debounceAsync)(() =>
|
|
240
|
+
exports.getProjectInfo = (0, misc_1.debounceAsync)(() => argv_1.argv.central === false ? Promise.resolve(builtIn) : readGithubFile(`${const_1.HFS_REPO}/${const_1.HFS_REPO_BRANCH}/${FN}`)
|
|
240
241
|
.then(JSON.parse, () => null)
|
|
241
242
|
.then(o => {
|
|
242
243
|
if (o)
|
package/src/i18n.js
CHANGED
|
@@ -40,6 +40,8 @@ function i18nFromTranslations(translations, embedded = 'en') {
|
|
|
40
40
|
for (const lang of searchLangs)
|
|
41
41
|
if (found = (_b = (_a = state.translations[selectedLang = lang]) === null || _a === void 0 ? void 0 : _a.translate) === null || _b === void 0 ? void 0 : _b[key])
|
|
42
42
|
break;
|
|
43
|
+
if (found)
|
|
44
|
+
break;
|
|
43
45
|
if (!warns.has(key) && langs.length && langs[0] !== embedded) {
|
|
44
46
|
warns.add(key);
|
|
45
47
|
console.debug("miss i18n:", key);
|
package/src/listen.js
CHANGED
|
@@ -46,6 +46,7 @@ const events_1 = __importDefault(require("./events"));
|
|
|
46
46
|
const net_1 = require("net");
|
|
47
47
|
const nat_1 = require("./nat");
|
|
48
48
|
const persistence_1 = require("./persistence");
|
|
49
|
+
const argv_1 = require("./argv");
|
|
49
50
|
let httpSrv;
|
|
50
51
|
let httpsSrv;
|
|
51
52
|
const openBrowserAtStart = (0, config_1.defineConfig)('open_browser_at_start', !const_1.DEV);
|
|
@@ -75,7 +76,7 @@ const considerHttp = (0, misc_1.debounceAsync)(async () => {
|
|
|
75
76
|
return;
|
|
76
77
|
httpSrv.on('connection', connections_1.newConnection);
|
|
77
78
|
printUrls(httpSrv.name);
|
|
78
|
-
if (openBrowserAtStart.get() && !
|
|
79
|
+
if (openBrowserAtStart.get() && !argv_1.argv.updated)
|
|
79
80
|
openAdmin();
|
|
80
81
|
});
|
|
81
82
|
exports.portCfg = (0, config_1.defineConfig)('port', 80);
|
|
@@ -54,6 +54,7 @@ const serveGuiAndSharedFiles = async (ctx, next) => {
|
|
|
54
54
|
ctx.status = cross_const_1.HTTP_SERVER_ERROR;
|
|
55
55
|
ctx.body = err.message || String(err);
|
|
56
56
|
});
|
|
57
|
+
ctx.req.on('close', () => dest.end());
|
|
57
58
|
const uri = await dest.lockMiddleware; // we need to wait more than just the stream
|
|
58
59
|
ctx.body = { uri };
|
|
59
60
|
}
|
package/src/update.js
CHANGED
|
@@ -19,6 +19,7 @@ const util_os_1 = require("./util-os");
|
|
|
19
19
|
const first_1 = require("./first");
|
|
20
20
|
const persistence_1 = require("./persistence");
|
|
21
21
|
const lodash_1 = __importDefault(require("lodash"));
|
|
22
|
+
const argv_1 = require("./argv");
|
|
22
23
|
const updateToBeta = (0, config_1.defineConfig)('update_to_beta', false);
|
|
23
24
|
const autoCheckUpdate = (0, config_1.defineConfig)('auto_check_update', true);
|
|
24
25
|
const lastCheckUpdate = persistence_1.storedMap.singleSync('lastCheckUpdate', 0);
|
|
@@ -92,7 +93,7 @@ function localUpdateAvailable() {
|
|
|
92
93
|
}
|
|
93
94
|
exports.localUpdateAvailable = localUpdateAvailable;
|
|
94
95
|
async function updateSupported() {
|
|
95
|
-
return
|
|
96
|
+
return argv_1.argv.forceupdate || const_1.IS_BINARY && !await util_os_1.RUNNING_AS_SERVICE;
|
|
96
97
|
}
|
|
97
98
|
exports.updateSupported = updateSupported;
|
|
98
99
|
async function update(tagOrUrl = '') {
|
|
@@ -170,12 +171,12 @@ exports.update = update;
|
|
|
170
171
|
function launch(cmd, pars = [], options) {
|
|
171
172
|
return ((options === null || options === void 0 ? void 0 : options.sync) ? child_process_1.spawnSync : child_process_1.spawn)((0, util_os_1.cmdEscape)(cmd), pars, { detached: true, shell: true, stdio: [0, 1, 2], ...options });
|
|
172
173
|
}
|
|
173
|
-
if (
|
|
174
|
+
if (argv_1.argv.updating) { // we were launched with a temporary name, restore original name to avoid breaking references
|
|
174
175
|
const bin = process.execPath;
|
|
175
|
-
const dest = (0, path_1.join)((0, path_1.dirname)(bin),
|
|
176
|
+
const dest = (0, path_1.join)((0, path_1.dirname)(bin), argv_1.argv.updating);
|
|
176
177
|
(0, fs_1.renameSync)(bin, dest);
|
|
177
178
|
// have to relaunch with new name, or otherwise next update will fail with EBUSY on hfs.exe
|
|
178
|
-
console.log("renamed binary file to",
|
|
179
|
+
console.log("renamed binary file to", argv_1.argv.updating, "and restarting");
|
|
179
180
|
// be sure to test launching both double-clicking and in a terminal
|
|
180
181
|
if (const_1.IS_WINDOWS) // this method on Mac works only once, and without console
|
|
181
182
|
(0, first_1.onProcessExit)(() => launch(dest, ['--updated', '--cwd .'])); // launch+sync here would cause old process to stay open, locking ports
|
package/src/upload.js
CHANGED
|
@@ -37,7 +37,7 @@ function setUploadMeta(path, ctx) {
|
|
|
37
37
|
}
|
|
38
38
|
// stay sync because we use this function with formidable()
|
|
39
39
|
const diskSpaceCache = (0, expiringCache_1.expiringCache)(3000); // invalidate shortly
|
|
40
|
-
const
|
|
40
|
+
const uploadingFiles = new Set();
|
|
41
41
|
function uploadWriter(base, baseUri, path, ctx) {
|
|
42
42
|
let fullPath = '';
|
|
43
43
|
if ((0, misc_1.dirTraversal)(path))
|
|
@@ -78,12 +78,12 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
78
78
|
catch (e) { // warn, but let it through
|
|
79
79
|
console.warn("can't check disk size:", e.message || String(e));
|
|
80
80
|
}
|
|
81
|
-
if (openFiles.has(fullPath))
|
|
82
|
-
return fail(const_1.HTTP_CONFLICT, 'uploading');
|
|
83
81
|
// optionally 'skip'
|
|
84
82
|
if (ctx.query.existing === 'skip' && fs_1.default.existsSync(fullPath))
|
|
85
83
|
return fail(const_1.HTTP_CONFLICT, 'exists');
|
|
86
|
-
|
|
84
|
+
if (uploadingFiles.has(fullPath))
|
|
85
|
+
return fail(const_1.HTTP_CONFLICT, 'uploading');
|
|
86
|
+
uploadingFiles.add(fullPath);
|
|
87
87
|
let overwriteRequestedButForbidden = false;
|
|
88
88
|
try {
|
|
89
89
|
// if upload creates a folder, then add meta to it too
|
|
@@ -91,38 +91,42 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
91
91
|
setUploadMeta(dir, ctx);
|
|
92
92
|
// use temporary name while uploading
|
|
93
93
|
const keepName = (0, path_1.basename)(fullPath).slice(-200);
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
const firstTempName = (0, path_1.join)(dir, 'hfs$upload-' + keepName);
|
|
95
|
+
const altTempName = (0, path_1.join)(dir, 'hfs$upload2-' + keepName);
|
|
96
|
+
const splitAndPreserving = ctx.query.preserveTempFile; // frontend knows about existing temp that can be resumed, but it is not resuming that, but instead it is continuing split-uploading on alternative temp file
|
|
97
|
+
let tempName = splitAndPreserving ? altTempName : firstTempName;
|
|
98
|
+
const stats = (0, misc_1.try_)(() => fs_1.default.statSync(tempName));
|
|
99
|
+
const resumableSize = (stats === null || stats === void 0 ? void 0 : stats.size) || 0; // we use size to even when user has not required resume, yet, to notify frontend of the possibility
|
|
100
|
+
const resumableTempName = resumableSize > 0 && tempName;
|
|
101
|
+
if (resumableTempName)
|
|
102
|
+
tempName = altTempName;
|
|
98
103
|
// checks for resume feature
|
|
99
104
|
let resume = Number(ctx.query.resume);
|
|
100
|
-
|
|
101
|
-
if (size === undefined) // stat failed
|
|
102
|
-
return fail(const_1.HTTP_SERVER_ERROR);
|
|
103
|
-
if (lodash_1.default.isNumber(size) && resume > size)
|
|
105
|
+
if (resume > resumableSize)
|
|
104
106
|
return fail(const_1.HTTP_RANGE_NOT_SATISFIABLE);
|
|
105
107
|
// warn frontend about resume possibility
|
|
106
108
|
let resumableLost = false;
|
|
107
|
-
if (!resume &&
|
|
109
|
+
if (!resume && !resumableTempName)
|
|
110
|
+
(0, frontEndApis_1.notifyClient)(ctx, const_1.UPLOAD_RESUMABLE, { [path]: 0 });
|
|
111
|
+
if (!resume && resumableTempName) {
|
|
108
112
|
const timeout = 30;
|
|
109
|
-
(0, frontEndApis_1.notifyClient)(ctx,
|
|
110
|
-
delayedDelete(
|
|
111
|
-
fs_1.default.rename(tempName,
|
|
113
|
+
(0, frontEndApis_1.notifyClient)(ctx, const_1.UPLOAD_RESUMABLE, { [path]: resumableSize, expires: Date.now() + timeout * 1000 });
|
|
114
|
+
delayedDelete(resumableTempName, timeout, () => // if user resumes, this upload is interrupted, and next upload will cancel this delayedDelete
|
|
115
|
+
fs_1.default.rename(tempName, resumableTempName, err => {
|
|
112
116
|
if (err)
|
|
113
117
|
return;
|
|
114
|
-
tempName =
|
|
118
|
+
tempName = resumableTempName;
|
|
115
119
|
resumableLost = true;
|
|
116
120
|
}));
|
|
117
121
|
}
|
|
118
122
|
// append if resuming
|
|
119
|
-
const resuming = resume &&
|
|
123
|
+
const resuming = resume && resumableTempName;
|
|
120
124
|
if (!resuming)
|
|
121
125
|
resume = 0;
|
|
122
126
|
const writeStream = (0, misc_1.createStreamLimiter)(reqSize !== null && reqSize !== void 0 ? reqSize : Infinity);
|
|
123
|
-
if (resuming) {
|
|
127
|
+
if (resuming && !splitAndPreserving) {
|
|
124
128
|
fs_1.default.rm(tempName, () => { });
|
|
125
|
-
tempName =
|
|
129
|
+
tempName = resumableTempName;
|
|
126
130
|
}
|
|
127
131
|
cancelDeletion(tempName);
|
|
128
132
|
ctx.state.uploadDestinationPath = tempName;
|
|
@@ -131,7 +135,7 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
131
135
|
const resEvent = events_1.default.emit('uploadStart', obj);
|
|
132
136
|
if (resEvent === null || resEvent === void 0 ? void 0 : resEvent.isDefaultPrevented())
|
|
133
137
|
return;
|
|
134
|
-
const fileStream = resuming ? fs_1.default.createWriteStream(
|
|
138
|
+
const fileStream = resuming ? fs_1.default.createWriteStream(resumableTempName, { flags: 'r+', start: resume })
|
|
135
139
|
: fs_1.default.createWriteStream(tempName);
|
|
136
140
|
writeStream.on('error', e => {
|
|
137
141
|
releaseFile();
|
|
@@ -145,7 +149,7 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
145
149
|
try {
|
|
146
150
|
await new Promise(res => fileStream.close(res)); // this only seem to be necessary on Windows
|
|
147
151
|
if (ctx.req.aborted) {
|
|
148
|
-
if (
|
|
152
|
+
if (resumableTempName && !resumableLost && !resuming) // we don't want to be left with 2 temp files
|
|
149
153
|
return (0, promises_1.rm)(tempName);
|
|
150
154
|
const sec = exports.deleteUnfinishedUploadsAfter.get();
|
|
151
155
|
return lodash_1.default.isNumber(sec) && delayedDelete(tempName, sec);
|
|
@@ -168,12 +172,14 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
168
172
|
try {
|
|
169
173
|
await (0, promises_1.rename)(tempName, dest);
|
|
170
174
|
cancelDeletion(tempName); // not necessary, as deletion's failure is silent, but still
|
|
175
|
+
if (splitAndPreserving) // we've been using altTempName, but now we're done, so we can delete firstTempName
|
|
176
|
+
delayedDelete(firstTempName, 0);
|
|
171
177
|
ctx.state.uploadDestinationPath = dest;
|
|
172
178
|
setUploadMeta(dest, ctx);
|
|
173
179
|
if (ctx.query.comment)
|
|
174
180
|
void (0, comments_1.setCommentFor)(dest, String(ctx.query.comment));
|
|
175
|
-
if (
|
|
176
|
-
(0, promises_1.rm)(
|
|
181
|
+
if (resumableTempName && !resuming) // this happens if user decided to not resume and the new upload finished before delayedDelete
|
|
182
|
+
(0, promises_1.rm)(resumableTempName).catch(console.warn);
|
|
177
183
|
obj.uri = (0, misc_1.enforceFinal)('/', baseUri) + (0, misc_1.pathEncode)((0, path_1.basename)(dest));
|
|
178
184
|
events_1.default.emit('uploadFinished', obj);
|
|
179
185
|
if (resEvent)
|
|
@@ -236,7 +242,7 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
236
242
|
delete waitingToBeDeleted[path];
|
|
237
243
|
}
|
|
238
244
|
function releaseFile() {
|
|
239
|
-
|
|
245
|
+
uploadingFiles.delete(fullPath);
|
|
240
246
|
}
|
|
241
247
|
function fail(status, msg) {
|
|
242
248
|
console.debug('upload failed', status, msg);
|
|
@@ -245,7 +251,7 @@ function uploadWriter(base, baseUri, path, ctx) {
|
|
|
245
251
|
ctx.status = status;
|
|
246
252
|
if (msg)
|
|
247
253
|
ctx.body = msg;
|
|
248
|
-
(0, frontEndApis_1.notifyClient)(ctx,
|
|
254
|
+
(0, frontEndApis_1.notifyClient)(ctx, const_1.UPLOAD_STATUS, { [path]: ctx.status }); // allow browsers to detect failure while still sending body
|
|
249
255
|
}
|
|
250
256
|
}
|
|
251
257
|
exports.uploadWriter = uploadWriter;
|