Skip to content

Commit

Permalink
Merge pull request #67 from multiversx/TOOL-233-extend-user-agent-on-…
Browse files Browse the repository at this point in the history
…js-network-providers

Extend user agent to contain client name
  • Loading branch information
danielailie authored Aug 28, 2024
2 parents ff50ec9 + 9f9e675 commit 6626d45
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 14 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-network-providers",
"version": "2.6.0",
"version": "2.7.0",
"lockfileVersion": 2,
"requires": true,
"author": "MultiversX",
Expand Down
20 changes: 16 additions & 4 deletions src/apiNetworkProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosRequestConfig } from "axios";
import axios from "axios";
import { AccountOnNetwork, GuardianData } from "./accounts";
import { defaultAxiosConfig, defaultPagination } from "./config";
import { ContractQueryRequest } from "./contractQueryRequest";
Expand All @@ -16,17 +16,29 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor
import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens";
import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions";
import { TransactionStatus } from "./transactionStatus";
import { extendUserAgent } from "./userAgent";
import { NetworkProviderConfig } from "./networkProviderConfig";
import { BaseUserAgent } from "./constants";

// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider".
export class ApiNetworkProvider implements INetworkProvider {
private url: string;
private config: AxiosRequestConfig;
private config: NetworkProviderConfig;
private backingProxyNetworkProvider;
private userAgentPrefix = `${BaseUserAgent}/api`

constructor(url: string, config?: AxiosRequestConfig) {
constructor(url: string, config?: NetworkProviderConfig) {
this.url = url;
let proxyConfig = this.getProxyConfig(config);
this.config = { ...defaultAxiosConfig, ...config };
this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config);
this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, proxyConfig);
extendUserAgent(this.userAgentPrefix, this.config);
}

private getProxyConfig(config: NetworkProviderConfig | undefined) {
let proxyConfig = JSON.parse(JSON.stringify(config));
proxyConfig = { ...defaultAxiosConfig, ...proxyConfig };
return proxyConfig;
}

async getNetworkConfig(): Promise<NetworkConfig> {
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ import { Address } from "./primitives";

export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615");
export const EsdtContractAddress = new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u");
export const BaseUserAgent = "multiversx-sdk"
export const UnknownClientName = "unknown"
5 changes: 5 additions & 0 deletions src/networkProviderConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AxiosRequestConfig } from 'axios';

export interface NetworkProviderConfig extends AxiosRequestConfig {
clientName?: string;
}
40 changes: 37 additions & 3 deletions src/providers.dev.net.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assert } from "chai";
import { assert, expect } from "chai";
import { ApiNetworkProvider } from "./apiNetworkProvider";
import { INetworkProvider, ITransactionNext } from "./interface";
import { Address } from "./primitives";
Expand All @@ -7,15 +7,16 @@ import { MockQuery } from "./testscommon/dummyQuery";
import { NonFungibleTokenOfAccountOnNetwork } from "./tokens";
import { TransactionEventData } from "./transactionEvents";
import { TransactionOnNetwork } from "./transactions";
import { AxiosHeaders } from "axios";

describe("test network providers on devnet: Proxy and API", function () {
let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th");
let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8");
let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7");
const MAX_NUMBER_OF_ITEMS_BY_DEFAULT = 20;

let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 });
let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000 });
let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, clientName: 'test' });
let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, clientName: 'test' });

it("should have same response for getNetworkConfig()", async function () {
let apiResponse = await apiProvider.getNetworkConfig();
Expand All @@ -24,6 +25,39 @@ describe("test network providers on devnet: Proxy and API", function () {
assert.deepEqual(apiResponse, proxyResponse);
});

it("should add userAgent unknown for clientName when no clientName passed", async function () {
const expectedApiUserAgent = "multiversx-sdk/api/unknown"
const expectedProxyUserAgent = "multiversx-sdk/proxy/unknown"

let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 });
let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000 });

assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent);
assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent);
});

it("should set userAgent with specified clientName ", async function () {
const expectedApiUserAgent = "multiversx-sdk/api/test"
const expectedProxyUserAgent = "multiversx-sdk/proxy/test"

let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, clientName: 'test' });
let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, clientName: 'test' });

assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent);
assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent);
});

it("should keep the set userAgent and add the sdk to it", async function () {
const expectedApiUserAgent = "Client-info multiversx-sdk/api/test"
const expectedProxyUserAgent = "Client-info multiversx-sdk/proxy/test"

let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, headers: new AxiosHeaders({ "User-Agent": "Client-info" }), clientName: 'test' });
let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, headers: new AxiosHeaders({ "User-Agent": "Client-info" }), clientName: 'test' });

assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent);
assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent);
});

it("should have same response for getNetworkStatus()", async function () {
let apiResponse = await apiProvider.getNetworkStatus();
let proxyResponse = await proxyProvider.getNetworkStatus();
Expand Down
12 changes: 8 additions & 4 deletions src/proxyNetworkProvider.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios, { AxiosRequestConfig } from "axios";
import axios from "axios";
import { AccountOnNetwork, GuardianData } from "./accounts";
import { defaultAxiosConfig } from "./config";
import { EsdtContractAddress } from "./constants";
import { EsdtContractAddress, BaseUserAgent } from "./constants";
import { ContractQueryRequest } from "./contractQueryRequest";
import { ContractQueryResponse } from "./contractQueryResponse";
import { ErrContractQuery, ErrNetworkProvider } from "./errors";
Expand All @@ -14,15 +14,19 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor
import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens";
import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions";
import { TransactionStatus } from "./transactionStatus";
import { extendUserAgent } from "./userAgent";
import { NetworkProviderConfig } from "./networkProviderConfig";

// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider".
export class ProxyNetworkProvider implements INetworkProvider {
private url: string;
private config: AxiosRequestConfig;
private config: NetworkProviderConfig;
private userAgentPrefix = `${BaseUserAgent}/proxy`

constructor(url: string, config?: AxiosRequestConfig) {
constructor(url: string, config?: NetworkProviderConfig) {
this.url = url;
this.config = { ...defaultAxiosConfig, ...config };
extendUserAgent(this.userAgentPrefix, this.config);
}

async getNetworkConfig(): Promise<NetworkConfig> {
Expand Down
19 changes: 19 additions & 0 deletions src/userAgent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { AxiosHeaders } from "axios";
import { NetworkProviderConfig } from "./networkProviderConfig";
import { UnknownClientName } from "./constants";

export function extendUserAgent(userAgentPrefix: string, config: NetworkProviderConfig) {
if (!config.headers) {
config.headers = new AxiosHeaders({})
};
if (!config.clientName) {
console.log("Can you please provide the client name of the application that uses the SDK? It will be used for metrics.")
}
const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true);
const resolvedClientName = config.clientName || UnknownClientName;

const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : '';
const newUserAgent = currentUserAgent ? `${currentUserAgent} ${userAgentPrefix}/${resolvedClientName}` : `${userAgentPrefix}/${resolvedClientName}`;

headers.setUserAgent(newUserAgent, true);
}

0 comments on commit 6626d45

Please sign in to comment.