mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-08-13 01:55:50 -07:00
86 lines
3.1 KiB
TypeScript
86 lines
3.1 KiB
TypeScript
import type { ChangelogSnapshot } from '../../../types/changelog';
|
|
import type { UpdateChannel } from '../../../types/config';
|
|
import { createCurlFetch, createGlobalFetch } from '../update/fetch-adapter';
|
|
import { fetchLatestStableRelease, type FetchLike } from '../update/release-assets';
|
|
import { readBundledChangelog, resolveBundledChangelogPath } from './bundled-changelog';
|
|
import { createChangelogSource } from './changelog-source';
|
|
|
|
export interface ChangelogRuntimeDeps {
|
|
getInstalledVersion: () => string;
|
|
getUpdateChannel: () => UpdateChannel;
|
|
resourcesPath: string;
|
|
appPath: string;
|
|
dirname: string;
|
|
joinPath: (...parts: string[]) => string;
|
|
fileExists: (path: string) => boolean;
|
|
readFile: (path: string) => string;
|
|
logWarn: (message: string) => void;
|
|
/** Injected in tests; production picks curl on POSIX and global fetch on Windows. */
|
|
createFetch?: () => FetchLike;
|
|
}
|
|
|
|
/**
|
|
* curl enforces its own `--max-time`, but the global-fetch transport has no
|
|
* deadline: without this a stalled connection leaves the modal on "Loading
|
|
* changelog..." with no way back except closing it.
|
|
*/
|
|
export const CHANGELOG_REQUEST_TIMEOUT_MS = 30_000;
|
|
|
|
export function withRequestTimeout(fetchImpl: FetchLike, timeoutMs: number): FetchLike {
|
|
return (url, init) => {
|
|
if (typeof AbortSignal?.timeout !== 'function') return fetchImpl(url, init);
|
|
return fetchImpl(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
|
|
};
|
|
}
|
|
|
|
export function createChangelogRuntime(deps: ChangelogRuntimeDeps): {
|
|
getChangelogSnapshot: (options?: { refresh?: boolean }) => Promise<ChangelogSnapshot>;
|
|
} {
|
|
// curl matches the updater's transport choice: Electron's global fetch is
|
|
// unreliable for GitHub on some Linux builds.
|
|
const fetchImpl = withRequestTimeout(
|
|
deps.createFetch?.() ??
|
|
(process.platform === 'win32' ? createGlobalFetch() : createCurlFetch()),
|
|
CHANGELOG_REQUEST_TIMEOUT_MS,
|
|
);
|
|
|
|
const source = createChangelogSource({
|
|
fetchLatestReleaseTag: async () => {
|
|
const release = await fetchLatestStableRelease({
|
|
fetch: fetchImpl,
|
|
channel: deps.getUpdateChannel(),
|
|
});
|
|
return release?.tag_name ?? null;
|
|
},
|
|
fetchText: async (url) => {
|
|
const response = await fetchImpl(url, {
|
|
headers: { 'User-Agent': 'SubMiner changelog' },
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Changelog request failed with ${response.status}`);
|
|
}
|
|
return await response.text();
|
|
},
|
|
readBundledChangelog: () =>
|
|
readBundledChangelog({
|
|
resolvePath: () =>
|
|
resolveBundledChangelogPath({
|
|
resourcesPath: deps.resourcesPath,
|
|
appPath: deps.appPath,
|
|
dirname: deps.dirname,
|
|
joinPath: deps.joinPath,
|
|
fileExists: deps.fileExists,
|
|
}),
|
|
readFile: deps.readFile,
|
|
logWarn: deps.logWarn,
|
|
}),
|
|
getInstalledVersion: deps.getInstalledVersion,
|
|
now: () => Date.now(),
|
|
logWarn: deps.logWarn,
|
|
});
|
|
|
|
return {
|
|
getChangelogSnapshot: (options?: { refresh?: boolean }) => source.getSnapshot(options),
|
|
};
|
|
}
|