dsh-unlag 1.9.65 → 1.9.66
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/index.js +51 -33
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1754,6 +1754,45 @@ export async function verifyStartup(clientModules, rows) {
|
|
|
1754
1754
|
return verifyStartupRows(graph, (url) => readStartupScript(clientModules, url), rows)
|
|
1755
1755
|
}
|
|
1756
1756
|
|
|
1757
|
+
/** What one press is told when the update it waits for did not answer in time. */
|
|
1758
|
+
const STILL_APPLYING = Object.freeze({ status: 'applying', warnings: [], pending: [], restartReason: null, failedEntries: [] });
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* The answer a press waits for, bounded in time. The update is asked for at most once and its
|
|
1762
|
+
* answer is settled the same way whether it is a promise, a plain value, or a promise that cannot
|
|
1763
|
+
* even be awaited: the page is always told one status, and nothing a plugin swap answers can turn
|
|
1764
|
+
* the route into an error.
|
|
1765
|
+
* @returns {{ outcome: object, timeRanOut: boolean, work: Promise<unknown> }}
|
|
1766
|
+
*/
|
|
1767
|
+
export async function answerReload(controller, limitMs) {
|
|
1768
|
+
let work = null
|
|
1769
|
+
try {
|
|
1770
|
+
work = Promise.resolve(controller.reloadNow())
|
|
1771
|
+
} catch (error) {
|
|
1772
|
+
log(`a press could not be started: ${error?.message ?? error}`)
|
|
1773
|
+
return { outcome: { status: 'failed', warnings: [], pending: [], restartReason: null, failedEntries: [] }, timeRanOut: false, work: Promise.resolve() }
|
|
1774
|
+
}
|
|
1775
|
+
let timer = null
|
|
1776
|
+
let timeRanOut = false
|
|
1777
|
+
const ranOut = new Promise((resolve) => {
|
|
1778
|
+
timer = setTimeout(() => {
|
|
1779
|
+
timeRanOut = true
|
|
1780
|
+
resolve(STILL_APPLYING)
|
|
1781
|
+
}, limitMs)
|
|
1782
|
+
})
|
|
1783
|
+
try {
|
|
1784
|
+
const outcome = await Promise.race([work.catch(() => null), ranOut])
|
|
1785
|
+
// Reading the status can throw too; an answer that cannot be read is not one the page can use.
|
|
1786
|
+
try {
|
|
1787
|
+
if (outcome !== null && typeof outcome === 'object' && typeof outcome.status === 'string') return { outcome, timeRanOut, work }
|
|
1788
|
+
} catch {}
|
|
1789
|
+
// An update that answers nothing usable is still a press that has to be answered.
|
|
1790
|
+
return { outcome: { status: 'failed', warnings: [], pending: [], restartReason: null, failedEntries: [] }, timeRanOut, work }
|
|
1791
|
+
} finally {
|
|
1792
|
+
if (timer !== null) clearTimeout(timer)
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1757
1796
|
/**
|
|
1758
1797
|
* The entry points the header button calls. Each answers with the current switches so the page
|
|
1759
1798
|
* never guesses: with both off it does nothing, and a turn still running is reported rather than
|
|
@@ -1888,42 +1927,21 @@ function serveButton(ctx, controller, config) {
|
|
|
1888
1927
|
if (buttonAllowed(req) === false) return sendJson(res, 403, { status: 'forbidden' })
|
|
1889
1928
|
if (!settings.reloadPlugins) return sendJson(res, 200, { status: 'off' })
|
|
1890
1929
|
const limit = Number(process.env.DSH_UNLAG_ANSWER_MS ?? '') || RELOAD_ANSWER_MS
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
})
|
|
1901
|
-
let answeredEarly = false
|
|
1902
|
-
try {
|
|
1903
|
-
const work = controller.reloadNow()
|
|
1904
|
-
/**
|
|
1905
|
-
* The answer the page waits for is bounded, but the update is not. Whatever the update
|
|
1906
|
-
* did after the page was told it is still applying is written down here: a replacement
|
|
1907
|
-
* that failed a moment later must not look like one that succeeded.
|
|
1908
|
-
*/
|
|
1930
|
+
const { outcome, timeRanOut, work } = await answerReload(controller, limit)
|
|
1931
|
+
/**
|
|
1932
|
+
* The answer the page waits for is bounded, but the update is not. Whatever the update
|
|
1933
|
+
* did after the page was told it is still applying is written down here: a replacement
|
|
1934
|
+
* that failed a moment later must not look like one that succeeded.
|
|
1935
|
+
*/
|
|
1936
|
+
if (outcome.status === 'applying') {
|
|
1937
|
+
if (timeRanOut) log('the update outlasted the answer the page waits for: the press is told it is still applying')
|
|
1938
|
+
else log('a press arrived while an update is already applying: the press is told it is still applying')
|
|
1909
1939
|
work.then(
|
|
1910
|
-
(late) => {
|
|
1911
|
-
|
|
1912
|
-
},
|
|
1913
|
-
(error) => {
|
|
1914
|
-
if (answeredEarly) log(`the update failed after the page was told it is still applying: ${error?.message ?? error}`)
|
|
1915
|
-
},
|
|
1940
|
+
(late) => log(`the update finished after the page was told it is still applying: ${String(late?.status ?? 'no status')}`),
|
|
1941
|
+
(error) => log(`the update failed after the page was told it is still applying: ${error?.message ?? error}`),
|
|
1916
1942
|
)
|
|
1917
|
-
const outcome = await Promise.race([work, stillApplying])
|
|
1918
|
-
if (outcome?.status === 'applying') {
|
|
1919
|
-
answeredEarly = true
|
|
1920
|
-
if (timedOut) log('the update outlasted the answer the page waits for: the press is told it is still applying')
|
|
1921
|
-
else log('a press arrived while an update is already applying: the press is told it is still applying')
|
|
1922
|
-
}
|
|
1923
|
-
sendJson(res, 200, outcome)
|
|
1924
|
-
} finally {
|
|
1925
|
-
if (timer !== null) clearTimeout(timer)
|
|
1926
1943
|
}
|
|
1944
|
+
sendJson(res, 200, outcome)
|
|
1927
1945
|
} catch (error) {
|
|
1928
1946
|
log(`cannot apply a plugin reload: ${error?.message ?? error}`)
|
|
1929
1947
|
sendJson(res, 500, { status: 'failed', detail: String(error?.message ?? error) })
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-unlag",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.66",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A press applies plugin edits right away and brings a laggy interface back; automatic reloading stays off unless you turn it on, so the press is the only trigger, and nothing restarts.",
|
|
6
6
|
"license": "MIT",
|