Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: remove deprecated pkg and use nodejs SEA #776

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@ coverage/
# Test results
cypress/videos
cypress/screenshots

*.blob
*.exe
14 changes: 3 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@
"pkg": {
"assets": [
"dist/assets/**/*",
"dist/**/*.map",
"dist/geoip-country.dat",
"dist/geoip-country6.dat"
"dist/**/*.map"
],
"targets": [
"node18-linuxstatic-x64",
Expand Down Expand Up @@ -67,9 +65,6 @@
"lint-staged": "lint-staged",
"prepare": "husky"
},
"dependencies": {
"geoip-country": "^4.1.60"
},
"devDependencies": {
"@babel/core": "^7.22.5",
"@babel/eslint-parser": "^7.22.5",
Expand All @@ -93,6 +88,7 @@
"@lingui/format-json": "^4.11.3",
"@lingui/loader": "^4.11.3",
"@lingui/react": "^4.11.3",
"@maxmind/geoip2-node": "^5.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@seald-io/nedb": "^3.1.0",
"@types/bencode": "^2.0.1",
Expand All @@ -106,13 +102,12 @@
"@types/d3-shape": "^3.1.6",
"@types/express": "^4.17.17",
"@types/fs-extra": "^9.0.13",
"@types/geoip-country": "^4.0.0",
"@types/http-errors": "^1.8.2",
"@types/jest": "^28.1.8",
"@types/jsonwebtoken": "^9.0.2",
"@types/lodash": "^4.14.195",
"@types/morgan": "^1.9.4",
"@types/node": "^14.0.0",
"@types/node": "^22.2.0",
"@types/parse-torrent": "^5.8.4",
"@types/passport": "^1.0.12",
"@types/passport-jwt": "^3.0.9",
Expand Down Expand Up @@ -234,9 +229,6 @@
"last 2 iOS version",
"last 2 Safari version"
],
"bundleDependencies": [
"geoip-country"
],
"lint-staged": {
"*": "prettier --ignore-unknown -w"
},
Expand Down
350 changes: 158 additions & 192 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions scripts/build-binary.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* build single executable binary with Node.js SEA
*/

import * as fs from 'node:fs';
import * as path from 'node:path/posix';
import {execSync} from 'node:child_process';

async function main() {
const [major, minor, patch] = process.versions.node.split('.').map(Number);
if (major <= 22) {
console.error('need node22 to run this scripts');
return;
}

execSync('npm run build');
const data = JSON.parse(fs.readFileSync('sea-config.tmpl.json').toString());
const assets = {};
for await (const p of walk('./dist/assets')) {
assets[path.normalize(p)] = p;
}

fs.writeFileSync('sea-config.json', JSON.stringify({...data, assets}));

execSync('node --experimental-sea-config sea-config.json');
fs.copyFileSync(process.execPath, 'flood.exe');
execSync(
'npx postject flood.exe NODE_SEA_BLOB sea-prep.blob --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2',
);
}

async function* walk(dir) {
for await (const d of await fs.promises.opendir(dir)) {
const entry = path.join(dir, d.name);
if (d.isDirectory()) yield* walk(entry);
else if (d.isFile()) yield entry;
}
}

await main();
16 changes: 16 additions & 0 deletions scripts/update-mmdb.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as zlib from 'node:zlib';
import * as fs from 'node:fs';

const buf = fs.readFileSync('server/geoip/GeoLite2-Country.mmdb');

fs.writeFileSync(
'server/geoip/data.mjs',
`
import * as zlib from 'node:zlib';

// data is brotli compressed GeoLite2-Country.mmdb in base64 format
export const data = zlib.brotliDecompressSync(Buffer.from('${zlib
.brotliCompressSync(buf)
.toString('base64')}', 'base64'));
`,
);
4 changes: 4 additions & 0 deletions sea-config.tmpl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"main": "dist/index.js",
"output": "sea-prep.blob"
}
11 changes: 7 additions & 4 deletions server/bin/enforce-prerequisites.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'fs';
import path from 'path';
import * as sea from 'node:sea';

import {appDist} from '../../shared/config/paths';
import config from '../../config';
Expand All @@ -26,10 +27,12 @@ const enforcePrerequisites = () =>
return;
}

// Ensure static assets exist if they need to be served
if (!doFilesExist(staticAssets) && config.serveAssets !== false) {
reject(new Error(`Static assets are missing.`));
return;
if (!sea.isSea()) {
// Ensure static assets exist if they need to be served
if (!doFilesExist(staticAssets) && config.serveAssets !== false) {
reject(new Error(`Static assets are missing.`));
return;
}
}

resolve();
Expand Down
1 change: 1 addition & 0 deletions server/geoip/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GeoLite2-Country.mmdb
1 change: 1 addition & 0 deletions server/geoip/data.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const data: string;
9 changes: 9 additions & 0 deletions server/geoip/data.mjs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions server/geoip/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
download `GeoLite2-Country.mmdb` from maxmind and put it here.

Then run `node ./scripts/update-mmdb.mjs` to update `data.mjs`
14 changes: 11 additions & 3 deletions server/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'fs';
import path from 'path';
import * as sea from 'node:sea';

import type {FastifyInstance} from 'fastify';

Expand Down Expand Up @@ -49,9 +50,16 @@ const constructRoutes = async (fastify: FastifyInstance) => {
// Disable ETag
app.set('etag', false);

// Static assets
// app.use(servedPath, express.static(paths.appDist));
fastify.register(fastifyStatic, {root: paths.appDist, prefix: servedPath});
if (sea.isSea()) {
fastify.get('/', (req, res) => {
console.log(req.routerPath);
res.send(sea.getAsset(req.routerPath));
});
} else {
// Static assets
// app.use(servedPath, express.static(paths.appDist));
fastify.register(fastifyStatic, {root: paths.appDist, prefix: servedPath});
}

// Client app routes, serve index.html and client js will figure it out
const html = fs.readFileSync(path.join(paths.appDist, 'index.html'), {
Expand Down
4 changes: 2 additions & 2 deletions server/services/Transmission/clientGatewayService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import geoip from 'geoip-country';
import path from 'path';

import type {
Expand Down Expand Up @@ -26,6 +25,7 @@ import type {TransferSummary} from '@shared/types/TransferData';
import type {TransmissionConnectionSettings} from '@shared/schema/ClientConnectionSettings';
import type {SetClientSettingsOptions} from '@shared/types/api/client';

import * as geoip from '../geoip';
import ClientGatewayService from '../clientGatewayService';
import ClientRequestManager from './clientRequestManager';
import {fetchUrls} from '../../util/fetchUtil';
Expand Down Expand Up @@ -195,7 +195,7 @@ class TransmissionClientGatewayService extends ClientGatewayService {
.filter((peer) => peer.isDownloadingFrom || peer.isUploadingTo)
.map((peer) => ({
address: peer.address,
country: geoip.lookup(peer.address)?.country || '',
country: geoip.lookup(peer.address),
clientVersion: peer.clientName,
completedPercent: peer.progress * 100,
downloadRate: peer.rateToClient,
Expand Down
13 changes: 13 additions & 0 deletions server/services/geoip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {Reader} from '@maxmind/geoip2-node';

import * as data from '../geoip/data.mjs';

const r = Reader.openBuffer(data.data);

export function lookup(s: string): string {
try {
return r.country(s)?.country?.isoCode ?? '';
} catch {
return '';
}
}
4 changes: 2 additions & 2 deletions server/services/rTorrent/clientGatewayService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import fs from 'fs';
import geoip from 'geoip-country';
import {move} from 'fs-extra';
import path from 'path';
import sanitize from 'sanitize-filename';
Expand Down Expand Up @@ -31,6 +30,7 @@ import type {TorrentTracker} from '@shared/types/TorrentTracker';
import type {TransferSummary} from '@shared/types/TransferData';
import type {SetClientSettingsOptions} from '@shared/types/api/client';

import * as geoip from '../geoip';
import {isAllowedPath, sanitizePath} from '../../util/fileUtil';
import ClientGatewayService from '../clientGatewayService';
import ClientRequestManager from './clientRequestManager';
Expand Down Expand Up @@ -262,7 +262,7 @@ class RTorrentClientGatewayService extends ClientGatewayService {
processedResponses.map(async (processedResponse) => {
return {
...processedResponse,
country: geoip.lookup(processedResponse.address)?.country || '',
country: geoip.lookup(processedResponse.address),
};
}),
);
Expand Down
Loading