mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(desktop): download the version a linux update prompt names (#2673)
This commit is contained in:
@@ -1,23 +1,26 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {createRequire} from 'node:module';
|
||||
import {BUILD_CHANNEL} from '@electron/common/BuildChannel';
|
||||
import {isPortableMode} from '@electron/common/UserDataPath';
|
||||
import {destroyDesktopTray} from '@electron/main/DesktopTray';
|
||||
import {isFlatpakRuntime} from '@electron/main/LinuxSandbox';
|
||||
import {
|
||||
DOWNLOAD_PAGE_URL,
|
||||
getManualDownloadOptions,
|
||||
getManualDownloadUrl,
|
||||
MANUAL_DESKTOP_FORMATS,
|
||||
type ManualDesktopFormat,
|
||||
type ManualLatestFile,
|
||||
type ManualLatestInfo,
|
||||
UPDATE_BASE_URL,
|
||||
type UpdaterDownloadOption,
|
||||
} from '@electron/main/UpdaterDownloads';
|
||||
import {setQuitting} from '@electron/main/Window';
|
||||
import {app, autoUpdater, type BrowserWindow, ipcMain} from 'electron';
|
||||
import log from 'electron-log';
|
||||
import type {UpdateInfo} from 'velopack';
|
||||
|
||||
type UpdaterContext = 'user' | 'background' | 'focus';
|
||||
type UpdaterDownloadOption = {
|
||||
format: ManualDesktopFormat;
|
||||
label: string;
|
||||
url: string;
|
||||
suggestedName?: string;
|
||||
sha256?: string | null;
|
||||
};
|
||||
type UpdaterEvent =
|
||||
| {
|
||||
type: 'checking';
|
||||
@@ -63,17 +66,6 @@ type UpdaterEvent =
|
||||
};
|
||||
|
||||
const requireModule = createRequire(import.meta.url);
|
||||
type DesktopDownloadArch = 'x64' | 'arm64';
|
||||
|
||||
function getDesktopDownloadArch(arch: NodeJS.Architecture): DesktopDownloadArch {
|
||||
return arch === 'arm64' ? 'arm64' : 'x64';
|
||||
}
|
||||
|
||||
const DESKTOP_DOWNLOAD_ARCH = getDesktopDownloadArch(process.arch);
|
||||
const UPDATE_API_ENDPOINT = BUILD_CHANNEL === 'canary' ? 'https://api.canary.fluxer.app' : 'https://api.fluxer.app';
|
||||
const UPDATE_BASE_URL = `${UPDATE_API_ENDPOINT}/dl/desktop/${BUILD_CHANNEL}/${process.platform}/${DESKTOP_DOWNLOAD_ARCH}`;
|
||||
const DOWNLOAD_PAGE_URL =
|
||||
BUILD_CHANNEL === 'canary' ? 'https://canary.fluxer.app/download' : 'https://fluxer.app/download';
|
||||
|
||||
let lastContext: UpdaterContext = 'background';
|
||||
let pendingVelopackUpdate: UpdateInfo | null = null;
|
||||
@@ -86,12 +78,6 @@ const UPDATE_DOWNLOAD_RETRY_BASE_DELAY_MS = 3000;
|
||||
const UPDATE_DOWNLOAD_RETRY_MAX_DELAY_MS = 60000;
|
||||
const ELECTRON_DOWNLOAD_MAX_RETRIES = 4;
|
||||
|
||||
const MANUAL_DESKTOP_FORMATS = ['setup', 'dmg', 'zip', 'appimage', 'deb', 'rpm', 'tar_gz'] as const;
|
||||
|
||||
type ManualDesktopFormat = (typeof MANUAL_DESKTOP_FORMATS)[number];
|
||||
type ManualLatestFile = {url: string; sha256: string | null};
|
||||
type LinuxManualDesktopFormat = Extract<ManualDesktopFormat, 'appimage' | 'deb' | 'rpm' | 'tar_gz'>;
|
||||
|
||||
function send(win: BrowserWindow | null, event: UpdaterEvent) {
|
||||
win?.webContents.send('updater-event', event);
|
||||
}
|
||||
@@ -399,12 +385,6 @@ function registerElectronUpdater(getMainWindow: () => BrowserWindow | null): voi
|
||||
});
|
||||
}
|
||||
|
||||
type ManualLatestInfo = {
|
||||
version: string;
|
||||
pubDate: string | null;
|
||||
files: Partial<Record<ManualDesktopFormat, ManualLatestFile>>;
|
||||
};
|
||||
|
||||
let manualLatestCache: {at: number; info: ManualLatestInfo} | null = null;
|
||||
|
||||
const MANUAL_CACHE_TTL_MS = 5 * 60 * 1000;
|
||||
@@ -453,90 +433,6 @@ function parseManualLatestFiles(value: unknown): Partial<Record<ManualDesktopFor
|
||||
return files;
|
||||
}
|
||||
|
||||
function getManualDownloadFormatPreference(): Array<ManualDesktopFormat> {
|
||||
if (process.platform === 'linux') {
|
||||
return ['appimage', 'deb', 'rpm', 'tar_gz'];
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
return ['dmg', 'zip'];
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
return ['setup'];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
const LINUX_MANUAL_FORMAT_LABELS: Record<LinuxManualDesktopFormat, string> = {
|
||||
appimage: 'AppImage',
|
||||
deb: 'DEB package',
|
||||
rpm: 'RPM package',
|
||||
tar_gz: 'tar.gz archive',
|
||||
};
|
||||
|
||||
const LINUX_MANUAL_FORMAT_EXTENSIONS: Record<LinuxManualDesktopFormat, string> = {
|
||||
appimage: '.AppImage',
|
||||
deb: '.deb',
|
||||
rpm: '.rpm',
|
||||
tar_gz: '.tar.gz',
|
||||
};
|
||||
|
||||
const LINUX_MANUAL_ARCH_TOKENS: Record<LinuxManualDesktopFormat, Record<DesktopDownloadArch, string>> = {
|
||||
appimage: {x64: 'x86_64', arm64: 'arm64'},
|
||||
deb: {x64: 'amd64', arm64: 'arm64'},
|
||||
rpm: {x64: 'x86_64', arm64: 'aarch64'},
|
||||
tar_gz: {x64: 'x64', arm64: 'arm64'},
|
||||
};
|
||||
|
||||
function isLinuxManualDesktopFormat(format: ManualDesktopFormat): format is LinuxManualDesktopFormat {
|
||||
return format === 'appimage' || format === 'deb' || format === 'rpm' || format === 'tar_gz';
|
||||
}
|
||||
|
||||
function buildManualLatestDownloadUrl(format: ManualDesktopFormat): string {
|
||||
return `${UPDATE_BASE_URL}/latest/${format}`;
|
||||
}
|
||||
|
||||
function getArtifactProductName(): string {
|
||||
return BUILD_CHANNEL === 'canary' ? 'Fluxer-Canary' : 'Fluxer';
|
||||
}
|
||||
|
||||
function getManualUpdateSuggestedName(format: LinuxManualDesktopFormat, version: string): string {
|
||||
const archToken = LINUX_MANUAL_ARCH_TOKENS[format][DESKTOP_DOWNLOAD_ARCH];
|
||||
const extension = LINUX_MANUAL_FORMAT_EXTENSIONS[format];
|
||||
return `${getArtifactProductName()}-${version}-linux-${archToken}${extension}`;
|
||||
}
|
||||
|
||||
function getManualDownloadOptions(info: ManualLatestInfo): Array<UpdaterDownloadOption> {
|
||||
if (process.platform !== 'linux') {
|
||||
return [];
|
||||
}
|
||||
return getManualDownloadFormatPreference()
|
||||
.filter(isLinuxManualDesktopFormat)
|
||||
.map((format) => {
|
||||
const file = info.files[format];
|
||||
return {
|
||||
format,
|
||||
label: LINUX_MANUAL_FORMAT_LABELS[format],
|
||||
url: buildManualLatestDownloadUrl(format),
|
||||
suggestedName: getManualUpdateSuggestedName(format, info.version),
|
||||
sha256: file?.sha256 ?? null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getManualDownloadUrl(info: ManualLatestInfo): string {
|
||||
const [preferredOption] = getManualDownloadOptions(info);
|
||||
if (preferredOption) {
|
||||
return preferredOption.url;
|
||||
}
|
||||
for (const format of getManualDownloadFormatPreference()) {
|
||||
const url = info.files[format]?.url;
|
||||
if (url) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
return DOWNLOAD_PAGE_URL;
|
||||
}
|
||||
|
||||
async function fetchManualLatest(options: {forceRefresh?: boolean} = {}): Promise<ManualLatestInfo> {
|
||||
const now = Date.now();
|
||||
if (!options.forceRefresh && manualLatestCache && now - manualLatestCache.at < MANUAL_CACHE_TTL_MS) {
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import {readFileSync} from 'node:fs';
|
||||
import {createRequire} from 'node:module';
|
||||
import {describe, test} from 'node:test';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import vm from 'node:vm';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const sourcePath = fileURLToPath(new URL('./UpdaterDownloads.ts', import.meta.url));
|
||||
const source = readFileSync(sourcePath, 'utf8');
|
||||
const transformedSource = esbuild.transformSync(source, {
|
||||
loader: 'ts',
|
||||
format: 'cjs',
|
||||
platform: 'node',
|
||||
target: 'node20',
|
||||
}).code;
|
||||
|
||||
const APPIMAGE_SHA256 = 'a'.repeat(64);
|
||||
const DEB_SHA256 = 'b'.repeat(64);
|
||||
const TAR_GZ_SHA256 = 'c'.repeat(64);
|
||||
|
||||
function loadUpdaterDownloads({channel = 'stable', platform = 'linux', arch = 'x64'} = {}) {
|
||||
function requireStub(specifier) {
|
||||
if (specifier === '@electron/common/BuildChannel') return {BUILD_CHANNEL: channel};
|
||||
throw new Error(`Unexpected import: ${specifier}`);
|
||||
}
|
||||
|
||||
const module = {exports: {}};
|
||||
const context = vm.createContext({
|
||||
require: requireStub,
|
||||
module,
|
||||
exports: module.exports,
|
||||
process: {platform, arch},
|
||||
});
|
||||
vm.runInContext(transformedSource, context, {filename: sourcePath});
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
function latestInfo(version, files = {}) {
|
||||
return {version, pubDate: null, files};
|
||||
}
|
||||
|
||||
describe('UpdaterDownloads Linux manual update options', () => {
|
||||
test('pins every format to the version its name and checksum describe', () => {
|
||||
const {getManualDownloadOptions} = loadUpdaterDownloads();
|
||||
const info = latestInfo('2026.910.101500', {
|
||||
appimage: {
|
||||
url: 'https://web.fluxer.app/api/dl/desktop/stable/linux/x64/2026.910.101500/appimage',
|
||||
sha256: APPIMAGE_SHA256,
|
||||
},
|
||||
deb: {url: 'https://web.fluxer.app/api/dl/desktop/stable/linux/x64/2026.910.101500/deb', sha256: DEB_SHA256},
|
||||
tar_gz: {
|
||||
url: 'https://web.fluxer.app/api/dl/desktop/stable/linux/x64/2026.910.101500/tar_gz',
|
||||
sha256: TAR_GZ_SHA256,
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(structuredClone(getManualDownloadOptions(info)), [
|
||||
{
|
||||
format: 'appimage',
|
||||
label: 'AppImage',
|
||||
url: 'https://api.fluxer.app/dl/desktop/stable/linux/x64/2026.910.101500/appimage',
|
||||
suggestedName: 'Fluxer-2026.910.101500-linux-x86_64.AppImage',
|
||||
sha256: APPIMAGE_SHA256,
|
||||
},
|
||||
{
|
||||
format: 'deb',
|
||||
label: 'DEB package',
|
||||
url: 'https://api.fluxer.app/dl/desktop/stable/linux/x64/2026.910.101500/deb',
|
||||
suggestedName: 'Fluxer-2026.910.101500-linux-amd64.deb',
|
||||
sha256: DEB_SHA256,
|
||||
},
|
||||
{
|
||||
format: 'rpm',
|
||||
label: 'RPM package',
|
||||
url: 'https://api.fluxer.app/dl/desktop/stable/linux/x64/2026.910.101500/rpm',
|
||||
suggestedName: 'Fluxer-2026.910.101500-linux-x86_64.rpm',
|
||||
sha256: null,
|
||||
},
|
||||
{
|
||||
format: 'tar_gz',
|
||||
label: 'tar.gz archive',
|
||||
url: 'https://api.fluxer.app/dl/desktop/stable/linux/x64/2026.910.101500/tar_gz',
|
||||
suggestedName: 'Fluxer-2026.910.101500-linux-x64.tar.gz',
|
||||
sha256: TAR_GZ_SHA256,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('uses arm64 architecture tokens in every url and name', () => {
|
||||
const {getManualDownloadOptions} = loadUpdaterDownloads({arch: 'arm64'});
|
||||
const options = structuredClone(getManualDownloadOptions(latestInfo('2026.910.101500')));
|
||||
|
||||
assert.deepEqual(
|
||||
options.map((option) => [option.url, option.suggestedName]),
|
||||
[
|
||||
[
|
||||
'https://api.fluxer.app/dl/desktop/stable/linux/arm64/2026.910.101500/appimage',
|
||||
'Fluxer-2026.910.101500-linux-arm64.AppImage',
|
||||
],
|
||||
[
|
||||
'https://api.fluxer.app/dl/desktop/stable/linux/arm64/2026.910.101500/deb',
|
||||
'Fluxer-2026.910.101500-linux-arm64.deb',
|
||||
],
|
||||
[
|
||||
'https://api.fluxer.app/dl/desktop/stable/linux/arm64/2026.910.101500/rpm',
|
||||
'Fluxer-2026.910.101500-linux-aarch64.rpm',
|
||||
],
|
||||
[
|
||||
'https://api.fluxer.app/dl/desktop/stable/linux/arm64/2026.910.101500/tar_gz',
|
||||
'Fluxer-2026.910.101500-linux-arm64.tar.gz',
|
||||
],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test('names canary and stable artefacts after their own product and api', () => {
|
||||
const info = latestInfo('2026.910.101500');
|
||||
const stableDeb = structuredClone(loadUpdaterDownloads({channel: 'stable'}).getManualDownloadOptions(info)).find(
|
||||
(option) => option.format === 'deb',
|
||||
);
|
||||
const canaryDeb = structuredClone(loadUpdaterDownloads({channel: 'canary'}).getManualDownloadOptions(info)).find(
|
||||
(option) => option.format === 'deb',
|
||||
);
|
||||
|
||||
assert.equal(stableDeb.url, 'https://api.fluxer.app/dl/desktop/stable/linux/x64/2026.910.101500/deb');
|
||||
assert.equal(stableDeb.suggestedName, 'Fluxer-2026.910.101500-linux-amd64.deb');
|
||||
assert.equal(canaryDeb.url, 'https://api.canary.fluxer.app/dl/desktop/canary/linux/x64/2026.910.101500/deb');
|
||||
assert.equal(canaryDeb.suggestedName, 'Fluxer-Canary-2026.910.101500-linux-amd64.deb');
|
||||
});
|
||||
|
||||
test('only ever fetches 2026.908.173325 for a prompt built from that release', () => {
|
||||
const {getManualDownloadOptions, getManualDownloadUrl} = loadUpdaterDownloads({channel: 'canary'});
|
||||
const info = latestInfo('2026.908.173325', {
|
||||
deb: {
|
||||
url: 'https://web.canary.fluxer.app/api/dl/desktop/canary/linux/x64/2026.908.173325/deb',
|
||||
sha256: DEB_SHA256,
|
||||
},
|
||||
});
|
||||
const options = structuredClone(getManualDownloadOptions(info));
|
||||
const deb = options.find((option) => option.format === 'deb');
|
||||
|
||||
assert.equal(deb.suggestedName, 'Fluxer-Canary-2026.908.173325-linux-amd64.deb');
|
||||
assert.equal(deb.url, 'https://api.canary.fluxer.app/dl/desktop/canary/linux/x64/2026.908.173325/deb');
|
||||
assert.equal(deb.sha256, DEB_SHA256);
|
||||
assert.equal(options.length, 4);
|
||||
for (const option of options) {
|
||||
const [format, version] = new URL(option.url).pathname.split('/').reverse();
|
||||
assert.equal(format, option.format);
|
||||
assert.equal(version, '2026.908.173325');
|
||||
assert.match(option.suggestedName, /^Fluxer-Canary-2026\.908\.173325-linux-/);
|
||||
}
|
||||
assert.equal(
|
||||
getManualDownloadUrl(info),
|
||||
'https://api.canary.fluxer.app/dl/desktop/canary/linux/x64/2026.908.173325/appimage',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UpdaterDownloads manual download url', () => {
|
||||
test('prefers the pinned Linux option over the response file urls', () => {
|
||||
const {getManualDownloadUrl} = loadUpdaterDownloads();
|
||||
const info = latestInfo('2026.910.101500', {
|
||||
appimage: {
|
||||
url: 'https://web.fluxer.app/api/dl/desktop/stable/linux/x64/2026.910.101500/appimage',
|
||||
sha256: null,
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
getManualDownloadUrl(info),
|
||||
'https://api.fluxer.app/dl/desktop/stable/linux/x64/2026.910.101500/appimage',
|
||||
);
|
||||
});
|
||||
|
||||
test('falls back to the response file urls in format order on macOS', () => {
|
||||
const {getManualDownloadOptions, getManualDownloadUrl} = loadUpdaterDownloads({platform: 'darwin', arch: 'arm64'});
|
||||
const dmg = {url: 'https://web.fluxer.app/api/dl/desktop/stable/darwin/arm64/2026.910.101500/dmg', sha256: null};
|
||||
const zip = {url: 'https://web.fluxer.app/api/dl/desktop/stable/darwin/arm64/2026.910.101500/zip', sha256: null};
|
||||
|
||||
assert.equal(getManualDownloadOptions(latestInfo('2026.910.101500', {dmg, zip})).length, 0);
|
||||
assert.equal(getManualDownloadUrl(latestInfo('2026.910.101500', {zip, dmg})), dmg.url);
|
||||
assert.equal(getManualDownloadUrl(latestInfo('2026.910.101500', {zip})), zip.url);
|
||||
});
|
||||
|
||||
test('falls back to the setup file url on Windows', () => {
|
||||
const {getManualDownloadOptions, getManualDownloadUrl} = loadUpdaterDownloads({platform: 'win32'});
|
||||
const setup = {url: 'https://web.fluxer.app/api/dl/desktop/stable/win32/x64/2026.910.101500/setup', sha256: null};
|
||||
|
||||
assert.equal(getManualDownloadOptions(latestInfo('2026.910.101500', {setup})).length, 0);
|
||||
assert.equal(getManualDownloadUrl(latestInfo('2026.910.101500', {setup})), setup.url);
|
||||
});
|
||||
|
||||
test('falls back to the download page when no file resolves', () => {
|
||||
const stable = loadUpdaterDownloads({channel: 'stable', platform: 'darwin'});
|
||||
const canary = loadUpdaterDownloads({channel: 'canary', platform: 'win32'});
|
||||
|
||||
assert.equal(stable.getManualDownloadUrl(latestInfo('2026.910.101500')), 'https://fluxer.app/download');
|
||||
assert.equal(canary.getManualDownloadUrl(latestInfo('2026.910.101500')), 'https://canary.fluxer.app/download');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {BUILD_CHANNEL} from '@electron/common/BuildChannel';
|
||||
|
||||
export type UpdaterDownloadOption = {
|
||||
format: ManualDesktopFormat;
|
||||
label: string;
|
||||
url: string;
|
||||
suggestedName?: string;
|
||||
sha256?: string | null;
|
||||
};
|
||||
|
||||
type DesktopDownloadArch = 'x64' | 'arm64';
|
||||
|
||||
function getDesktopDownloadArch(arch: NodeJS.Architecture): DesktopDownloadArch {
|
||||
return arch === 'arm64' ? 'arm64' : 'x64';
|
||||
}
|
||||
|
||||
const DESKTOP_DOWNLOAD_ARCH = getDesktopDownloadArch(process.arch);
|
||||
const UPDATE_API_ENDPOINT = BUILD_CHANNEL === 'canary' ? 'https://api.canary.fluxer.app' : 'https://api.fluxer.app';
|
||||
export const UPDATE_BASE_URL = `${UPDATE_API_ENDPOINT}/dl/desktop/${BUILD_CHANNEL}/${process.platform}/${DESKTOP_DOWNLOAD_ARCH}`;
|
||||
export const DOWNLOAD_PAGE_URL =
|
||||
BUILD_CHANNEL === 'canary' ? 'https://canary.fluxer.app/download' : 'https://fluxer.app/download';
|
||||
|
||||
export const MANUAL_DESKTOP_FORMATS = ['setup', 'dmg', 'zip', 'appimage', 'deb', 'rpm', 'tar_gz'] as const;
|
||||
|
||||
export type ManualDesktopFormat = (typeof MANUAL_DESKTOP_FORMATS)[number];
|
||||
export type ManualLatestFile = {url: string; sha256: string | null};
|
||||
type LinuxManualDesktopFormat = Extract<ManualDesktopFormat, 'appimage' | 'deb' | 'rpm' | 'tar_gz'>;
|
||||
|
||||
export type ManualLatestInfo = {
|
||||
version: string;
|
||||
pubDate: string | null;
|
||||
files: Partial<Record<ManualDesktopFormat, ManualLatestFile>>;
|
||||
};
|
||||
|
||||
function getManualDownloadFormatPreference(): Array<ManualDesktopFormat> {
|
||||
if (process.platform === 'linux') {
|
||||
return ['appimage', 'deb', 'rpm', 'tar_gz'];
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
return ['dmg', 'zip'];
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
return ['setup'];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
const LINUX_MANUAL_FORMAT_LABELS: Record<LinuxManualDesktopFormat, string> = {
|
||||
appimage: 'AppImage',
|
||||
deb: 'DEB package',
|
||||
rpm: 'RPM package',
|
||||
tar_gz: 'tar.gz archive',
|
||||
};
|
||||
|
||||
const LINUX_MANUAL_FORMAT_EXTENSIONS: Record<LinuxManualDesktopFormat, string> = {
|
||||
appimage: '.AppImage',
|
||||
deb: '.deb',
|
||||
rpm: '.rpm',
|
||||
tar_gz: '.tar.gz',
|
||||
};
|
||||
|
||||
const LINUX_MANUAL_ARCH_TOKENS: Record<LinuxManualDesktopFormat, Record<DesktopDownloadArch, string>> = {
|
||||
appimage: {x64: 'x86_64', arm64: 'arm64'},
|
||||
deb: {x64: 'amd64', arm64: 'arm64'},
|
||||
rpm: {x64: 'x86_64', arm64: 'aarch64'},
|
||||
tar_gz: {x64: 'x64', arm64: 'arm64'},
|
||||
};
|
||||
|
||||
function isLinuxManualDesktopFormat(format: ManualDesktopFormat): format is LinuxManualDesktopFormat {
|
||||
return format === 'appimage' || format === 'deb' || format === 'rpm' || format === 'tar_gz';
|
||||
}
|
||||
|
||||
function buildManualVersionDownloadUrl(version: string, format: ManualDesktopFormat): string {
|
||||
return `${UPDATE_BASE_URL}/${version}/${format}`;
|
||||
}
|
||||
|
||||
function getArtifactProductName(): string {
|
||||
return BUILD_CHANNEL === 'canary' ? 'Fluxer-Canary' : 'Fluxer';
|
||||
}
|
||||
|
||||
function getManualUpdateSuggestedName(format: LinuxManualDesktopFormat, version: string): string {
|
||||
const archToken = LINUX_MANUAL_ARCH_TOKENS[format][DESKTOP_DOWNLOAD_ARCH];
|
||||
const extension = LINUX_MANUAL_FORMAT_EXTENSIONS[format];
|
||||
return `${getArtifactProductName()}-${version}-linux-${archToken}${extension}`;
|
||||
}
|
||||
|
||||
export function getManualDownloadOptions(info: ManualLatestInfo): Array<UpdaterDownloadOption> {
|
||||
if (process.platform !== 'linux') {
|
||||
return [];
|
||||
}
|
||||
return getManualDownloadFormatPreference()
|
||||
.filter(isLinuxManualDesktopFormat)
|
||||
.map((format) => {
|
||||
const file = info.files[format];
|
||||
return {
|
||||
format,
|
||||
label: LINUX_MANUAL_FORMAT_LABELS[format],
|
||||
url: buildManualVersionDownloadUrl(info.version, format),
|
||||
suggestedName: getManualUpdateSuggestedName(format, info.version),
|
||||
sha256: file?.sha256 ?? null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function getManualDownloadUrl(info: ManualLatestInfo): string {
|
||||
const [preferredOption] = getManualDownloadOptions(info);
|
||||
if (preferredOption) {
|
||||
return preferredOption.url;
|
||||
}
|
||||
for (const format of getManualDownloadFormatPreference()) {
|
||||
const url = info.files[format]?.url;
|
||||
if (url) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
return DOWNLOAD_PAGE_URL;
|
||||
}
|
||||
Reference in New Issue
Block a user