pinokiod 8.0.72 → 8.0.73
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.
|
@@ -57,6 +57,7 @@ class AutomaticScans {
|
|
|
57
57
|
this.lifecycleWork = new Set()
|
|
58
58
|
this.stopSettleMs = STOP_SETTLE_MS
|
|
59
59
|
this.drainQueued = false
|
|
60
|
+
this.drainRequested = false
|
|
60
61
|
this.waitingFor = null
|
|
61
62
|
this.listeners = new Set()
|
|
62
63
|
this.appTransitions = new Map()
|
|
@@ -266,9 +267,13 @@ class AutomaticScans {
|
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
async candidateThreshold() {
|
|
269
|
-
const
|
|
270
|
-
|
|
270
|
+
const cached = this.vault.lastScanCache &&
|
|
271
|
+
typeof this.vault.lastScanCache.get === "function"
|
|
272
|
+
? this.vault.lastScanCache.get("")
|
|
271
273
|
: null
|
|
274
|
+
const scan = cached || (this.vault.registry
|
|
275
|
+
? await this.vault.registry.scanFor()
|
|
276
|
+
: null)
|
|
272
277
|
const threshold = scan ? Number(scan.candidate_min_bytes) : NaN
|
|
273
278
|
return Number.isFinite(threshold) && threshold >= 0
|
|
274
279
|
? threshold
|
|
@@ -805,24 +810,38 @@ class AutomaticScans {
|
|
|
805
810
|
}
|
|
806
811
|
|
|
807
812
|
schedule() {
|
|
808
|
-
if (this.disposed
|
|
813
|
+
if (this.disposed) return
|
|
814
|
+
if (this.drainQueued) {
|
|
815
|
+
this.drainRequested = true
|
|
816
|
+
return
|
|
817
|
+
}
|
|
809
818
|
this.drainQueued = true
|
|
810
819
|
queueMicrotask(() => {
|
|
811
|
-
|
|
812
|
-
|
|
820
|
+
const pending = (async () => {
|
|
821
|
+
do {
|
|
822
|
+
this.drainRequested = false
|
|
823
|
+
await this.drain()
|
|
824
|
+
} while (!this.disposed && this.drainRequested)
|
|
825
|
+
})()
|
|
813
826
|
this.lifecycleWork.add(pending)
|
|
814
827
|
pending.then(
|
|
815
|
-
() =>
|
|
816
|
-
|
|
828
|
+
() => {
|
|
829
|
+
this.lifecycleWork.delete(pending)
|
|
830
|
+
this.drainQueued = false
|
|
831
|
+
if (this.drainRequested) this.schedule()
|
|
832
|
+
},
|
|
833
|
+
(error) => {
|
|
834
|
+
this.lifecycleWork.delete(pending)
|
|
835
|
+
this.drainQueued = false
|
|
836
|
+
this.log("error", {
|
|
837
|
+
stage: "queue",
|
|
838
|
+
message: error && error.message ? error.message : String(error)
|
|
839
|
+
})
|
|
840
|
+
console.warn("Automatic Disk Saver check failed:",
|
|
841
|
+
error && error.message ? error.message : error)
|
|
842
|
+
if (this.drainRequested) this.schedule()
|
|
843
|
+
}
|
|
817
844
|
)
|
|
818
|
-
pending.catch((error) => {
|
|
819
|
-
this.log("error", {
|
|
820
|
-
stage: "queue",
|
|
821
|
-
message: error && error.message ? error.message : String(error)
|
|
822
|
-
})
|
|
823
|
-
console.warn("Automatic Disk Saver check failed:",
|
|
824
|
-
error && error.message ? error.message : error)
|
|
825
|
-
})
|
|
826
845
|
})
|
|
827
846
|
}
|
|
828
847
|
|
|
@@ -972,7 +991,6 @@ class AutomaticScans {
|
|
|
972
991
|
const paths = [...new Set(active.paths || [])].filter((filePath) =>
|
|
973
992
|
typeof filePath === "string" && inside(root, filePath))
|
|
974
993
|
const verifiedHashes = new Map()
|
|
975
|
-
await this.vault.registry.beginAutomaticPrecheck(app)
|
|
976
994
|
this.log("check-started", {
|
|
977
995
|
app,
|
|
978
996
|
root,
|
|
@@ -980,6 +998,7 @@ class AutomaticScans {
|
|
|
980
998
|
changed_paths: paths.length,
|
|
981
999
|
policy: "metadata-prefilter-sha256"
|
|
982
1000
|
})
|
|
1001
|
+
await this.vault.registry.beginAutomaticPrecheck(app)
|
|
983
1002
|
try {
|
|
984
1003
|
this.checkpoint(active)
|
|
985
1004
|
const metadataOptions = {
|
|
@@ -1164,7 +1183,19 @@ class AutomaticScans {
|
|
|
1164
1183
|
item.state === "checking")
|
|
1165
1184
|
if (!entry) return
|
|
1166
1185
|
await this.refreshGlobalScanReady()
|
|
1167
|
-
if (this.disposed
|
|
1186
|
+
if (this.disposed) return
|
|
1187
|
+
if (!this.globalScanReady) {
|
|
1188
|
+
if (this.entries.get(entry.app) === entry) {
|
|
1189
|
+
this.restorePrevious(entry.app)
|
|
1190
|
+
this.discardChangedPaths(entry.app)
|
|
1191
|
+
this.log("check-skipped", {
|
|
1192
|
+
app: entry.app,
|
|
1193
|
+
reason: "global-scan-required"
|
|
1194
|
+
})
|
|
1195
|
+
}
|
|
1196
|
+
this.schedule()
|
|
1197
|
+
return
|
|
1198
|
+
}
|
|
1168
1199
|
if (this.manualDepth > 0 || this.currentBusyPromise() ||
|
|
1169
1200
|
this.vault.fileActionProgress) {
|
|
1170
1201
|
this.waitForBusyWork()
|
package/package.json
CHANGED
|
@@ -405,6 +405,71 @@ describe("automatic app checks", () => {
|
|
|
405
405
|
assert.equal(checksStarted, 0)
|
|
406
406
|
})
|
|
407
407
|
|
|
408
|
+
test("scheduler coalesces wakeups while dispatch is in progress", async () => {
|
|
409
|
+
let releaseReadiness
|
|
410
|
+
let readinessCalls = 0
|
|
411
|
+
let dispatches = 0
|
|
412
|
+
const automatic = makeAutomatic({
|
|
413
|
+
enabled: true,
|
|
414
|
+
registry: {},
|
|
415
|
+
runExclusive: () => {
|
|
416
|
+
dispatches += 1
|
|
417
|
+
return new Promise(() => {})
|
|
418
|
+
}
|
|
419
|
+
})
|
|
420
|
+
automatic.entries.set("demo", {
|
|
421
|
+
app: "demo",
|
|
422
|
+
state: "checking",
|
|
423
|
+
paths: []
|
|
424
|
+
})
|
|
425
|
+
automatic.globalScanReady = true
|
|
426
|
+
automatic.refreshGlobalScanReady = async () => {
|
|
427
|
+
readinessCalls += 1
|
|
428
|
+
if (readinessCalls === 1) {
|
|
429
|
+
await new Promise((resolve) => { releaseReadiness = resolve })
|
|
430
|
+
}
|
|
431
|
+
automatic.globalScanReady = true
|
|
432
|
+
}
|
|
433
|
+
automatic.appRootIsAvailable = async () => true
|
|
434
|
+
automatic.appIsRunning = () => false
|
|
435
|
+
|
|
436
|
+
automatic.schedule()
|
|
437
|
+
await waitFor(() => typeof releaseReadiness === "function",
|
|
438
|
+
"scheduler readiness pause")
|
|
439
|
+
automatic.schedule()
|
|
440
|
+
releaseReadiness()
|
|
441
|
+
await waitFor(() => dispatches > 0, "automatic dispatch")
|
|
442
|
+
await new Promise((resolve) => setImmediate(resolve))
|
|
443
|
+
|
|
444
|
+
assert.equal(dispatches, 1)
|
|
445
|
+
assert.equal(readinessCalls, 1)
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
test("queued checks are cleared if global readiness disappears", async () => {
|
|
449
|
+
const automatic = makeAutomatic({
|
|
450
|
+
enabled: true,
|
|
451
|
+
registry: {}
|
|
452
|
+
})
|
|
453
|
+
automatic.entries.set("demo", {
|
|
454
|
+
app: "demo",
|
|
455
|
+
state: "checking",
|
|
456
|
+
paths: ["/pinokio/api/demo/model.bin"]
|
|
457
|
+
})
|
|
458
|
+
automatic.changedPaths.set("demo", new Set([
|
|
459
|
+
"/pinokio/api/demo/model.bin"
|
|
460
|
+
]))
|
|
461
|
+
automatic.refreshGlobalScanReady = async () => {
|
|
462
|
+
automatic.globalScanReady = false
|
|
463
|
+
}
|
|
464
|
+
automatic.log = () => {}
|
|
465
|
+
|
|
466
|
+
automatic.schedule()
|
|
467
|
+
await waitFor(() => !automatic.drainQueued, "automatic queue cleanup")
|
|
468
|
+
|
|
469
|
+
assert.equal(automatic.entries.has("demo"), false)
|
|
470
|
+
assert.equal(automatic.changedPaths.has("demo"), false)
|
|
471
|
+
})
|
|
472
|
+
|
|
408
473
|
test("Linux starts no watcher and ignores automatic lifecycle work", async () => {
|
|
409
474
|
const home = await makeHome()
|
|
410
475
|
const appRoot = path.join(home, "api", "linux-app")
|