Skip to content

Commit 54379fa

Browse files
committed
Ensure the server is always up-to-date before packaging
1 parent b72c53a commit 54379fa

File tree

6 files changed

+137
-47
lines changed

6 files changed

+137
-47
lines changed

package-lock.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
"postinstall": "electron-builder install-app-deps",
1111
"build": "npm run build:src && npm run build:electron",
1212
"build:src": "tsc",
13-
"build:electron": "electron-builder build",
14-
"build:dir-only": "electron-builder --dir",
15-
"start": "node setup-local.js && npm run start:app",
16-
"start:dev": "node setup-dev.js && cross-env APP_URL='http://local.httptoolkit.tech:8080' npm run start:app",
13+
"build:electron": "ts-node ./setup-server.ts && electron-builder build",
14+
"build:dir-only": "ts-node ./setup-server.ts && electron-builder --dir",
15+
"start": "ts-node ./setup-server.ts && npm run start:app",
16+
"start:dev": "ts-node ./skip-server.ts && cross-env APP_URL='http://local.httptoolkit.tech:8080' npm run start:app",
1717
"start:app": "tsc-watch --onSuccess 'electron .'"
1818
},
1919
"keywords": [],
@@ -87,6 +87,7 @@
8787
"@types/node-fetch": "^2.1.4",
8888
"@types/rimraf": "^3.0.0",
8989
"@types/semver": "^7.3.4",
90+
"@types/targz": "^1.0.0",
9091
"@types/universal-analytics": "^0.4.3",
9192
"@types/uuid": "^3.4.6",
9293
"@types/yargs": "^15.0.3",

setup-local.js

Lines changed: 0 additions & 34 deletions
This file was deleted.

setup-server.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
require('ts-node/register');
2+
3+
import * as path from 'path';
4+
import * as os from 'os';
5+
import * as fs from 'fs';
6+
import { promisify } from 'util';
7+
8+
import * as _ from 'lodash';
9+
import * as semver from 'semver';
10+
import fetch from 'node-fetch';
11+
import * as rimraf from 'rimraf';
12+
import * as targz from 'targz';
13+
14+
const extractTarGz = promisify(targz.decompress);
15+
const deleteFile = promisify(fs.unlink);
16+
17+
const canAccess = (path: string) => promisify(fs.access)(path).then(() => true).catch(() => false);
18+
const deleteDir = promisify(rimraf);
19+
20+
const packageJson = require('./package.json');
21+
const requiredServerVersion = 'v' + packageJson.config['httptoolkit-server-version'];
22+
23+
// For local testing of the desktop app, we need to pull the latest server and unpack it.
24+
// This real prod server will then be used with the real prod web UI, but this local desktop app.
25+
async function setUpLocalEnv() {
26+
const serverExists = await canAccess('./httptoolkit-server/package.json');
27+
const serverVersion = serverExists ? require('./httptoolkit-server/package.json').version : null;
28+
29+
if (!serverVersion || semver.neq(serverVersion, requiredServerVersion)) {
30+
if (serverExists) await deleteDir('./httptoolkit-server');
31+
await insertServer(__dirname, os.platform(), os.arch());
32+
console.log('Server setup completed.');
33+
} else {
34+
console.log('Correct server already downloaded.');
35+
}
36+
}
37+
38+
/*
39+
* Download the correct server binary and include it in the build directly.
40+
* We use the binary build rather than our actual npm dev dependency
41+
* because the binary builds are capable of autoupdating all by themselves,
42+
* and because it makes it possible for users to run the server directly
43+
* with minimal effort, if they so choose.
44+
*/
45+
async function insertServer(
46+
buildPath: string,
47+
platform: string,
48+
arch: string,
49+
) {
50+
console.log(`Downloading httptoolkit-server ${requiredServerVersion} for ${platform}-${arch}`);
51+
52+
const assetRegex = new RegExp(`httptoolkit-server-${requiredServerVersion}-${platform}-${arch}.tar.gz`);
53+
54+
const headers: { Authorization: string } | {} = process.env.GITHUB_TOKEN
55+
? { Authorization: `token ${process.env.GITHUB_TOKEN}` }
56+
: {}
57+
58+
const response = await fetch(
59+
'https://api.github.com/repos/httptoolkit/httptoolkit-server/releases',
60+
{ headers }
61+
);
62+
63+
const releases = await response.json();
64+
65+
const release = _.find(releases, { tag_name: requiredServerVersion });
66+
67+
if (!release || !release.assets) {
68+
console.error(JSON.stringify(release, null, 2));
69+
throw new Error('Could not retrieve release assets');
70+
}
71+
72+
const asset = release.assets.filter((asset: { name: string }) => asset.name.match(assetRegex))[0];
73+
if (!asset) {
74+
throw new Error(`No server available matching ${assetRegex.toString()}`);
75+
}
76+
77+
console.log(`Downloading server from ${asset.browser_download_url}...`);
78+
79+
const downloadPath = path.join(buildPath, 'httptoolkit-server.tar.gz');
80+
81+
const assetDownload = await fetch(asset.browser_download_url);
82+
const assetWrite = assetDownload.body.pipe(fs.createWriteStream(downloadPath));
83+
84+
await new Promise((resolve, reject) => {
85+
assetWrite.on('finish', resolve);
86+
assetWrite.on('error', reject);
87+
});
88+
89+
console.log(`Extracting server to ${buildPath}`);
90+
await extractTarGz({ src: downloadPath, dest: buildPath });
91+
await deleteFile(downloadPath);
92+
93+
console.log('Server download completed');
94+
}
95+
96+
setUpLocalEnv().catch(e => {
97+
console.error(e);
98+
process.exit(1);
99+
});

setup-dev.js renamed to skip-server.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
require('ts-node/register');
1+
import { promisify } from 'util';
2+
import * as path from 'path';
3+
import * as fs from 'fs';
4+
import * as rimraf from 'rimraf';
25

3-
const { promisify } = require('util');
4-
const path = require('path');
5-
const fs = require('fs');
6-
const rimraf = require('rimraf');
7-
8-
const canAccess = (file) => promisify(fs.access)(file).then(() => true).catch(() => false);
6+
const canAccess = (file: string) => promisify(fs.access)(file).then(() => true).catch(() => false);
97
const deleteDir = promisify(rimraf);
108
const mkdir = promisify(fs.mkdir);
119
const writeFile = promisify(fs.writeFile);

src/hooks/after-copy.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)