54 lines
2.3 KiB
TypeScript
54 lines
2.3 KiB
TypeScript
/** Electron-native inactivity deadlines for updater checks, full downloads, and blockmap requests. */
|
|
import { ElectronHttpExecutor } from 'electron-updater/out/electronHttpExecutor.js'
|
|
import type { ClientRequest, IncomingMessage } from 'electron'
|
|
|
|
/** Retains electron-updater transport and proxy handling while bounding silent connections. */
|
|
export class DesktopUpdateHttpExecutor extends ElectronHttpExecutor {
|
|
/**
|
|
* @param idleTimeoutMs - Maximum silence before headers or between response chunks, not a total download deadline.
|
|
* @param proxyLogin - Existing updater login event forwarding.
|
|
*/
|
|
constructor(private readonly idleTimeoutMs: number, proxyLogin?: ConstructorParameters<typeof ElectronHttpExecutor>[0]) {
|
|
super(proxyLogin)
|
|
if (!Number.isSafeInteger(idleTimeoutMs) || idleTimeoutMs < 1000 || idleTimeoutMs > 2_147_483_647) {
|
|
throw new Error('desktop update: HTTP idle timeout must be an integer from 1000 through 2147483647')
|
|
}
|
|
}
|
|
|
|
override addErrorAndTimeoutHandlers(request: ClientRequest, reject: (error: Error) => void): void {
|
|
// The upstream socket timer is for Node HTTP; Electron ClientRequest has response/close events instead.
|
|
super.addErrorAndTimeoutHandlers(request, reject, this.idleTimeoutMs)
|
|
let response: IncomingMessage | undefined
|
|
let timer: ReturnType<typeof setTimeout>
|
|
const stop = (): void => {
|
|
clearTimeout(timer)
|
|
request.off('response', onResponse)
|
|
request.off('abort', stop)
|
|
request.off('error', stop)
|
|
response?.off('data', refresh)
|
|
response?.off('end', stop)
|
|
response?.off('error', stop)
|
|
}
|
|
const refresh = (): void => {
|
|
clearTimeout(timer)
|
|
timer = setTimeout(() => {
|
|
stop()
|
|
reject(Object.assign(new Error('Desktop update connection timed out'), { code: 'ETIMEDOUT' }))
|
|
request.abort()
|
|
}, this.idleTimeoutMs)
|
|
}
|
|
const onResponse = (incoming: IncomingMessage): void => {
|
|
response = incoming
|
|
response.on('data', refresh)
|
|
response.once('end', stop)
|
|
response.once('error', stop)
|
|
refresh()
|
|
}
|
|
request.once('response', onResponse)
|
|
// Electron 44 can emit writable close after finish, before response headers arrive.
|
|
request.once('abort', stop)
|
|
request.once('error', stop)
|
|
refresh()
|
|
}
|
|
}
|