chore(launcher): Electron-only distro, CI sync with Windows pack
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
const { githubToken } = require('./github-token');
|
||||
const { fetchToFile, downloadBodyToFile } = require('./http-download');
|
||||
|
||||
function encodeRepoPath(repoPath) {
|
||||
let p = String(repoPath || '').replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
||||
if (!p) return '';
|
||||
return p.split('/').map((seg) => encodeURIComponent(seg)).join('/');
|
||||
}
|
||||
|
||||
function ghHeaders(token, json = false) {
|
||||
const h = {
|
||||
'User-Agent': 'Fractured-Launcher-Electron',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
};
|
||||
if (json) h.Accept = 'application/vnd.github+json';
|
||||
if (token) h.Authorization = `Bearer ${token}`;
|
||||
return h;
|
||||
}
|
||||
|
||||
async function downloadGitHubRepoFile(cfg, repoPath, destPath) {
|
||||
const token = githubToken(cfg);
|
||||
const enc = encodeRepoPath(repoPath);
|
||||
const ref = cfg.github.ref || 'main';
|
||||
const { owner, repo } = cfg.github;
|
||||
|
||||
if (!token) {
|
||||
const url = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${enc}`;
|
||||
await fetchToFile(url, {}, destPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const apiUrl = `https://api.github.com/repos/${owner}/${repo}/contents/${enc}?ref=${encodeURIComponent(ref)}`;
|
||||
const res = await fetch(apiUrl, { headers: ghHeaders(token, true) });
|
||||
const body = await res.text();
|
||||
if (!res.ok) {
|
||||
throw new Error(`GitHub contents API ${res.status}: ${body.slice(0, 800)}`);
|
||||
}
|
||||
const meta = JSON.parse(body);
|
||||
if (meta.type && meta.type !== 'file') {
|
||||
throw new Error(`not a file: ${repoPath}`);
|
||||
}
|
||||
if (meta.download_url) {
|
||||
const h = { Accept: 'application/octet-stream' };
|
||||
if (token) {
|
||||
h.Authorization = `Bearer ${token}`;
|
||||
h['X-GitHub-Api-Version'] = '2022-11-28';
|
||||
}
|
||||
await fetchToFile(meta.download_url, h, destPath);
|
||||
return;
|
||||
}
|
||||
if (meta.content && meta.encoding === 'base64') {
|
||||
const buf = Buffer.from(String(meta.content).replace(/\n/g, ''), 'base64');
|
||||
if (!buf.length) throw new Error('empty base64 content');
|
||||
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
||||
const tmp = destPath + '.downloading';
|
||||
await fs.writeFile(tmp, buf);
|
||||
await fs.rename(tmp, destPath);
|
||||
return;
|
||||
}
|
||||
throw new Error(`unexpected GitHub response for ${repoPath}`);
|
||||
}
|
||||
|
||||
async function downloadReleaseAsset(cfg, assetName, destPath) {
|
||||
const token = githubToken(cfg);
|
||||
const tag = (cfg.github.release_tag || 'latest').trim() || 'latest';
|
||||
const { owner, repo } = cfg.github;
|
||||
let listUrl;
|
||||
if (tag.toLowerCase() === 'latest') {
|
||||
listUrl = `https://api.github.com/repos/${owner}/${repo}/releases/latest`;
|
||||
} else {
|
||||
listUrl = `https://api.github.com/repos/${owner}/${repo}/releases/tags/${encodeURIComponent(tag)}`;
|
||||
}
|
||||
const res = await fetch(listUrl, { headers: ghHeaders(token, true) });
|
||||
const text = await res.text();
|
||||
if (!res.ok) {
|
||||
let hint = '';
|
||||
if (res.status === 404) hint = ' (wrong tag or private repo without token?)';
|
||||
if (res.status === 401 || res.status === 403) hint = ' (set GITHUB_TOKEN or token_env PAT)';
|
||||
throw new Error(`releases list ${res.status}${hint}: ${text.slice(0, 600)}`);
|
||||
}
|
||||
const rel = JSON.parse(text);
|
||||
const assets = rel.assets || [];
|
||||
let assetURL = '';
|
||||
for (const a of assets) {
|
||||
if (a.name !== assetName) continue;
|
||||
if (token && a.url) {
|
||||
assetURL = a.url;
|
||||
break;
|
||||
}
|
||||
if (a.browser_download_url) {
|
||||
assetURL = a.browser_download_url;
|
||||
break;
|
||||
}
|
||||
assetURL = a.url;
|
||||
break;
|
||||
}
|
||||
if (!assetURL) {
|
||||
const names = assets.map((x) => x.name);
|
||||
throw new Error(`release asset "${assetName}" not found; attachments: ${names.join(', ')}`);
|
||||
}
|
||||
const h = { Accept: 'application/octet-stream' };
|
||||
if (token) {
|
||||
h.Authorization = `Bearer ${token}`;
|
||||
h['X-GitHub-Api-Version'] = '2022-11-28';
|
||||
}
|
||||
const dl = await fetch(assetURL, { headers: h, redirect: 'follow' });
|
||||
await downloadBodyToFile(dl, destPath);
|
||||
}
|
||||
|
||||
module.exports = { downloadGitHubRepoFile, downloadReleaseAsset, encodeRepoPath };
|
||||
Reference in New Issue
Block a user