You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
7.2 KiB
JavaScript
173 lines
7.2 KiB
JavaScript
11 months ago
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.getFAASEnv = exports.makeClientMetadata = exports.LimitedSizeDocument = void 0;
|
||
|
const os = require("os");
|
||
|
const process = require("process");
|
||
|
const bson_1 = require("../../bson");
|
||
|
const error_1 = require("../../error");
|
||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||
|
const NODE_DRIVER_VERSION = require('../../../package.json').version;
|
||
|
/** @internal */
|
||
|
class LimitedSizeDocument {
|
||
|
constructor(maxSize) {
|
||
|
this.maxSize = maxSize;
|
||
|
this.document = new Map();
|
||
|
/** BSON overhead: Int32 + Null byte */
|
||
|
this.documentSize = 5;
|
||
|
}
|
||
|
/** Only adds key/value if the bsonByteLength is less than MAX_SIZE */
|
||
|
ifItFitsItSits(key, value) {
|
||
|
// The BSON byteLength of the new element is the same as serializing it to its own document
|
||
|
// subtracting the document size int32 and the null terminator.
|
||
|
const newElementSize = bson_1.BSON.serialize(new Map().set(key, value)).byteLength - 5;
|
||
|
if (newElementSize + this.documentSize > this.maxSize) {
|
||
|
return false;
|
||
|
}
|
||
|
this.documentSize += newElementSize;
|
||
|
this.document.set(key, value);
|
||
|
return true;
|
||
|
}
|
||
|
toObject() {
|
||
|
return bson_1.BSON.deserialize(bson_1.BSON.serialize(this.document), {
|
||
|
promoteLongs: false,
|
||
|
promoteBuffers: false,
|
||
|
promoteValues: false,
|
||
|
useBigInt64: false
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
exports.LimitedSizeDocument = LimitedSizeDocument;
|
||
|
/**
|
||
|
* From the specs:
|
||
|
* Implementors SHOULD cumulatively update fields in the following order until the document is under the size limit:
|
||
|
* 1. Omit fields from `env` except `env.name`.
|
||
|
* 2. Omit fields from `os` except `os.type`.
|
||
|
* 3. Omit the `env` document entirely.
|
||
|
* 4. Truncate `platform`. -- special we do not truncate this field
|
||
|
*/
|
||
|
function makeClientMetadata(options) {
|
||
|
const metadataDocument = new LimitedSizeDocument(512);
|
||
|
const { appName = '' } = options;
|
||
|
// Add app name first, it must be sent
|
||
|
if (appName.length > 0) {
|
||
|
const name = Buffer.byteLength(appName, 'utf8') <= 128
|
||
|
? options.appName
|
||
|
: Buffer.from(appName, 'utf8').subarray(0, 128).toString('utf8');
|
||
|
metadataDocument.ifItFitsItSits('application', { name });
|
||
|
}
|
||
|
const { name = '', version = '', platform = '' } = options.driverInfo;
|
||
|
const driverInfo = {
|
||
|
name: name.length > 0 ? `nodejs|${name}` : 'nodejs',
|
||
|
version: version.length > 0 ? `${NODE_DRIVER_VERSION}|${version}` : NODE_DRIVER_VERSION
|
||
|
};
|
||
|
if (!metadataDocument.ifItFitsItSits('driver', driverInfo)) {
|
||
|
throw new error_1.MongoInvalidArgumentError('Unable to include driverInfo name and version, metadata cannot exceed 512 bytes');
|
||
|
}
|
||
|
let runtimeInfo = getRuntimeInfo();
|
||
|
if (platform.length > 0) {
|
||
|
runtimeInfo = `${runtimeInfo}|${platform}`;
|
||
|
}
|
||
|
if (!metadataDocument.ifItFitsItSits('platform', runtimeInfo)) {
|
||
|
throw new error_1.MongoInvalidArgumentError('Unable to include driverInfo platform, metadata cannot exceed 512 bytes');
|
||
|
}
|
||
|
// Note: order matters, os.type is last so it will be removed last if we're at maxSize
|
||
|
const osInfo = new Map()
|
||
|
.set('name', process.platform)
|
||
|
.set('architecture', process.arch)
|
||
|
.set('version', os.release())
|
||
|
.set('type', os.type());
|
||
|
if (!metadataDocument.ifItFitsItSits('os', osInfo)) {
|
||
|
for (const key of osInfo.keys()) {
|
||
|
osInfo.delete(key);
|
||
|
if (osInfo.size === 0)
|
||
|
break;
|
||
|
if (metadataDocument.ifItFitsItSits('os', osInfo))
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
const faasEnv = getFAASEnv();
|
||
|
if (faasEnv != null) {
|
||
|
if (!metadataDocument.ifItFitsItSits('env', faasEnv)) {
|
||
|
for (const key of faasEnv.keys()) {
|
||
|
faasEnv.delete(key);
|
||
|
if (faasEnv.size === 0)
|
||
|
break;
|
||
|
if (metadataDocument.ifItFitsItSits('env', faasEnv))
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return metadataDocument.toObject();
|
||
|
}
|
||
|
exports.makeClientMetadata = makeClientMetadata;
|
||
|
/**
|
||
|
* Collects FaaS metadata.
|
||
|
* - `name` MUST be the last key in the Map returned.
|
||
|
*/
|
||
|
function getFAASEnv() {
|
||
|
const { AWS_EXECUTION_ENV = '', AWS_LAMBDA_RUNTIME_API = '', FUNCTIONS_WORKER_RUNTIME = '', K_SERVICE = '', FUNCTION_NAME = '', VERCEL = '', AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '', AWS_REGION = '', FUNCTION_MEMORY_MB = '', FUNCTION_REGION = '', FUNCTION_TIMEOUT_SEC = '', VERCEL_REGION = '' } = process.env;
|
||
|
const isAWSFaaS = AWS_EXECUTION_ENV.startsWith('AWS_Lambda_') || AWS_LAMBDA_RUNTIME_API.length > 0;
|
||
|
const isAzureFaaS = FUNCTIONS_WORKER_RUNTIME.length > 0;
|
||
|
const isGCPFaaS = K_SERVICE.length > 0 || FUNCTION_NAME.length > 0;
|
||
|
const isVercelFaaS = VERCEL.length > 0;
|
||
|
// Note: order matters, name must always be the last key
|
||
|
const faasEnv = new Map();
|
||
|
// When isVercelFaaS is true so is isAWSFaaS; Vercel inherits the AWS env
|
||
|
if (isVercelFaaS && !(isAzureFaaS || isGCPFaaS)) {
|
||
|
if (VERCEL_REGION.length > 0) {
|
||
|
faasEnv.set('region', VERCEL_REGION);
|
||
|
}
|
||
|
faasEnv.set('name', 'vercel');
|
||
|
return faasEnv;
|
||
|
}
|
||
|
if (isAWSFaaS && !(isAzureFaaS || isGCPFaaS || isVercelFaaS)) {
|
||
|
if (AWS_REGION.length > 0) {
|
||
|
faasEnv.set('region', AWS_REGION);
|
||
|
}
|
||
|
if (AWS_LAMBDA_FUNCTION_MEMORY_SIZE.length > 0 &&
|
||
|
Number.isInteger(+AWS_LAMBDA_FUNCTION_MEMORY_SIZE)) {
|
||
|
faasEnv.set('memory_mb', new bson_1.Int32(AWS_LAMBDA_FUNCTION_MEMORY_SIZE));
|
||
|
}
|
||
|
faasEnv.set('name', 'aws.lambda');
|
||
|
return faasEnv;
|
||
|
}
|
||
|
if (isAzureFaaS && !(isGCPFaaS || isAWSFaaS || isVercelFaaS)) {
|
||
|
faasEnv.set('name', 'azure.func');
|
||
|
return faasEnv;
|
||
|
}
|
||
|
if (isGCPFaaS && !(isAzureFaaS || isAWSFaaS || isVercelFaaS)) {
|
||
|
if (FUNCTION_REGION.length > 0) {
|
||
|
faasEnv.set('region', FUNCTION_REGION);
|
||
|
}
|
||
|
if (FUNCTION_MEMORY_MB.length > 0 && Number.isInteger(+FUNCTION_MEMORY_MB)) {
|
||
|
faasEnv.set('memory_mb', new bson_1.Int32(FUNCTION_MEMORY_MB));
|
||
|
}
|
||
|
if (FUNCTION_TIMEOUT_SEC.length > 0 && Number.isInteger(+FUNCTION_TIMEOUT_SEC)) {
|
||
|
faasEnv.set('timeout_sec', new bson_1.Int32(FUNCTION_TIMEOUT_SEC));
|
||
|
}
|
||
|
faasEnv.set('name', 'gcp.func');
|
||
|
return faasEnv;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
exports.getFAASEnv = getFAASEnv;
|
||
|
/**
|
||
|
* @internal
|
||
|
* Get current JavaScript runtime platform
|
||
|
*
|
||
|
* NOTE: The version information fetching is intentionally written defensively
|
||
|
* to avoid having a released driver version that becomes incompatible
|
||
|
* with a future change to these global objects.
|
||
|
*/
|
||
|
function getRuntimeInfo() {
|
||
|
if ('Deno' in globalThis) {
|
||
|
const version = typeof Deno?.version?.deno === 'string' ? Deno?.version?.deno : '0.0.0-unknown';
|
||
|
return `Deno v${version}, ${os.endianness()}`;
|
||
|
}
|
||
|
if ('Bun' in globalThis) {
|
||
|
const version = typeof Bun?.version === 'string' ? Bun?.version : '0.0.0-unknown';
|
||
|
return `Bun v${version}, ${os.endianness()}`;
|
||
|
}
|
||
|
return `Node.js ${process.version}, ${os.endianness()}`;
|
||
|
}
|
||
|
//# sourceMappingURL=client_metadata.js.map
|