Remove Polyfills (#101)
* poly: remove completely * bootstrap: remove unused request require * asarUpdate: rewrite request -> https * moduleUpdater: rewrite request -> https * ui: fallback to channel instead of "custom" if no hash * index: set name to branch for obvious testing * config/backend: tweak source * moduleUpdater: fix rewrite * moduleUpdater: fix rewrite (x2) * moduleUpdater: follow redirects with rewrite * ci: start multi-branch rewrite * ci: upgrade node to 18.x * ci: rewrite version changing to use existing * ci: change release version getting to in file * ci: mess with yaml syntax * ci: revert to node 16.x, fix version wrapped in quotes * ci: fix invalid yaml * ci: yaml syntax fixing * ci: append to tag * ci: make pre-release unless nightly build * ci: add title nicening * asarUpdate: fix release suffix * asarUpdate: fix not following redirect * winFirst: don't remake shortcuts, tweaks * ui: add channel prefix if non-nightly * chore: prep for main branch
This commit is contained in:
parent
f2da613f2b
commit
ec5082860e
11 changed files with 61 additions and 175 deletions
19
.github/workflows/nightly.yml
vendored
19
.github/workflows/nightly.yml
vendored
|
@ -6,7 +6,6 @@ on:
|
|||
paths:
|
||||
- 'src/**'
|
||||
- 'scripts/**'
|
||||
- 'poly/**'
|
||||
- '.github/workflows/**'
|
||||
|
||||
jobs:
|
||||
|
@ -25,8 +24,7 @@ jobs:
|
|||
- name: Pack base asar
|
||||
run: |
|
||||
npm i -g asar
|
||||
bash scripts/injectPolyfills.sh
|
||||
sed -i -e "s/nightly/nightly-$(git rev-parse HEAD | cut -c 1-7)/" src/index.js
|
||||
sed -i -e "s/oaVersion = '\(.*\)'/oaVersion = '\1-$(git rev-parse HEAD | cut -c 1-7)'/" src/index.js
|
||||
node scripts/strip.js
|
||||
npx asar pack src app.asar
|
||||
|
||||
|
@ -147,15 +145,16 @@ jobs:
|
|||
|
||||
- name: GitHub Release
|
||||
run: |
|
||||
git tag -d nightly || true
|
||||
git push origin --delete nightly || true
|
||||
git tag nightly
|
||||
git push origin nightly
|
||||
echo ${{ env.VERSION }}
|
||||
git tag -d ${{ env.VERSION }} || true
|
||||
git push origin --delete ${{ env.VERSION }} || true
|
||||
git tag ${{ env.VERSION }}
|
||||
git push origin ${{ env.VERSION }}
|
||||
gh release delete ${{ env.VERSION }} -y || true
|
||||
gh release create ${{ env.VERSION }} -t "Nightly" -n "$(git rev-parse HEAD | cut -c 1-7) | $(git log -1 --pretty=%B)" ${{ env.FILES }}
|
||||
gh release create ${{ env.VERSION }} -t "$(echo "${{ env.VERSION }}" | sed 's/.*/\u&/' | sed "s/nt/n't/")" -n "$(git rev-parse HEAD | cut -c 1-7) | $(git log -1 --pretty=%B)" "$([ "${{ env.VERSION }}" != "nightly" ] && echo "-p")" ${{ env.FILES }}
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
|
||||
VERSION: 'nightly'
|
||||
VERSION: $(strings app.asar | grep -oP "oaVersion='.*?-" | grep -oP "(?<=').*?(?=-)")
|
||||
FILES: app.asar
|
||||
|
||||
# debug-linux:
|
||||
|
@ -230,4 +229,4 @@ jobs:
|
|||
# cd discord/app-1.0.0
|
||||
# ./DiscordCanary.exe --enable-logging
|
||||
# timeout-minutes: 5
|
||||
# shell: bash
|
||||
# shell: bash
|
2
faq.md
2
faq.md
|
@ -22,7 +22,7 @@ OpenAsar optimizes Chromium (the web engine / browser Discord uses) to help incr
|
|||
The main speed increase (default options) is mostly accidental / coincidental (not intended) as it is mostly a side effect of rewriting it.
|
||||
|
||||
### How is this so small?
|
||||
Compared to Discord's original, OpenAsar is <2% of the size. This is because when rewriting we remove NPM dependencies with our own custom code for more performance and efficiency. These are replaced with custom polyfills (compatible replacements).
|
||||
Compared to Discord's original, OpenAsar is <2% of the size. This is because when rewriting we remove NPM dependencies with our own custom code for more performance and efficiency.
|
||||
|
||||
### What is Quickstart?
|
||||
Quickstart "skips" a few Discord features like the splash screen and waiting for updates in favour of speed. It is currently experimental and not fully recommended for normal use.
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
// Stub
|
||||
exports.lookup = (file) => 'text/plain';
|
|
@ -1,84 +0,0 @@
|
|||
const https = require('https');
|
||||
|
||||
// Generic polyfill for "request" npm package, wrapper for https
|
||||
const nodeReq = ({ method, url, headers, qs, timeout, body }) => new Promise((resolve) => {
|
||||
let req;
|
||||
try {
|
||||
req = https.request(url + (qs != null ? `?${(new URLSearchParams(qs)).toString()}` : ''), { method, headers, timeout }, async (res) => {
|
||||
const loc = res.headers.location;
|
||||
if (loc) return resolve(await nodeReq({ url: loc, method, headers, timeout, body }));
|
||||
|
||||
resolve(res);
|
||||
});
|
||||
} catch (e) {
|
||||
return resolve(e);
|
||||
}
|
||||
|
||||
req.on('error', resolve);
|
||||
|
||||
if (body) req.write(body); // Write POST body if included
|
||||
|
||||
req.end();
|
||||
});
|
||||
|
||||
const request = (...args) => {
|
||||
let options, callback;
|
||||
switch (args.length) {
|
||||
case 3: // request(url, options, callback)
|
||||
options = {
|
||||
url: args[0],
|
||||
...args[1]
|
||||
};
|
||||
|
||||
callback = args[2];
|
||||
break;
|
||||
|
||||
default: // request(url, callback) / request(options, callback)
|
||||
options = args[0];
|
||||
callback = args[1];
|
||||
}
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
url: options
|
||||
};
|
||||
}
|
||||
|
||||
const listeners = {};
|
||||
|
||||
nodeReq(options).then(async (res) => {
|
||||
if (!res.statusCode) {
|
||||
listeners['error']?.(res);
|
||||
return callback?.(res, null, null);
|
||||
}
|
||||
|
||||
listeners['response']?.(res);
|
||||
|
||||
let data = [];
|
||||
res.on('data', (chunk) => {
|
||||
data.push(chunk);
|
||||
listeners['data']?.(chunk);
|
||||
});
|
||||
|
||||
await new Promise((resolve) => res.on('end', resolve)); // Wait to read full body
|
||||
|
||||
const buf = Buffer.concat(data);
|
||||
callback?.(undefined, res, options.encoding !== null ? buf.toString() : buf);
|
||||
});
|
||||
|
||||
const ret = {
|
||||
on: (type, handler) => {
|
||||
listeners[type] = handler;
|
||||
return ret; // Return self
|
||||
}
|
||||
};
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
for (const m of [ 'get', 'post', 'put', 'patch', 'delete', 'head', 'options' ]) {
|
||||
request[m] = (url, callback) => request({ url, method: m }, callback);
|
||||
}
|
||||
request.del = request.delete; // Special case
|
||||
|
||||
module.exports = request;
|
|
@ -1,3 +0,0 @@
|
|||
rm -rf src/node_modules
|
||||
mkdir src/node_modules
|
||||
cp -rf poly/* src/node_modules
|
|
@ -1,7 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo "Packing asar..."
|
||||
./scripts/injectPolyfills.sh
|
||||
asar pack src app.asar # Package asar
|
||||
# asar list app.asar # List asar for debugging / testing
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const request = require('request');
|
||||
const { get } = require('https');
|
||||
const fs = require('original-fs'); // Use original-fs, not Electron's modified fs
|
||||
const { join } = require('path');
|
||||
|
||||
|
@ -7,21 +7,23 @@ const downloadPath = join(asarPath, '..', 'app.asar.download');
|
|||
|
||||
const asarUrl = `https://github.com/GooseMod/OpenAsar/releases/download/${oaVersion.split('-')[0]}/app.asar`;
|
||||
|
||||
// todo: have these https utils centralised?
|
||||
const redirs = url => new Promise(res => get(url, r => { // Minimal wrapper around https.get to follow redirects
|
||||
const loc = r.headers.location;
|
||||
if (loc) return redirs(loc).then(res);
|
||||
|
||||
res(r);
|
||||
}));
|
||||
|
||||
module.exports = async () => { // (Try) update asar
|
||||
log('AsarUpdate', 'Updating...');
|
||||
|
||||
if (!oaVersion.includes('-')) return;
|
||||
|
||||
await new Promise((res) => {
|
||||
const file = fs.createWriteStream(downloadPath);
|
||||
const file = fs.createWriteStream(downloadPath);
|
||||
(await redirs(asarUrl)).pipe(file);
|
||||
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
res();
|
||||
});
|
||||
|
||||
request.get(asarUrl).on('response', r => r.pipe(file));
|
||||
});
|
||||
await new Promise(res => file.on('finish', res));
|
||||
|
||||
if (fs.readFileSync(downloadPath, 'utf8').startsWith('<')) return log('AsarUpdate', 'Download error');
|
||||
|
||||
|
|
5
src/bootstrap.js
vendored
5
src/bootstrap.js
vendored
|
@ -1,6 +1,5 @@
|
|||
const { app, session } = require('electron');
|
||||
const { readFileSync } = require('fs');
|
||||
const get = require('request');
|
||||
const { join } = require('path');
|
||||
|
||||
if (!settings.get('enableHardwareAcceleration', true)) app.disableHardwareAcceleration();
|
||||
|
@ -41,7 +40,7 @@ const startCore = () => {
|
|||
const [ channel, hash ] = oaVersion.split('-'); // Split via -
|
||||
|
||||
bw.webContents.executeJavaScript(readFileSync(join(__dirname, 'mainWindow.js'), 'utf8')
|
||||
.replaceAll('<hash>', hash || 'custom')
|
||||
.replaceAll('<hash>', hash)
|
||||
.replaceAll('<notrack>', oaConfig.noTrack)
|
||||
.replace('<css>', (oaConfig.css ?? '').replaceAll('\\', '\\\\').replaceAll('`', '\\`')));
|
||||
|
||||
|
@ -92,7 +91,7 @@ const startUpdate = () => {
|
|||
inst.on('InconsistentInstallerState', fatal);
|
||||
inst.on('update-error', console.error);
|
||||
|
||||
require('./winFirst').do(inst);
|
||||
require('./winFirst').do();
|
||||
} else {
|
||||
moduleUpdater.init(Constants.UPDATE_ENDPOINT, buildInfo);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ exports.open = () => {
|
|||
ipcMain.on('cs', (e, c) => {
|
||||
config = c;
|
||||
settings.set('openasar', config);
|
||||
settings.save(); // Ensure saving
|
||||
settings.save();
|
||||
});
|
||||
|
||||
ipcMain.on('cg', e => {
|
||||
|
|
|
@ -3,7 +3,7 @@ const fs = require('fs');
|
|||
const Module = require('module');
|
||||
const { execFile } = require('child_process');
|
||||
const { app, autoUpdater } = require('electron');
|
||||
const request = require('request');
|
||||
const { get } = require('https');
|
||||
|
||||
const paths = require('../paths');
|
||||
|
||||
|
@ -32,6 +32,20 @@ const resetTracking = () => {
|
|||
installing = Object.assign({}, base);
|
||||
};
|
||||
|
||||
const req = url => new Promise(res => get(url, r => { // Minimal wrapper around https.get to include body
|
||||
let dat = '';
|
||||
r.on('data', b => dat += b.toString());
|
||||
|
||||
r.on('end', () => res([ r, dat ]));
|
||||
}));
|
||||
|
||||
const redirs = url => new Promise(res => get(url, r => { // Minimal wrapper around https.get to follow redirects
|
||||
const loc = r.headers.location;
|
||||
if (loc) return redirs(loc).then(res);
|
||||
|
||||
res(r);
|
||||
}));
|
||||
|
||||
exports.init = (endpoint, { releaseChannel, version }) => {
|
||||
skipHost = settings.get('SKIP_HOST_UPDATE');
|
||||
skipModule = settings.get('SKIP_MODULE_UPDATE');
|
||||
|
@ -61,13 +75,11 @@ exports.init = (endpoint, { releaseChannel, version }) => {
|
|||
setFeedURL(url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
|
||||
checkForUpdates() {
|
||||
request(this.url, (e, r, b) => {
|
||||
if (e) return this.emit('error');
|
||||
|
||||
req(this.url).then(([ r, b ]) => {
|
||||
if (r.statusCode === 204) return this.emit('update-not-available');
|
||||
|
||||
|
||||
this.emit('update-manually', b);
|
||||
});
|
||||
}
|
||||
|
@ -95,17 +107,11 @@ exports.init = (endpoint, { releaseChannel, version }) => {
|
|||
host.setFeedURL(`${endpoint}/updates/${releaseChannel}?platform=${platform}&version=${version}`);
|
||||
|
||||
baseUrl = `${endpoint}/modules/${releaseChannel}`;
|
||||
qs = {
|
||||
host_version: version,
|
||||
platform
|
||||
};
|
||||
qs = `?host_version=${version}&platform=${platform}`;
|
||||
};
|
||||
|
||||
const checkModules = async () => {
|
||||
remote = await new Promise((res) => request({
|
||||
url: baseUrl + '/versions.json',
|
||||
qs
|
||||
}, (e, r, b) => res(JSON.parse(b))));
|
||||
remote = JSON.parse((await req(baseUrl + '/versions.json' + qs))[1]);
|
||||
|
||||
for (const name in installed) {
|
||||
const inst = installed[name].installedVersion;
|
||||
|
@ -113,7 +119,7 @@ const checkModules = async () => {
|
|||
|
||||
if (inst !== rem) {
|
||||
log('Modules', 'Update:', name, inst, '->', rem);
|
||||
|
||||
|
||||
downloadModule(name, rem);
|
||||
}
|
||||
}
|
||||
|
@ -129,26 +135,21 @@ const downloadModule = async (name, ver) => {
|
|||
|
||||
// log('Modules', 'Downloading', `${name}@${ver}`);
|
||||
|
||||
let success, total, cur = 0;
|
||||
request({
|
||||
url: baseUrl + '/' + name + '/' + ver,
|
||||
qs
|
||||
}).on('response', (res) => {
|
||||
success = res.statusCode === 200;
|
||||
total = parseInt(res.headers['content-length'] ?? 1, 10);
|
||||
let success, total, cur = 0;
|
||||
const res = await redirs(baseUrl + '/' + name + '/' + ver + qs);
|
||||
success = res.statusCode === 200;
|
||||
total = parseInt(res.headers['content-length'] ?? 1, 10);
|
||||
|
||||
res.pipe(file);
|
||||
res.pipe(file);
|
||||
|
||||
res.on('data', c => {
|
||||
cur += c.length;
|
||||
res.on('data', c => {
|
||||
cur += c.length;
|
||||
|
||||
events.emit('downloading-module', { name, cur, total });
|
||||
});
|
||||
events.emit('downloading-module', { name, cur, total });
|
||||
});
|
||||
|
||||
await new Promise((res) => file.on('close', res));
|
||||
|
||||
|
||||
if (success) commitManifest();
|
||||
else downloading.fail++;
|
||||
|
||||
|
@ -156,7 +157,6 @@ const downloadModule = async (name, ver) => {
|
|||
name
|
||||
});
|
||||
|
||||
|
||||
downloading.done++;
|
||||
|
||||
if (downloading.done === downloading.total) {
|
||||
|
@ -211,10 +211,10 @@ const installModule = async (name, ver, path) => {
|
|||
|
||||
proc.on('close', () => {
|
||||
if (err) return;
|
||||
|
||||
|
||||
installed[name] = { installedVersion: ver };
|
||||
commitManifest();
|
||||
|
||||
|
||||
finishInstall(name, ver, true);
|
||||
});
|
||||
};
|
||||
|
@ -236,7 +236,7 @@ const finishInstall = (name, ver, success) => {
|
|||
events.emit('installed', {
|
||||
failed: installing.fail
|
||||
});
|
||||
|
||||
|
||||
resetTracking();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
const fs = require('fs');
|
||||
const { join, resolve, basename } = require('path');
|
||||
const { join, resolve } = require('path');
|
||||
|
||||
const Constants = require('./Constants');
|
||||
const reg = (a, c) => require('child_process').execFile('reg.exe', a, c);
|
||||
|
||||
const exec = process.execPath;
|
||||
const app = resolve(exec, '..');
|
||||
const root = resolve(app, '..');
|
||||
|
||||
|
||||
exports.do = (updater) => {
|
||||
exports.do = () => {
|
||||
const flag = join(app, '.first-run');
|
||||
if (fs.existsSync(flag)) return; // Already done, skip
|
||||
|
||||
|
@ -23,31 +22,8 @@ exports.do = (updater) => {
|
|||
[base + '\\shell\\open\\command', '/ve', '/d', `"${exec}" --url -- "%1"`]
|
||||
]) reg([ 'add', ...x, '/f' ], e => {});
|
||||
|
||||
try { // Make shortcuts
|
||||
const file = Constants.APP_NAME_FOR_HUMANS + '.lnk';
|
||||
const icon_path = join(root, 'app.ico');
|
||||
|
||||
fs.copyFileSync(join(app, 'app.ico'), icon_path); // app-1.0.0/app.ico -> app.ico
|
||||
|
||||
for (const shortcut_path of [
|
||||
join(updater.getKnownFolder('desktop'), file),
|
||||
join(updater.getKnownFolder('programs'), Constants.APP_COMPANY, file)
|
||||
]) {
|
||||
if (!fs.existsSync(shortcut_path)) continue; // Don't update already deleted paths
|
||||
|
||||
updater.createShortcut({
|
||||
target_path: join(root, 'Update.exe'),
|
||||
shortcut_path,
|
||||
arguments: '--processStart ' + basename(exec),
|
||||
icon_path,
|
||||
icon_index: 0,
|
||||
description: Constants.APP_DESCRIPTION,
|
||||
app_user_model_id: Constants.APP_ID,
|
||||
working_directory: app
|
||||
});
|
||||
}
|
||||
|
||||
fs.writeFileSync(flag, 'true');
|
||||
try {
|
||||
fs.writeFileSync(flag, '');
|
||||
} catch (e) {
|
||||
log('FirstRun', e);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue