diff --git a/.generator/src/generator/templates/configuration.j2 b/.generator/src/generator/templates/configuration.j2 index d831d8718f0..64f0885a1bc 100644 --- a/.generator/src/generator/templates/configuration.j2 +++ b/.generator/src/generator/templates/configuration.j2 @@ -1,4 +1,4 @@ -import { HttpLibrary, HttpConfiguration, RequestContext } from "./http/http"; +import { HttpLibrary, HttpConfiguration, RequestContext, ZstdCompressorCallback } from "./http/http"; import { IsomorphicFetchHttpLibrary as DefaultHttpLibrary } from "./http/isomorphic-fetch"; import { BaseServerConfiguration, server1, servers, operationServers } from "./servers"; import { configureAuthMethods, AuthMethods, AuthMethodsConfiguration } from "./auth"; @@ -47,6 +47,10 @@ export interface ConfigurationParameters { * Flag to enable requests tracing */ debug?: boolean + /** + * Callback method to compress string body with zstd + */ + zstdCompressorCallback?: ZstdCompressorCallback } /** @@ -101,6 +105,7 @@ export function createConfiguration(conf: ConfigurationParameters = {}): Configu httpConfig: conf.httpConfig || {}, debug: conf.debug }; + configuration.httpApi.zstdCompressorCallback = conf.zstdCompressorCallback configuration.httpApi.debug = configuration.debug; return configuration; } diff --git a/.generator/src/generator/templates/http/http.j2 b/.generator/src/generator/templates/http/http.j2 index b6c10c575ef..fea33b962f0 100644 --- a/.generator/src/generator/templates/http/http.j2 +++ b/.generator/src/generator/templates/http/http.j2 @@ -234,7 +234,10 @@ export class ResponseContext { } } +export type ZstdCompressorCallback = (body: string) => Buffer; + export interface HttpLibrary { debug?: boolean; + zstdCompressorCallback?: ZstdCompressorCallback; send(request: RequestContext): Promise; } diff --git a/.generator/src/generator/templates/http/isomorphic-fetch.j2 b/.generator/src/generator/templates/http/isomorphic-fetch.j2 index 955b3d9bac5..a9e2735477d 100644 --- a/.generator/src/generator/templates/http/isomorphic-fetch.j2 +++ b/.generator/src/generator/templates/http/isomorphic-fetch.j2 @@ -1,10 +1,11 @@ -import { HttpLibrary, RequestContext, ResponseContext } from "./http"; +import { HttpLibrary, RequestContext, ResponseContext, ZstdCompressorCallback } from "./http"; import fetch from "cross-fetch"; import pako from "pako"; import bufferFrom from "buffer-from"; export class IsomorphicFetchHttpLibrary implements HttpLibrary { public debug = false; + public zstdCompressorCallback: ZstdCompressorCallback | undefined; public send(request: RequestContext): Promise { if (this.debug) { @@ -24,6 +25,12 @@ export class IsomorphicFetchHttpLibrary implements HttpLibrary { body = bufferFrom(pako.gzip(body).buffer); } else if (headers["Content-Encoding"] == "deflate") { body = bufferFrom(pako.deflate(body).buffer); + } else if (headers["Content-Encoding"] == "zstd1") { + if (this.zstdCompressorCallback) { + body = this.zstdCompressorCallback(body); + } else { + throw new Error("zstdCompressorCallback method missing") + } } } diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index 739e05f7306..fabc613d5d1 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -39,3 +39,4 @@ typedoc,Apache-2.0,Copyright (c) 2015 Sebastian Lenz Copyright (c) 2016-2021 Typ typescript,Apache-2.0,Copyright (c) Microsoft Corporation. url-parse,MIT,Copyright (c) 2015 Unshift.io, Arnout Kazemier, the Contributors. loglevel,MIT,Copyright (c) 2013 Tim Perry +zstd.ts,BSD-2-Clause,Copyright (c) [2021] [Beeno Tung (Tung Cheung Leong)] diff --git a/README.md b/README.md index 2b0a59b66ff..f95a619d32b 100644 --- a/README.md +++ b/README.md @@ -161,9 +161,54 @@ async function main() { main(); ``` +### Zstd compression + +Zstd compression support requires users to supply their own zstd compressor callback function. +The callback should accept string arg and return compressed Buffer data. +Callback signature `(body: string) => Buffer`. +For example, using `zstd.ts` package: + +```typescript +import { compressSync } from 'zstd.ts' +import { client, v2 } from "@datadog/datadog-api-client"; + +async function main() { + const configurationOpts = { + zstdCompressorCallback: (body: string) => compressSync({input: Buffer.from(body, "utf8")}) + } + const configuration = client.createConfiguration(configurationOpts); + const apiInstance = new v2.MetricsApi(configuration); + const params: v2.MetricsApiSubmitMetricsRequest = { + body: { + series: [ + { + metric: "system.load.1", + type: 0, + points: [ + { + timestamp: Math.round(new Date().getTime() / 1000), + value: 0.7, + }, + ], + }, + ], + }, + contentEncoding: "zstd1", + }; + + apiInstance.submitMetrics(params).then((data: v2.IntakePayloadAccepted) => { + console.log( + "API called successfully. Returned data: " + JSON.stringify(data) + ); + }).catch((error: any) => console.error(error)); +} + +main(); +``` + ## Documentation -Documentation for API endpoints can be found in in [Github pages][github pages]. +Documentation for API endpoints can be found in [GitHub pages][github pages]. ## Contributing diff --git a/features/support/given.ts b/features/support/given.ts index c86d803a0b3..1e0cc4cbf1c 100644 --- a/features/support/given.ts +++ b/features/support/given.ts @@ -1,4 +1,5 @@ import { Given } from "@cucumber/cucumber"; +import { compressSync } from 'zstd.ts' import fs from "fs"; import path from "path"; @@ -43,7 +44,9 @@ for (const apiVersion of Versions) { appKeyAuth: process.env.DD_TEST_CLIENT_APP_KEY, }, httpConfig: { compress: false }, + zstdCompressorCallback: (body: string) => compressSync({input: Buffer.from(body, "utf8")}), }; + if (process.env.DD_TEST_SITE) { const server = datadogApiClient.client.servers[2]; const serverConf = server.getConfiguration(); diff --git a/package.json b/package.json index 6e8afff2b44..39a44a57809 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,8 @@ "ts-jest": "^27.0.4", "ts-node": "^9.1.1", "typedoc": "^0.22.11", - "typescript": "4.5.5" + "typescript": "4.5.5", + "zstd.ts": "^1.1.3" }, "engines": { "node": ">=12.0.0" diff --git a/packages/datadog-api-client-common/configuration.ts b/packages/datadog-api-client-common/configuration.ts index eb131466cb6..0ee12841c5d 100644 --- a/packages/datadog-api-client-common/configuration.ts +++ b/packages/datadog-api-client-common/configuration.ts @@ -1,4 +1,9 @@ -import { HttpLibrary, HttpConfiguration, RequestContext } from "./http/http"; +import { + HttpLibrary, + HttpConfiguration, + RequestContext, + ZstdCompressorCallback, +} from "./http/http"; import { IsomorphicFetchHttpLibrary as DefaultHttpLibrary } from "./http/isomorphic-fetch"; import { BaseServerConfiguration, @@ -55,6 +60,10 @@ export interface ConfigurationParameters { * Flag to enable requests tracing */ debug?: boolean; + /** + * Callback method to compress string body with zstd + */ + zstdCompressorCallback?: ZstdCompressorCallback; } /** @@ -129,6 +138,7 @@ export function createConfiguration( httpConfig: conf.httpConfig || {}, debug: conf.debug, }; + configuration.httpApi.zstdCompressorCallback = conf.zstdCompressorCallback; configuration.httpApi.debug = configuration.debug; return configuration; } diff --git a/packages/datadog-api-client-common/http/http.ts b/packages/datadog-api-client-common/http/http.ts index b6c10c575ef..fea33b962f0 100644 --- a/packages/datadog-api-client-common/http/http.ts +++ b/packages/datadog-api-client-common/http/http.ts @@ -234,7 +234,10 @@ export class ResponseContext { } } +export type ZstdCompressorCallback = (body: string) => Buffer; + export interface HttpLibrary { debug?: boolean; + zstdCompressorCallback?: ZstdCompressorCallback; send(request: RequestContext): Promise; } diff --git a/packages/datadog-api-client-common/http/isomorphic-fetch.ts b/packages/datadog-api-client-common/http/isomorphic-fetch.ts index 955b3d9bac5..1b29be8c66c 100644 --- a/packages/datadog-api-client-common/http/isomorphic-fetch.ts +++ b/packages/datadog-api-client-common/http/isomorphic-fetch.ts @@ -1,10 +1,16 @@ -import { HttpLibrary, RequestContext, ResponseContext } from "./http"; +import { + HttpLibrary, + RequestContext, + ResponseContext, + ZstdCompressorCallback, +} from "./http"; import fetch from "cross-fetch"; import pako from "pako"; import bufferFrom from "buffer-from"; export class IsomorphicFetchHttpLibrary implements HttpLibrary { public debug = false; + public zstdCompressorCallback: ZstdCompressorCallback | undefined; public send(request: RequestContext): Promise { if (this.debug) { @@ -24,6 +30,12 @@ export class IsomorphicFetchHttpLibrary implements HttpLibrary { body = bufferFrom(pako.gzip(body).buffer); } else if (headers["Content-Encoding"] == "deflate") { body = bufferFrom(pako.deflate(body).buffer); + } else if (headers["Content-Encoding"] == "zstd1") { + if (this.zstdCompressorCallback) { + body = this.zstdCompressorCallback(body); + } else { + throw new Error("zstdCompressorCallback method missing"); + } } } diff --git a/yarn.lock b/yarn.lock index 302dc6f02f1..86c0a5d2cbd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5302,3 +5302,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zstd.ts@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/zstd.ts/-/zstd.ts-1.1.3.tgz#3ddbc625ef499429aa69d423a0fb5892e5af99f5" + integrity sha512-1xlKTD4O/4H2MEQ/McteFAdujc4cHxNZYDRzjxtWfLAimYbPzV7mIa+ZzzJqpN830AuNklVDA6RgHwcop6IZKw==