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

Don't overwrite extracted native module #5

Merged
merged 1 commit into from
Apr 12, 2019
Merged
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
18 changes: 10 additions & 8 deletions node.patch
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index 885546c5d6..f1287bb191 100644
index 885546c5d6..f21e7993f1 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -215,11 +215,16 @@
// are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide
// which mode we run in.
// which mode we run in.
+
+ if (NativeModule.exists('_third_party_main')) {
+ NativeModule.require('_third_party_main');
Expand All @@ -21,7 +21,7 @@ index 885546c5d6..f1287bb191 100644
// one to drop a file lib/_third_party_main.js into the build
// directory which will be executed instead of Node's normal loading.
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index fb3770b729..eb65385afe 100644
index fb3770b729..f4bad8d6de 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -44,6 +44,9 @@ const { getOptionValue } = require('internal/options');
Expand Down Expand Up @@ -101,17 +101,19 @@ index fb3770b729..eb65385afe 100644
try {
module.exports = JSON.parse(stripBOM(content));
} catch (err) {
@@ -715,7 +742,14 @@ Module._extensions['.json'] = function(module, filename) {
@@ -715,7 +742,16 @@ Module._extensions['.json'] = function(module, filename) {

// Native extension for .node
Module._extensions['.node'] = function(module, filename) {
- return process.dlopen(module, path.toNamespacedPath(filename));
+ let isInternal = false;
+ if (nbin.existsSync(filename)) {
+ const tmpFile = path.join(os.tmpdir(), `.nbin-${path.basename(filename)}`);
+ fs.writeFileSync(tmpFile, nbin.readFileSync(filename));
+ filename = tmpFile;
+ isInternal = true;
+ const tmpFile = path.join(os.tmpdir(), `.nbin${nbin.id}-${path.basename(filename)}`);
+ if (!fs.existsSync(tmpFile)) {
+ fs.writeFileSync(tmpFile, nbin.readFileSync(filename));
+ }
+ filename = tmpFile;
+ isInternal = true;
+ }
+ return process.dlopen(module, isInternal ? filename : path.toNamespacedPath(filename));
};
Expand Down
21 changes: 14 additions & 7 deletions src/api/bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import { WritableFilesystem } from "../common/filesystem";
import { createFooter } from "../common/footer";
import ora, { Ora } from "ora";

declare const __non_webpack_require__: typeof require;

export class Binary implements nbin.Binary {
private readonly fs: WritableFilesystem = new WritableFilesystem();

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

// Create a buffer containing a (most likely) unique ID and its length.
const idLength = 6;
const possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const id = Array(idLength).fill(1)
.map(() => possible[Math.floor(Math.random() * possible.length)])
.join("");
const idBuffer = Buffer.alloc(2 + Buffer.byteLength(id));
writeString(idBuffer, id);

// Writing the entrypoint
const mainFileBuffer = Buffer.alloc(2 + Buffer.byteLength(this.options.mainFile));
writeString(mainFileBuffer, this.options.mainFile);
Expand All @@ -99,19 +106,19 @@ export class Binary implements nbin.Binary {

// Footer
const footerBuffer = createFooter(
fsBuffer.header.byteLength + mainFileBuffer.byteLength, // Header byte length
fsBuffer.header.byteLength + idBuffer.byteLength + mainFileBuffer.byteLength, // Header byte length
nodeBuffer.byteLength, // Header byte offset
fsBuffer.fileContents.byteLength, // File contents length
nodeBuffer.byteLength + fsBuffer.header.byteLength + mainFileBuffer.byteLength, // File contents offset
);
nodeBuffer.byteLength + fsBuffer.header.byteLength + idBuffer.byteLength + mainFileBuffer.byteLength, // File contents offset
);

return Buffer.concat([nodeBuffer, mainFileBuffer, fsBuffer.header, fsBuffer.fileContents, footerBuffer]);
return Buffer.concat([nodeBuffer, idBuffer, mainFileBuffer, fsBuffer.header, fsBuffer.fileContents, footerBuffer]);
}

private async cacheBinary(): Promise<Buffer> {
let nodeBinaryPath = this.options.nodePath || path.join(__dirname, "../../lib/node/out/Release/node");
const nodeBinaryName = this.nodeBinaryName;

const cacheDir = path.join(os.homedir(), ".nbin");
if (!fs.existsSync(nodeBinaryPath)) {
if (!fs.existsSync(cacheDir)) {
Expand Down
15 changes: 10 additions & 5 deletions src/patches/nbin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,23 @@ const nbinFd = fs.openSync(execPath, "r");
// Footer is located at the end of the file
const footer = readFooter(nbinFd, execPathStat.size);

// Contains the mainFile and the filesystem
const mainFileFsBuffer = Buffer.allocUnsafe(footer.headerLength);
fs.readSync(nbinFd, mainFileFsBuffer, 0, footer.headerLength, footer.headerOffset);
// Contains the ID, mainFile and the filesystem
const headerBuffer = Buffer.allocUnsafe(footer.headerLength);
fs.readSync(nbinFd, headerBuffer, 0, footer.headerLength, footer.headerOffset);

// Reading the ID.
const id = readString(headerBuffer, 0);

// Reading the mainfile
const mainFile = readString(mainFileFsBuffer, 0);
const mainFile = readString(headerBuffer, id.offset);

/**
* Maximize read perf by storing before any overrides
*/
const originalRead = fs.read;
const originalReadSync = fs.readSync;

const fsBuffer = mainFileFsBuffer.slice(mainFile.offset);
const fsBuffer = headerBuffer.slice(mainFile.offset);
const readableFs = ReadableFilesystem.fromBuffer(fsBuffer, {
readContents: (offset: number, length: number): Promise<Buffer> => {
const buffer = Buffer.allocUnsafe(length);
Expand Down Expand Up @@ -81,6 +84,8 @@ const createNotFound = (): Error => {
};

const exported: typeof import("nbin") = {
id: id.value,

mainFile: mainFile.value,

existsSync: (pathName: string): boolean => {
Expand Down
7 changes: 6 additions & 1 deletion typings/nbin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ declare module 'nbin' {
function readFileSync(path: string, encoding?: "buffer", offset?: number, length?: number): Buffer;
function readFileSync(path: string, encoding?: "utf8", offset?: number, length?: number): Buffer;

/**
* Uniquely generated ID for the packaged binary.
*/
export const id: string;

/**
* Returns the entrypoint of the application.
*/
Expand Down Expand Up @@ -97,7 +102,7 @@ declare module '@coder/nbin' {
* Will bundle a module based on path and name.
* Allows you to do `writeModule("/test/bananas/node_modules/frog")` and
* embed the `frog` module within the binary.
*
*
* All modules by default will be placed in `/node_modules`
*/
public writeModule(modulePath: string): void;
Expand Down