CoolFace
Apppublic

opusdev/vector-similarity-api

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes
mongocryptd_manager.ts101 linesDownload Raw Back to client-side-encryption
1import type { ChildProcess } from 'child_process';2 3import { MongoNetworkTimeoutError } from '../error';4import { type AutoEncryptionExtraOptions } from './auto_encrypter';5 6/**7 * @internal8 * An internal class that handles spawning a mongocryptd.9 */10export class MongocryptdManager {11  static DEFAULT_MONGOCRYPTD_URI = 'mongodb://localhost:27020';12 13  uri: string;14  bypassSpawn: boolean;15  spawnPath = '';16  spawnArgs: Array<string> = [];17  _child?: ChildProcess;18 19  constructor(extraOptions: AutoEncryptionExtraOptions = {}) {20    this.uri =21      typeof extraOptions.mongocryptdURI === 'string' && extraOptions.mongocryptdURI.length > 022        ? extraOptions.mongocryptdURI23        : MongocryptdManager.DEFAULT_MONGOCRYPTD_URI;24 25    this.bypassSpawn = !!extraOptions.mongocryptdBypassSpawn;26 27    if (Object.hasOwn(extraOptions, 'mongocryptdSpawnPath') && extraOptions.mongocryptdSpawnPath) {28      this.spawnPath = extraOptions.mongocryptdSpawnPath;29    }30    if (31      Object.hasOwn(extraOptions, 'mongocryptdSpawnArgs') &&32      Array.isArray(extraOptions.mongocryptdSpawnArgs)33    ) {34      this.spawnArgs = this.spawnArgs.concat(extraOptions.mongocryptdSpawnArgs);35    }36    if (37      this.spawnArgs38        .filter(arg => typeof arg === 'string')39        .every(arg => arg.indexOf('--idleShutdownTimeoutSecs') < 0)40    ) {41      this.spawnArgs.push('--idleShutdownTimeoutSecs', '60');42    }43  }44 45  /**46   * Will check to see if a mongocryptd is up. If it is not up, it will attempt47   * to spawn a mongocryptd in a detached process, and then wait for it to be up.48   */49  async spawn(): Promise<void> {50    const cmdName = this.spawnPath || 'mongocryptd';51 52    // eslint-disable-next-line @typescript-eslint/no-require-imports53    const { spawn } = require('child_process') as typeof import('child_process');54 55    // Spawned with stdio: ignore and detached: true56    // to ensure child can outlive parent.57    this._child = spawn(cmdName, this.spawnArgs, {58      stdio: 'ignore',59      detached: true60    });61 62    this._child.on('error', () => {63      // From the FLE spec:64      // "The stdout and stderr of the spawned process MUST not be exposed in the driver65      // (e.g. redirect to /dev/null). Users can pass the argument --logpath to66      // extraOptions.mongocryptdSpawnArgs if they need to inspect mongocryptd logs.67      // If spawning is necessary, the driver MUST spawn mongocryptd whenever server68      // selection on the MongoClient to mongocryptd fails. If the MongoClient fails to69      // connect after spawning, the server selection error is propagated to the user."70      // The AutoEncrypter and MongoCryptdManager should work together to spawn71      // mongocryptd whenever necessary.  Additionally, the `mongocryptd` intentionally72      // shuts down after 60s and gets respawned when necessary.  We rely on server73      // selection timeouts when connecting to the `mongocryptd` to inform users that something74      // has been configured incorrectly.  For those reasons, we suppress stderr from75      // the `mongocryptd` process and immediately unref the process.76    });77 78    // unref child to remove handle from event loop79    this._child.unref();80  }81 82  /**83   * @returns the result of `fn` or rejects with an error.84   */85  async withRespawn<T>(fn: () => Promise<T>): ReturnType<typeof fn> {86    try {87      const result = await fn();88      return result;89    } catch (err) {90      // If we are not bypassing spawning, then we should retry once on a MongoTimeoutError (server selection error)91      const shouldSpawn = err instanceof MongoNetworkTimeoutError && !this.bypassSpawn;92      if (!shouldSpawn) {93        throw err;94      }95    }96    await this.spawn();97    const result = await fn();98    return result;99  }100}101