Skip to content
This repository was archived by the owner on May 23, 2021. It is now read-only.

Commit e21aa75

Browse files
code-asherkylecarbs
authored andcommitted
Don't overwrite extracted native module (#5)
1 parent 7b303f6 commit e21aa75

File tree

4 files changed

+40
-21
lines changed

4 files changed

+40
-21
lines changed

node.patch

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
2-
index 885546c5d6..f1287bb191 100644
2+
index 885546c5d6..f21e7993f1 100644
33
--- a/lib/internal/bootstrap/node.js
44
+++ b/lib/internal/bootstrap/node.js
55
@@ -215,11 +215,16 @@
66
// are running from a script and running the REPL - but there are a few
77
// others like the debugger or running --eval arguments. Here we decide
8-
// which mode we run in.
8+
// which mode we run in.
99
+
1010
+ if (NativeModule.exists('_third_party_main')) {
1111
+ NativeModule.require('_third_party_main');
@@ -21,7 +21,7 @@ index 885546c5d6..f1287bb191 100644
2121
// one to drop a file lib/_third_party_main.js into the build
2222
// directory which will be executed instead of Node's normal loading.
2323
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
24-
index fb3770b729..eb65385afe 100644
24+
index fb3770b729..f4bad8d6de 100644
2525
--- a/lib/internal/modules/cjs/loader.js
2626
+++ b/lib/internal/modules/cjs/loader.js
2727
@@ -44,6 +44,9 @@ const { getOptionValue } = require('internal/options');
@@ -101,17 +101,19 @@ index fb3770b729..eb65385afe 100644
101101
try {
102102
module.exports = JSON.parse(stripBOM(content));
103103
} catch (err) {
104-
@@ -715,7 +742,14 @@ Module._extensions['.json'] = function(module, filename) {
104+
@@ -715,7 +742,16 @@ Module._extensions['.json'] = function(module, filename) {
105105

106106
// Native extension for .node
107107
Module._extensions['.node'] = function(module, filename) {
108108
- return process.dlopen(module, path.toNamespacedPath(filename));
109109
+ let isInternal = false;
110110
+ if (nbin.existsSync(filename)) {
111-
+ const tmpFile = path.join(os.tmpdir(), `.nbin-${path.basename(filename)}`);
112-
+ fs.writeFileSync(tmpFile, nbin.readFileSync(filename));
113-
+ filename = tmpFile;
114-
+ isInternal = true;
111+
+ const tmpFile = path.join(os.tmpdir(), `.nbin${nbin.id}-${path.basename(filename)}`);
112+
+ if (!fs.existsSync(tmpFile)) {
113+
+ fs.writeFileSync(tmpFile, nbin.readFileSync(filename));
114+
+ }
115+
+ filename = tmpFile;
116+
+ isInternal = true;
115117
+ }
116118
+ return process.dlopen(module, isInternal ? filename : path.toNamespacedPath(filename));
117119
};

src/api/bundler.ts

+14-7
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import { WritableFilesystem } from "../common/filesystem";
1111
import { createFooter } from "../common/footer";
1212
import ora, { Ora } from "ora";
1313

14-
declare const __non_webpack_require__: typeof require;
15-
1614
export class Binary implements nbin.Binary {
1715
private readonly fs: WritableFilesystem = new WritableFilesystem();
1816

@@ -87,6 +85,15 @@ export class Binary implements nbin.Binary {
8785
public async build(): Promise<Buffer> {
8886
const nodeBuffer = await this.cacheBinary();
8987

88+
// Create a buffer containing a (most likely) unique ID and its length.
89+
const idLength = 6;
90+
const possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
91+
const id = Array(idLength).fill(1)
92+
.map(() => possible[Math.floor(Math.random() * possible.length)])
93+
.join("");
94+
const idBuffer = Buffer.alloc(2 + Buffer.byteLength(id));
95+
writeString(idBuffer, id);
96+
9097
// Writing the entrypoint
9198
const mainFileBuffer = Buffer.alloc(2 + Buffer.byteLength(this.options.mainFile));
9299
writeString(mainFileBuffer, this.options.mainFile);
@@ -99,19 +106,19 @@ export class Binary implements nbin.Binary {
99106

100107
// Footer
101108
const footerBuffer = createFooter(
102-
fsBuffer.header.byteLength + mainFileBuffer.byteLength, // Header byte length
109+
fsBuffer.header.byteLength + idBuffer.byteLength + mainFileBuffer.byteLength, // Header byte length
103110
nodeBuffer.byteLength, // Header byte offset
104111
fsBuffer.fileContents.byteLength, // File contents length
105-
nodeBuffer.byteLength + fsBuffer.header.byteLength + mainFileBuffer.byteLength, // File contents offset
106-
);
112+
nodeBuffer.byteLength + fsBuffer.header.byteLength + idBuffer.byteLength + mainFileBuffer.byteLength, // File contents offset
113+
);
107114

108-
return Buffer.concat([nodeBuffer, mainFileBuffer, fsBuffer.header, fsBuffer.fileContents, footerBuffer]);
115+
return Buffer.concat([nodeBuffer, idBuffer, mainFileBuffer, fsBuffer.header, fsBuffer.fileContents, footerBuffer]);
109116
}
110117

111118
private async cacheBinary(): Promise<Buffer> {
112119
let nodeBinaryPath = this.options.nodePath || path.join(__dirname, "../../lib/node/out/Release/node");
113120
const nodeBinaryName = this.nodeBinaryName;
114-
121+
115122
const cacheDir = path.join(os.homedir(), ".nbin");
116123
if (!fs.existsSync(nodeBinaryPath)) {
117124
if (!fs.existsSync(cacheDir)) {

src/patches/nbin.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,23 @@ const nbinFd = fs.openSync(execPath, "r");
1313
// Footer is located at the end of the file
1414
const footer = readFooter(nbinFd, execPathStat.size);
1515

16-
// Contains the mainFile and the filesystem
17-
const mainFileFsBuffer = Buffer.allocUnsafe(footer.headerLength);
18-
fs.readSync(nbinFd, mainFileFsBuffer, 0, footer.headerLength, footer.headerOffset);
16+
// Contains the ID, mainFile and the filesystem
17+
const headerBuffer = Buffer.allocUnsafe(footer.headerLength);
18+
fs.readSync(nbinFd, headerBuffer, 0, footer.headerLength, footer.headerOffset);
19+
20+
// Reading the ID.
21+
const id = readString(headerBuffer, 0);
1922

2023
// Reading the mainfile
21-
const mainFile = readString(mainFileFsBuffer, 0);
24+
const mainFile = readString(headerBuffer, id.offset);
2225

2326
/**
2427
* Maximize read perf by storing before any overrides
2528
*/
2629
const originalRead = fs.read;
2730
const originalReadSync = fs.readSync;
2831

29-
const fsBuffer = mainFileFsBuffer.slice(mainFile.offset);
32+
const fsBuffer = headerBuffer.slice(mainFile.offset);
3033
const readableFs = ReadableFilesystem.fromBuffer(fsBuffer, {
3134
readContents: (offset: number, length: number): Promise<Buffer> => {
3235
const buffer = Buffer.allocUnsafe(length);
@@ -81,6 +84,8 @@ const createNotFound = (): Error => {
8184
};
8285

8386
const exported: typeof import("nbin") = {
87+
id: id.value,
88+
8489
mainFile: mainFile.value,
8590

8691
existsSync: (pathName: string): boolean => {

typings/nbin.d.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ declare module 'nbin' {
3939
function readFileSync(path: string, encoding?: "buffer", offset?: number, length?: number): Buffer;
4040
function readFileSync(path: string, encoding?: "utf8", offset?: number, length?: number): Buffer;
4141

42+
/**
43+
* Uniquely generated ID for the packaged binary.
44+
*/
45+
export const id: string;
46+
4247
/**
4348
* Returns the entrypoint of the application.
4449
*/
@@ -97,7 +102,7 @@ declare module '@coder/nbin' {
97102
* Will bundle a module based on path and name.
98103
* Allows you to do `writeModule("/test/bananas/node_modules/frog")` and
99104
* embed the `frog` module within the binary.
100-
*
105+
*
101106
* All modules by default will be placed in `/node_modules`
102107
*/
103108
public writeModule(modulePath: string): void;

0 commit comments

Comments
 (0)