better code
Massimo Melina committed
May 3, 2026 at 12:27 UTC
da52e60665ec582869936705958d79fe4f1899f6
2 files changed
+17
-16
src/misc.ts
+15
-2
@@ -1,6 +1,6 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
-import { basename } from 'path'
3
+import { basename, dirname, join } from 'path'
4
import Koa from 'koa'
5
import { Connection } from './connections'
6
export * from './util-http'
@@ -13,7 +13,7 @@ import { Readable, Transform } from 'stream'
13
import { SocketAddress, BlockList } from 'node:net'
14
import { ApiError } from './apiMiddleware'
15
import { HTTP_BAD_REQUEST } from './const'
16
-import { isIpLocalHost, makeMatcher, try_ } from './cross'
16
+import { Callback, isIpLocalHost, makeMatcher, try_ } from './cross'
17
import { isIPv6 } from 'net'
18
import _ from 'lodash'
19
@@ -129,3 +129,16 @@ export function createStreamLimiter(limit: number) {
129
}
130
})
131
}
132
+
133
+export function retrySync(cb: Callback, attempts=20, sleep=500) {
134
+ const sleepSyncBuffer = new Int32Array(new SharedArrayBuffer(4))
135
+ for (let retry = 0; ; retry++) {
136
+ try { return cb() }
137
+ catch (e: any) {
138
+ if (e?.code !== 'EBUSY' || retry >= attempts)
139
+ throw e
140
+ Atomics.wait(sleepSyncBuffer, 0, 0, sleep)
141
+ }
142
+ }
143
+}
144
+
src/update.ts
+2
-14
@@ -5,7 +5,7 @@ import { ARGS_FILE, HFS_REPO, IS_BINARY, IS_WINDOWS, IS_MAC, PREVIOUS_TAG, RUNNI
5
import { dirname, join } from 'path'
6
import { spawn, spawnSync } from 'child_process'
7
import {
8
- DAY, exists, unzip, prefix, xlate, HOUR, httpStream, statWithTimeout, repeat, debounceAsync, formatPerc
8
+ DAY, exists, unzip, prefix, xlate, HOUR, httpStream, statWithTimeout, repeat, debounceAsync, formatPerc, retrySync
9
} from './misc'
10
import { createReadStream, createWriteStream, existsSync, renameSync, unlinkSync, writeFileSync } from 'fs'
11
import { pluginsWatcher } from './plugins'
@@ -192,7 +192,7 @@ export async function update(tagOrUrl: string='') {
192
catch {}
193
renameSync(bin, oldBin)
194
if (!preserveTerminal) {
195
- try { renameSyncWithBusyRetry(newBin, join(binPath, binFile)) }
195
+ try { retrySync(() => renameSync(newBin, join(binPath, binFile))) }
196
catch (e) {
197
try { renameSync(oldBin, bin) } // restore the service target because hfs.exe was already moved aside
198
catch (rollbackError) { console.error("Couldn't restore original binary after failed update", rollbackError) }
@@ -215,18 +215,6 @@ export async function update(tagOrUrl: string='') {
215
}
216
}
217
218
-function renameSyncWithBusyRetry(src: string, dest: string) {
219
- const sleepSyncBuffer = new Int32Array(new SharedArrayBuffer(4))
220
- for (let retry = 0; ; retry++) {
221
- try { return renameSync(src, dest) }
222
- catch (e: any) {
223
- if (e?.code !== 'EBUSY' || retry >= 20)
224
- throw e
225
- Atomics.wait(sleepSyncBuffer, 0, 0, 500)
226
- }
227
- }
228
-}
229
-
218
if (argv.updating) { // we were launched with a temporary name, restore original name to avoid breaking references
219
const bin = process.execPath
220
const dest = join(dirname(bin), argv.updating)