async getProjectStates(): Promise<Array<ProjectState>> { const projectStates = []; for (const connection of this._server.getConnections()) { // Just in case the connection is no longer valid, we wrap it with a // timeout less than Nuclide RPC's default of 60s. We swallow any // errors and return an empty ProjectState if this happens. projectStates.push( timeoutPromise( connection.getAtomCommands().getProjectState(), GET_PROJECT_STATES_TIMEOUT_MS, ).catch(error => ({ rootFolders: [], })), ); } const resolvedProjectStates = await Promise.all(projectStates); return [].concat(...resolvedProjectStates); }
async _closeServerConnection(shutdown: boolean): Promise<void> { try { // If the Nuclide server has already been shutdown or has crashed, // the closeConnection() call will attempt to disconnect from the Nuclide // server forever. This sets a 5 second timeout for it so that the rest // of this function and anything calling it can complete. await timeoutPromise( this._getInfoService().closeConnection(shutdown), 5000, ); } catch (e) { getLogger('nuclide-remote-connection').error( 'Failed to close Nuclide server connection.', ); } finally { if (shutdown) { // Clear the saved connection config so we don't try it again at startup. clearConnectionConfig(this._config.host); } } }
Array.from(relatedFilesProviders.values()).map(provider => timeoutPromise(provider.getRelatedFiles(path), 2000),
export async function startServer({ certificateStrategy, ports, timeout, expirationDays, exclusive, jsonOutputFile, absolutePathToServerMain, serverParams, }: StartServerParams): Promise<void> { const logger = getLogger(); logger.info('in startServer()'); let paths; let certificateGeneratorOutput = {}; switch (certificateStrategy.type) { case 'generate': const { clientCommonName, serverCommonName, openSSLConfigPath, } = certificateStrategy; paths = await generateCertificates( clientCommonName, serverCommonName, openSSLConfigPath, expirationDays, ); logger.info('generateCertificates() succeeded!'); certificateGeneratorOutput = { hostname: serverCommonName, cert: await fs.readFileAsString(paths.clientCert), key: await fs.readFileAsString(paths.clientKey), }; break; case 'reuse': paths = certificateStrategy.paths; logger.info('reusing existing certificates'); break; default: (certificateStrategy.type: empty); throw Error('invalid certificate strategy'); } const [key, cert, ca] = await Promise.all([ fs.readFileAsBuffer(paths.serverKey), fs.readFileAsBuffer(paths.serverCert), fs.readFileAsBuffer(paths.caCert), ]); const params: LauncherScriptParams = { key: key.toString(), cert: cert.toString(), ca: ca.toString(), ports, expirationDays, exclusive, absolutePathToServerMain, serverParams, }; // Redirect child stderr to a file so that we can read it. // (If we just pipe it, there's no safe way of disconnecting it after.) temp.track(); const stderrLog = temp.openSync('big-dig-stderr'); const launcherScript = require.resolve('./launchServer-entry.js'); logger.info(`About to spawn ${launcherScript} to launch Big Dig server.`); const child = child_process.spawn( process.execPath, [ // Increase stack trace limit for better debug logs. // For reference, Atom/Electron does not have a stack trace limit. '--stack-trace-limit=50', // Increase the maximum heap size if we have enough memory. ...(os.totalmem() > 8 * 1024 * 1024 * 1024 ? ['--max-old-space-size=4096'] : []), launcherScript, ], { detached: true, stdio: ['ignore', 'ignore', stderrLog.fd, 'ipc'], }, ); logger.info(`spawn called for ${launcherScript}`); // Send launch parameters over IPC to avoid making them visible in `ps`. child.send(params); const childPort = await timeoutPromise( new Promise((resolve, reject) => { const onMessage = ({port: result}) => { resolve(result); child.removeAllListeners(); }; child.on('message', onMessage); child.on('error', reject); child.on('exit', async code => { const stderr = await fs .readFileAsString(stderrLog.path) .catch(() => ''); reject( Error(`Child exited early with code ${code}.\nstderr: ${stderr}`), ); }); }), timeout, ).catch(err => { // Make sure we clean up hung children. if (err instanceof TimedOutError) { child.kill('SIGKILL'); } return Promise.reject(err); }); const {version} = require('../../package.json'); const json = JSON.stringify( // These properties are the ones currently written by nuclide-server. { ...certificateGeneratorOutput, pid: child.pid, version, port: childPort, ca: ca.toString(), ca_path: paths.caCert, server_cert_path: paths.serverCert, server_key_path: paths.serverKey, protocol_version: 2, success: true, }, ); await fs.writeFile(jsonOutputFile, json, {mode: 0o600}); logger.info(`Server config written to ${jsonOutputFile}.`); child.unref(); }