@@ -23,6 +23,8 @@ async function parseArguments() {
23
23
libVersion : { short : 'l' , type : 'string' , default : pkg [ 'mongodb:libmongocrypt' ] } ,
24
24
clean : { short : 'c' , type : 'boolean' , default : false } ,
25
25
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
26
28
help : { short : 'h' , type : 'boolean' , default : false }
27
29
} ;
28
30
@@ -39,7 +41,12 @@ async function parseArguments() {
39
41
}
40
42
41
43
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 ,
43
50
clean : args . values . clean ,
44
51
build : args . values . build
45
52
} ;
@@ -76,7 +83,7 @@ export async function cloneLibMongoCrypt(libmongocryptRoot, { url, ref }) {
76
83
}
77
84
}
78
85
79
- export async function buildLibMongoCrypt ( libmongocryptRoot , nodeDepsRoot ) {
86
+ export async function buildLibMongoCrypt ( libmongocryptRoot , nodeDepsRoot , options ) {
80
87
console . error ( 'building libmongocrypt...' ) ;
81
88
82
89
const nodeBuildRoot = resolveRoot ( nodeDepsRoot , 'tmp' , 'libmongocrypt-build' ) ;
@@ -87,7 +94,6 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
87
94
const CMAKE_FLAGS = toFlags ( {
88
95
/**
89
96
* We provide crypto hooks from Node.js binding to openssl (so disable system crypto)
90
- * TODO: NODE-5455
91
97
*
92
98
* One thing that is not obvious from the build instructions for libmongocrypt
93
99
* and the Node.js bindings is that the Node.js driver uses libmongocrypt in
@@ -100,7 +106,7 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
100
106
* have a copy of OpenSSL available directly, but for now it seems to make sense
101
107
* to stick with what the Node.js addon does here.
102
108
*/
103
- DDISABLE_NATIVE_CRYPTO : '1' ,
109
+ DDISABLE_NATIVE_CRYPTO : options . crypto ? '0' : '1' ,
104
110
/** A consistent name for the output "library" directory */
105
111
DCMAKE_INSTALL_LIBDIR : 'lib' ,
106
112
/** No warnings allowed */
@@ -127,15 +133,26 @@ export async function buildLibMongoCrypt(libmongocryptRoot, nodeDepsRoot) {
127
133
128
134
await run (
129
135
'cmake' ,
130
- [ ...CMAKE_FLAGS , ...WINDOWS_CMAKE_FLAGS , ...MACOS_CMAKE_FLAGS , libmongocryptRoot ] ,
136
+ [
137
+ '--parallel' ,
138
+ '4' ,
139
+ ...CMAKE_FLAGS ,
140
+ ...WINDOWS_CMAKE_FLAGS ,
141
+ ...MACOS_CMAKE_FLAGS ,
142
+ libmongocryptRoot
143
+ ] ,
131
144
{ cwd : nodeBuildRoot }
132
145
) ;
133
- await run ( 'cmake' , [ '--build' , '.' , '--target' , 'install' , '--config' , 'RelWithDebInfo' ] , {
134
- cwd : nodeBuildRoot
135
- } ) ;
146
+ await run (
147
+ 'cmake' ,
148
+ [ '--parallel' , '4' , '--build' , '.' , '--target' , 'install' , '--config' , 'RelWithDebInfo' ] ,
149
+ {
150
+ cwd : nodeBuildRoot
151
+ }
152
+ ) ;
136
153
}
137
154
138
- export async function downloadLibMongoCrypt ( nodeDepsRoot , { ref } ) {
155
+ export async function downloadLibMongoCrypt ( nodeDepsRoot , { ref, crypto } , fastDownload ) {
139
156
const downloadURL =
140
157
ref === 'latest'
141
158
? 'https://mciuploads.s3.amazonaws.com/libmongocrypt/all/master/latest/libmongocrypt-all.tar.gz'
@@ -163,33 +180,67 @@ export async function downloadLibMongoCrypt(nodeDepsRoot, { ref }) {
163
180
164
181
console . error ( `Platform: ${ detectedPlatform } Prebuild: ${ prebuild } ` ) ;
165
182
166
- const unzipArgs = [ '-xzv' , '-C' , `_libmongocrypt-${ ref } ` , `${ prebuild } /nocrypto` ] ;
183
+ const downloadDestination = crypto ? `${ prebuild } ` : `${ prebuild } /nocrypto` ;
184
+ const unzipArgs = [ '-xzv' , '-C' , `_libmongocrypt-${ ref } ` , downloadDestination ] ;
167
185
console . error ( `+ tar ${ unzipArgs . join ( ' ' ) } ` ) ;
168
186
const unzip = child_process . spawn ( 'tar' , unzipArgs , {
169
- stdio : [ 'pipe' , 'inherit' ] ,
187
+ stdio : [ 'pipe' , 'inherit' , 'pipe' ] ,
170
188
cwd : resolveRoot ( '.' )
171
189
} ) ;
172
190
173
191
const [ response ] = await events . once ( https . get ( downloadURL ) , 'response' ) ;
174
192
175
193
const start = performance . now ( ) ;
176
- await stream . pipeline ( response , unzip . stdin ) ;
194
+
195
+ let signal ;
196
+ if ( fastDownload ) {
197
+ /**
198
+ * Tar will print out each file it finds inside MEMBER (ex. macos/nocrypto)
199
+ * For each file it prints, we give it a deadline of 10seconds to print the next one.
200
+ * If nothing prints after 10 seconds we exit early.
201
+ * This depends on the tar file being in order and un-tar-able in under 10sec.
202
+ *
203
+ * download time went from 230s to 80s
204
+ */
205
+ const controller = new AbortController ( ) ;
206
+ signal = controller . signal ;
207
+ let isFirstStdoutDataEv = true ;
208
+ let timeout ;
209
+ unzip . stderr . on ( 'data' , chunk => {
210
+ process . stderr . write ( chunk , ( ) => {
211
+ if ( isFirstStdoutDataEv ) {
212
+ isFirstStdoutDataEv = false ;
213
+ timeout = setTimeout ( ( ) => controller . abort ( ) , 10_000 ) ;
214
+ }
215
+ timeout ?. refresh ( ) ;
216
+ } ) ;
217
+ } ) ;
218
+ }
219
+
220
+ try {
221
+ await stream . pipeline ( response , unzip . stdin , { signal } ) ;
222
+ } catch {
223
+ await fs . access ( path . join ( `_libmongocrypt-${ ref } ` , downloadDestination ) ) ;
224
+ }
177
225
const end = performance . now ( ) ;
178
226
179
227
console . error ( `downloaded libmongocrypt in ${ ( end - start ) / 1000 } secs...` ) ;
180
228
181
229
await fs . rm ( nodeDepsRoot , { recursive : true , force : true } ) ;
182
- await fs . cp ( resolveRoot ( destination , prebuild , 'nocrypto' ) , nodeDepsRoot , { recursive : true } ) ;
183
- const currentPath = path . join ( nodeDepsRoot , 'lib64' ) ;
230
+ const source = crypto
231
+ ? resolveRoot ( destination , prebuild )
232
+ : resolveRoot ( destination , prebuild , 'nocrypto' ) ;
233
+ await fs . cp ( source , nodeDepsRoot , { recursive : true } ) ;
234
+ const potentialLib64Path = path . join ( nodeDepsRoot , 'lib64' ) ;
184
235
try {
185
- await fs . rename ( currentPath , path . join ( nodeDepsRoot , 'lib' ) ) ;
236
+ await fs . rename ( potentialLib64Path , path . join ( nodeDepsRoot , 'lib' ) ) ;
186
237
} catch ( error ) {
187
- console . error ( `error renaming ${ currentPath } : ${ error . message } ` ) ;
238
+ await fs . access ( path . join ( nodeDepsRoot , 'lib' ) ) ; // Ensure there is a "lib" directory
188
239
}
189
240
}
190
241
191
242
async function main ( ) {
192
- const { libmongocrypt, build, clean } = await parseArguments ( ) ;
243
+ const { libmongocrypt, build, clean, fastDownload } = await parseArguments ( ) ;
193
244
194
245
const nodeDepsDir = resolveRoot ( 'deps' ) ;
195
246
@@ -213,11 +264,13 @@ async function main() {
213
264
const isBuilt = libmongocryptBuiltVersion . trim ( ) === libmongocrypt . ref ;
214
265
215
266
if ( clean || ! isBuilt ) {
216
- await buildLibMongoCrypt ( libmongocryptCloneDir , nodeDepsDir ) ;
267
+ await buildLibMongoCrypt ( libmongocryptCloneDir , nodeDepsDir , {
268
+ crypto : libmongocrypt . crypto
269
+ } ) ;
217
270
}
218
271
} else {
219
272
// Download
220
- await downloadLibMongoCrypt ( nodeDepsDir , libmongocrypt ) ;
273
+ await downloadLibMongoCrypt ( nodeDepsDir , libmongocrypt , fastDownload ) ;
221
274
}
222
275
223
276
await fs . rm ( resolveRoot ( 'build' ) , { force : true , recursive : true } ) ;
0 commit comments