Skip to content

Commit 9840e82

Browse files
committed
feat(NODE-5455): use builtin native crypto
1 parent 52da925 commit 9840e82

File tree

1 file changed

+71
-18
lines changed

1 file changed

+71
-18
lines changed

.github/scripts/libmongocrypt.mjs

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ async function parseArguments() {
2323
libVersion: { short: 'l', type: 'string', default: pkg['mongodb:libmongocrypt'] },
2424
clean: { short: 'c', type: 'boolean', default: false },
2525
build: { short: 'b', type: 'boolean', default: false },
26+
crypto: { type: 'boolean', default: false }, // Use Node.js builtin crypto
27+
fastDownload: { type: 'boolean', default: false }, // Potentially incorrect download, only for the brave and impatient
2628
help: { short: 'h', type: 'boolean', default: false }
2729
};
2830

@@ -39,7 +41,12 @@ async function parseArguments() {
3941
}
4042

4143
return {
42-
libmongocrypt: { url: args.values.gitURL, ref: args.values.libVersion },
44+
libmongocrypt: {
45+
url: args.values.gitURL,
46+
ref: args.values.libVersion,
47+
crypto: args.values.crypto
48+
},
49+
fastDownload: args.values.fastDownload,
4350
clean: args.values.clean,
4451
build: args.values.build,
4552
pkg
@@ -77,7 +84,7 @@ export async function cloneLibMongoCrypt(libmongocryptRoot, { url, ref }) {
7784
}
7885
}
7986

80-
export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
87+
export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot, options) {
8188
console.error('building libmongocrypt...');
8289

8390
const nodeBuildRoot = resolveRoot(nodeDepsRoot, 'tmp', 'libmongocrypt-build');
@@ -88,7 +95,6 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
8895
const CMAKE_FLAGS = toFlags({
8996
/**
9097
* We provide crypto hooks from Node.js binding to openssl (so disable system crypto)
91-
* TODO: NODE-5455
9298
*
9399
* One thing that is not obvious from the build instructions for libmongocrypt
94100
* and the Node.js bindings is that the Node.js driver uses libmongocrypt in
@@ -101,7 +107,7 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
101107
* have a copy of OpenSSL available directly, but for now it seems to make sense
102108
* to stick with what the Node.js addon does here.
103109
*/
104-
DDISABLE_NATIVE_CRYPTO: '1',
110+
DDISABLE_NATIVE_CRYPTO: options.crypto ? '0' : '1',
105111
/** A consistent name for the output "library" directory */
106112
DCMAKE_INSTALL_LIBDIR: 'lib',
107113
/** No warnings allowed */
@@ -128,15 +134,26 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
128134

129135
await run(
130136
'cmake',
131-
[...CMAKE_FLAGS, ...WINDOWS_CMAKE_FLAGS, ...MACOS_CMAKE_FLAGS, libmongocryptRoot],
137+
[
138+
'--parallel',
139+
'4',
140+
...CMAKE_FLAGS,
141+
...WINDOWS_CMAKE_FLAGS,
142+
...MACOS_CMAKE_FLAGS,
143+
libmongocryptRoot
144+
],
132145
{ cwd: nodeBuildRoot }
133146
);
134-
await run('cmake', ['--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'], {
135-
cwd: nodeBuildRoot
136-
});
147+
await run(
148+
'cmake',
149+
['--parallel', '4', '--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'],
150+
{
151+
cwd: nodeBuildRoot
152+
}
153+
);
137154
}
138155

139-
export async function downloadLibMongoCrypt(nodeDepsRoot, { ref }) {
156+
export async function downloadLibMongoCrypt(nodeDepsRoot, { ref, crypto }, fastDownload) {
140157
const downloadURL =
141158
ref === 'latest'
142159
? 'https://mciuploads.s3.amazonaws.com/libmongocrypt/all/master/latest/libmongocrypt-all.tar.gz'
@@ -164,28 +181,62 @@ export async function downloadLibMongoCrypt(nodeDepsRoot, { ref }) {
164181

165182
console.error(`Platform: ${detectedPlatform} Prebuild: ${prebuild}`);
166183

167-
const unzipArgs = ['-xzv', '-C', `_libmongocrypt-${ref}`, `${prebuild}/nocrypto`];
184+
const downloadDestination = crypto ? `${prebuild}` : `${prebuild}/nocrypto`;
185+
const unzipArgs = ['-xzv', '-C', `_libmongocrypt-${ref}`, downloadDestination];
168186
console.error(`+ tar ${unzipArgs.join(' ')}`);
169187
const unzip = child_process.spawn('tar', unzipArgs, {
170-
stdio: ['pipe', 'inherit'],
188+
stdio: ['pipe', 'inherit', 'pipe'],
171189
cwd: resolveRoot('.')
172190
});
173191

174192
const [response] = await events.once(https.get(downloadURL), 'response');
175193

176194
const start = performance.now();
177-
await stream.pipeline(response, unzip.stdin);
195+
196+
let signal;
197+
if (fastDownload) {
198+
/**
199+
* Tar will print out each file it finds inside MEMBER (ex. macos/nocrypto)
200+
* For each file it prints, we give it a deadline of 10seconds to print the next one.
201+
* If nothing prints after 10 seconds we exit early.
202+
* This depends on the tar file being in order and un-tar-able in under 10sec.
203+
*
204+
* download time went from 230s to 80s
205+
*/
206+
const controller = new AbortController();
207+
signal = controller.signal;
208+
let isFirstStdoutDataEv = true;
209+
let timeout;
210+
unzip.stderr.on('data', chunk => {
211+
process.stderr.write(chunk, () => {
212+
if (isFirstStdoutDataEv) {
213+
isFirstStdoutDataEv = false;
214+
timeout = setTimeout(() => controller.abort(), 10_000);
215+
}
216+
timeout?.refresh();
217+
});
218+
});
219+
}
220+
221+
try {
222+
await stream.pipeline(response, unzip.stdin, { signal });
223+
} catch {
224+
await fs.access(path.join(`_libmongocrypt-${ref}`, downloadDestination));
225+
}
178226
const end = performance.now();
179227

180228
console.error(`downloaded libmongocrypt in ${(end - start) / 1000} secs...`);
181229

182230
await fs.rm(nodeDepsRoot, { recursive: true, force: true });
183-
await fs.cp(resolveRoot(destination, prebuild, 'nocrypto'), nodeDepsRoot, { recursive: true });
184-
const currentPath = path.join(nodeDepsRoot, 'lib64');
231+
const source = crypto
232+
? resolveRoot(destination, prebuild)
233+
: resolveRoot(destination, prebuild, 'nocrypto');
234+
await fs.cp(source, nodeDepsRoot, { recursive: true });
235+
const potentialLib64Path = path.join(nodeDepsRoot, 'lib64');
185236
try {
186-
await fs.rename(currentPath, path.join(nodeDepsRoot, 'lib'));
237+
await fs.rename(potentialLib64Path, path.join(nodeDepsRoot, 'lib'));
187238
} catch (error) {
188-
console.error(`error renaming ${currentPath}: ${error.message}`);
239+
await fs.access(path.join(nodeDepsRoot, 'lib')); // Ensure there is a "lib" directory
189240
}
190241
}
191242

@@ -214,11 +265,13 @@ async function main() {
214265
const isBuilt = libmongocryptBuiltVersion.trim() === libmongocrypt.ref;
215266

216267
if (clean || !isBuilt) {
217-
await buildLibMongoCrypt(libmongocryptCloneDir, nodeDepsDir);
268+
await buildLibMongoCrypt(libmongocryptCloneDir, nodeDepsDir, {
269+
crypto: libmongocrypt.crypto
270+
});
218271
}
219272
} else {
220273
// Download
221-
await downloadLibMongoCrypt(nodeDepsDir, libmongocrypt);
274+
await downloadLibMongoCrypt(nodeDepsDir, libmongocrypt, fastDownload);
222275
}
223276

224277
await fs.rm(resolveRoot('build'), { force: true, recursive: true });

0 commit comments

Comments
 (0)