@chainlink/external-adapter-framework 0.0.67 → 0.0.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapter.d.ts +156 -0
- package/adapter.js +200 -0
- package/adapter.js.map +1 -0
- package/cache/redis.d.ts +8 -1
- package/cache/redis.js +39 -22
- package/cache/redis.js.map +1 -1
- package/config/index.d.ts +1 -1
- package/examples/bank-frick/config/index.d.ts +1 -1
- package/examples/coingecko/batch-warming.d.ts +7 -0
- package/examples/coingecko/batch-warming.js +54 -0
- package/examples/coingecko/batch-warming.js.map +1 -0
- package/examples/coingecko/index.d.ts +2 -0
- package/examples/coingecko/index.js +12 -0
- package/examples/coingecko/index.js.map +1 -0
- package/examples/coingecko/rest.d.ts +12 -0
- package/examples/coingecko/rest.js +55 -0
- package/examples/coingecko/rest.js.map +1 -0
- package/examples/coingecko/src/crypto-utils.d.ts +3 -3
- package/examples/coingecko/src/crypto-utils.js.map +1 -1
- package/examples/coingecko/src/cryptoUtils.d.ts +31 -0
- package/examples/coingecko/src/cryptoUtils.js +60 -0
- package/examples/coingecko/src/endpoint/coins.js.map +1 -1
- package/examples/coingecko/src/endpoint/crypto-marketcap.js.map +1 -1
- package/examples/coingecko/src/endpoint/crypto-volume.js.map +1 -1
- package/examples/coingecko/src/endpoint/crypto.js.map +1 -1
- package/examples/coingecko/src/endpoint/dominance.js.map +1 -1
- package/examples/coingecko/src/endpoint/global-marketcap.js.map +1 -1
- package/examples/coingecko/src/global-utils.d.ts +3 -3
- package/examples/coingecko/src/global-utils.js.map +1 -1
- package/examples/coingecko/src/globalUtils.d.ts +27 -0
- package/examples/coingecko/src/globalUtils.js +46 -0
- package/examples/coingecko/src/index.d.ts +1 -1
- package/examples/cryptocompare/src/index.d.ts +1 -1
- package/examples/genesis/sseStream.js.map +1 -1
- package/index.d.ts +1 -2
- package/index.js.map +1 -1
- package/package.json +2 -2
- package/rate-limiting/index.d.ts +2 -2
- package/transports/metrics.d.ts +1 -1
- package/transports/rest.d.ts +0 -1
- package/transports/rest.js.map +1 -1
- package/validation/preset-tokens.json +23 -0
- package/validation/validator.d.ts +47 -0
- package/validation/validator.js +303 -0
package/adapter.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
import type EventSource from 'eventsource';
|
|
3
|
+
import { Cache } from './cache';
|
|
4
|
+
import { AdapterConfig, BaseAdapterConfig, CustomSettingsType, SettingsMap } from './config';
|
|
5
|
+
import { AdapterRateLimitTier, BackgroundExecuteRateLimiter, RequestRateLimiter } from './rate-limiting';
|
|
6
|
+
import { Transport } from './transports';
|
|
7
|
+
import { SubscriptionSetFactory } from './util';
|
|
8
|
+
import { InputParameters } from './validation/input-params';
|
|
9
|
+
import { InputValidator } from './validation/input-validator';
|
|
10
|
+
/**
|
|
11
|
+
* Dependencies that will be injected into the Adapter on startup
|
|
12
|
+
*/
|
|
13
|
+
export interface AdapterDependencies {
|
|
14
|
+
/** Specific instance of the Cache the adapter will use (e.g. Local, Redis, etc.) */
|
|
15
|
+
cache: Cache;
|
|
16
|
+
/** Shared instance of the request rate limiter */
|
|
17
|
+
requestRateLimiter: RequestRateLimiter;
|
|
18
|
+
/** Shared instance of the background execute rate limiter */
|
|
19
|
+
backgroundExecuteRateLimiter: BackgroundExecuteRateLimiter;
|
|
20
|
+
/** Factory to create subscription sets based on the specified cache type */
|
|
21
|
+
subscriptionSetFactory: SubscriptionSetFactory;
|
|
22
|
+
/** Redis client used for cache and subscription set */
|
|
23
|
+
redisClient: Redis;
|
|
24
|
+
/** EventSource to use for listening to server sent events. A mock EventSource can be provided as a dependency for testing */
|
|
25
|
+
eventSource: typeof EventSource;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Context that will be used on background executions of a Transport.
|
|
29
|
+
* For example, the endpointName used to log statements or generate Cache keys.
|
|
30
|
+
*/
|
|
31
|
+
export interface AdapterContext<CustomSettings extends CustomSettingsType<CustomSettings> = SettingsMap> {
|
|
32
|
+
/** Endpoint instance within the adapter that the Transport is related to */
|
|
33
|
+
adapterEndpoint: AdapterEndpoint<unknown, unknown, CustomSettings>;
|
|
34
|
+
/** Initialized config for the adapter that the Transport can access */
|
|
35
|
+
adapterConfig: AdapterConfig<CustomSettings>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Structure to describe rate limits specs for the Adapter
|
|
39
|
+
*/
|
|
40
|
+
interface AdapterRateLimitingConfig {
|
|
41
|
+
/** Adapter rate limits, gotten from the specific tier requested */
|
|
42
|
+
tiers: Record<string, AdapterRateLimitTier>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Main structure of an External Adapter
|
|
46
|
+
*/
|
|
47
|
+
export interface AdapterParams<CustomSettings extends SettingsMap> {
|
|
48
|
+
/** Name of the adapter */
|
|
49
|
+
name: string;
|
|
50
|
+
/** If present, the string that will be used for requests with no specified endpoint */
|
|
51
|
+
defaultEndpoint?: string;
|
|
52
|
+
/**
|
|
53
|
+
* List of [[AdapterEndpoint]]s in the adapter. This is purposefully typed any; it's the correct type in this case.
|
|
54
|
+
*
|
|
55
|
+
* When you try to create an adapter and you provide an endpoint, if these generics were set to "unknown" instead
|
|
56
|
+
* what would happen is that Typescript would check if the types match, and would fail to assign unknown to the
|
|
57
|
+
* specific Params or Result in the transport itself.
|
|
58
|
+
* We also can't use generics, because if we had more than one transport with different requests (very likely)
|
|
59
|
+
* then those new types wouldn't match with each other.
|
|
60
|
+
*/
|
|
61
|
+
endpoints: AdapterEndpoint<any, any, CustomSettings>[];
|
|
62
|
+
/** Map of overrides to the default config values for an Adapter */
|
|
63
|
+
envDefaultOverrides?: Partial<BaseAdapterConfig>;
|
|
64
|
+
/** List of custom env vars for this particular adapter (e.g. RPC_URL) */
|
|
65
|
+
customSettings?: SettingsMap;
|
|
66
|
+
/** Configuration relevant to outbound (EA --\> DP) communication rate limiting */
|
|
67
|
+
rateLimiting?: AdapterRateLimitingConfig;
|
|
68
|
+
/** Overrides for converting the 'base' parameter that are hardcoded into the adapter. */
|
|
69
|
+
overrides?: Record<string, string>;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Structure to describe rate limits specs for a specific adapter endpoint
|
|
73
|
+
*/
|
|
74
|
+
export interface EndpointRateLimitingConfig {
|
|
75
|
+
/**
|
|
76
|
+
* How much of the total limit for the adapter will be assigned to this specific endpoint.
|
|
77
|
+
* Should be a non-zero positive number up to 100.
|
|
78
|
+
* Endpoints in the same adapter without a specific allocation will divide the remaining limits equally.
|
|
79
|
+
*/
|
|
80
|
+
allocationPercentage: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Structure to describe a specific endpoint in an [[Adapter]]
|
|
84
|
+
*/
|
|
85
|
+
export interface AdapterEndpointParams<Params, Result, CustomSettings extends SettingsMap> {
|
|
86
|
+
/** Name that will be used to match input params to this endpoint (case insensitive) */
|
|
87
|
+
name: string;
|
|
88
|
+
/** List of alternative endpoint names that will resolve to this same transport (case insensitive) */
|
|
89
|
+
aliases?: string[];
|
|
90
|
+
/** Transport that will be used to handle data processing and communication for this endpoint */
|
|
91
|
+
transport: Transport<Params, Result, CustomSettings>;
|
|
92
|
+
/** Specification of what the body of a request hitting this endpoint should look like (used for validation) */
|
|
93
|
+
inputParameters: InputParameters;
|
|
94
|
+
/** Specific details related to the rate limiting for this endpoint in particular */
|
|
95
|
+
rateLimiting?: EndpointRateLimitingConfig;
|
|
96
|
+
}
|
|
97
|
+
export declare class AdapterEndpoint<Params, Result, CustomSettings extends SettingsMap> implements AdapterEndpointParams<Params, Result, CustomSettings> {
|
|
98
|
+
name: string;
|
|
99
|
+
aliases?: string[] | undefined;
|
|
100
|
+
transport: Transport<Params, Result, CustomSettings>;
|
|
101
|
+
inputParameters: InputParameters;
|
|
102
|
+
rateLimiting?: EndpointRateLimitingConfig | undefined;
|
|
103
|
+
validator: InputValidator;
|
|
104
|
+
constructor(params: AdapterEndpointParams<Params, Result, CustomSettings>);
|
|
105
|
+
}
|
|
106
|
+
declare type CustomAdapterSettings = SettingsMap & NegatedAdapterSettings;
|
|
107
|
+
declare type NegatedAdapterSettings = {
|
|
108
|
+
[K in keyof BaseAdapterConfig]?: never;
|
|
109
|
+
};
|
|
110
|
+
export declare class Adapter<CustomSettings extends CustomAdapterSettings = SettingsMap> implements AdapterParams<CustomSettings> {
|
|
111
|
+
name: string;
|
|
112
|
+
defaultEndpoint?: string | undefined;
|
|
113
|
+
endpoints: AdapterEndpoint<unknown, unknown, CustomSettings>[];
|
|
114
|
+
envDefaultOverrides?: Partial<BaseAdapterConfig> | undefined;
|
|
115
|
+
customSettings?: SettingsMap | undefined;
|
|
116
|
+
rateLimiting?: AdapterRateLimitingConfig | undefined;
|
|
117
|
+
overrides?: Record<string, string> | undefined;
|
|
118
|
+
initialized: boolean;
|
|
119
|
+
/** Object containing alias translations for all endpoints */
|
|
120
|
+
endpointsMap: Record<string, AdapterEndpoint<unknown, unknown, CustomSettings>>;
|
|
121
|
+
/** Initialized dependencies that the adapter will use */
|
|
122
|
+
dependencies: AdapterDependencies;
|
|
123
|
+
/** Configuration params for various adapter properties */
|
|
124
|
+
config: AdapterConfig;
|
|
125
|
+
constructor(params: AdapterParams<CustomSettings>);
|
|
126
|
+
/**
|
|
127
|
+
* Initializes all of the [[Transport]]s in the adapter, passing along any [[AdapterDependencies]] and [[AdapterConfig]].
|
|
128
|
+
* Additionally, it builds a map out of all the endpoint names and aliases (checking for duplicates).
|
|
129
|
+
*/
|
|
130
|
+
initialize(dependencies?: Partial<AdapterDependencies>): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Takes an adapter and normalizes all endpoint names and aliases, as well as the default endpoint.
|
|
133
|
+
* i.e. makes them lowercase for now
|
|
134
|
+
*/
|
|
135
|
+
private normalizeEndpointNames;
|
|
136
|
+
/**
|
|
137
|
+
* This function will take an adapter structure and go through each endpoint, calculating
|
|
138
|
+
* each one's allocation of the total rate limits that are set for the adapter as a whole.
|
|
139
|
+
*
|
|
140
|
+
*/
|
|
141
|
+
private calculateRateLimitAllocations;
|
|
142
|
+
/**
|
|
143
|
+
* Creates a list of key/value pairs that need to be censored in the logs
|
|
144
|
+
* using the sensitive flag in the adapter config
|
|
145
|
+
*/
|
|
146
|
+
private buildCensorList;
|
|
147
|
+
/**
|
|
148
|
+
* This function will process dependencies for an adapter, such as caches or rate limiters,
|
|
149
|
+
* in order to inject them into transports and other relevant places later in the lifecycle.
|
|
150
|
+
*
|
|
151
|
+
* @param inputDependencies - a partial obj of initialized dependencies to override the created ones
|
|
152
|
+
* @returns a set of AdapterDependencies all initialized
|
|
153
|
+
*/
|
|
154
|
+
initializeDependencies(inputDependencies?: Partial<AdapterDependencies>): AdapterDependencies;
|
|
155
|
+
}
|
|
156
|
+
export {};
|
package/adapter.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.Adapter = exports.AdapterEndpoint = void 0;
|
|
30
|
+
const ioredis_1 = __importDefault(require("ioredis"));
|
|
31
|
+
const cache_1 = require("./cache");
|
|
32
|
+
const config_1 = require("./config");
|
|
33
|
+
const rate_limiting_1 = require("./rate-limiting");
|
|
34
|
+
const util_1 = require("./util");
|
|
35
|
+
const censor_list_1 = __importDefault(require("./util/censor/censor-list"));
|
|
36
|
+
const cacheMetrics = __importStar(require("./cache/metrics"));
|
|
37
|
+
const input_validator_1 = require("./validation/input-validator");
|
|
38
|
+
const client = __importStar(require("prom-client"));
|
|
39
|
+
const logger = (0, util_1.makeLogger)('Adapter');
|
|
40
|
+
/**
|
|
41
|
+
* `prom-client` is shared between v2 and v3 when both are dependencies, resulting in metric collision errors
|
|
42
|
+
* Clearing metrics on import will wipe v2's existing register so we can replace them with v3's metrics
|
|
43
|
+
**/
|
|
44
|
+
client.register.clear();
|
|
45
|
+
class AdapterEndpoint {
|
|
46
|
+
constructor(params) {
|
|
47
|
+
this.name = params.name;
|
|
48
|
+
this.aliases = params.aliases;
|
|
49
|
+
this.transport = params.transport;
|
|
50
|
+
this.inputParameters = params.inputParameters;
|
|
51
|
+
this.rateLimiting = params.rateLimiting;
|
|
52
|
+
this.validator = new input_validator_1.InputValidator(this.inputParameters);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.AdapterEndpoint = AdapterEndpoint;
|
|
56
|
+
class Adapter {
|
|
57
|
+
constructor(params) {
|
|
58
|
+
// After initialization
|
|
59
|
+
this.initialized = false;
|
|
60
|
+
/** Object containing alias translations for all endpoints */
|
|
61
|
+
this.endpointsMap = {};
|
|
62
|
+
// Copy over params
|
|
63
|
+
this.name = params.name;
|
|
64
|
+
this.defaultEndpoint = params.defaultEndpoint?.toLowerCase();
|
|
65
|
+
this.endpoints = params.endpoints;
|
|
66
|
+
this.envDefaultOverrides = params.envDefaultOverrides;
|
|
67
|
+
this.customSettings = params.customSettings;
|
|
68
|
+
this.rateLimiting = params.rateLimiting;
|
|
69
|
+
this.overrides = params.overrides;
|
|
70
|
+
this.config = (0, config_1.buildAdapterConfig)({
|
|
71
|
+
overrides: this.envDefaultOverrides,
|
|
72
|
+
customSettings: this.customSettings,
|
|
73
|
+
});
|
|
74
|
+
this.normalizeEndpointNames();
|
|
75
|
+
this.calculateRateLimitAllocations();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Initializes all of the [[Transport]]s in the adapter, passing along any [[AdapterDependencies]] and [[AdapterConfig]].
|
|
79
|
+
* Additionally, it builds a map out of all the endpoint names and aliases (checking for duplicates).
|
|
80
|
+
*/
|
|
81
|
+
async initialize(dependencies) {
|
|
82
|
+
if (this.initialized) {
|
|
83
|
+
throw new Error('This adapter has already been initialized!');
|
|
84
|
+
}
|
|
85
|
+
this.dependencies = this.initializeDependencies(dependencies);
|
|
86
|
+
for (const endpoint of this.endpoints) {
|
|
87
|
+
// Add aliases to map to use in validation
|
|
88
|
+
const aliases = [endpoint.name, ...(endpoint.aliases || [])];
|
|
89
|
+
for (const alias of aliases) {
|
|
90
|
+
if (this.endpointsMap[alias]) {
|
|
91
|
+
throw new Error(`Duplicate endpoint / alias: "${alias}"`);
|
|
92
|
+
}
|
|
93
|
+
this.endpointsMap[alias] = endpoint;
|
|
94
|
+
}
|
|
95
|
+
logger.debug(`Initializing transport for endpoint "${endpoint.name}"...`);
|
|
96
|
+
await endpoint.transport.initialize(this.dependencies, this.config, endpoint.name);
|
|
97
|
+
}
|
|
98
|
+
// Build list of key/values that need to be redacted in logs
|
|
99
|
+
// Populates the static array in CensorList to use in censor-transport
|
|
100
|
+
this.buildCensorList();
|
|
101
|
+
logger.debug('Adapter initialization complete.');
|
|
102
|
+
this.initialized = true;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Takes an adapter and normalizes all endpoint names and aliases, as well as the default endpoint.
|
|
106
|
+
* i.e. makes them lowercase for now
|
|
107
|
+
*/
|
|
108
|
+
normalizeEndpointNames() {
|
|
109
|
+
for (const endpoint of this.endpoints) {
|
|
110
|
+
endpoint.name = endpoint.name.toLowerCase();
|
|
111
|
+
endpoint.aliases = endpoint.aliases?.map((a) => a.toLowerCase());
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* This function will take an adapter structure and go through each endpoint, calculating
|
|
116
|
+
* each one's allocation of the total rate limits that are set for the adapter as a whole.
|
|
117
|
+
*
|
|
118
|
+
*/
|
|
119
|
+
calculateRateLimitAllocations() {
|
|
120
|
+
const numberOfEndpoints = this.endpoints.length;
|
|
121
|
+
const endpointsWithExplicitAllocations = this.endpoints.filter((e) => e.rateLimiting);
|
|
122
|
+
const totalExplicitAllocation = endpointsWithExplicitAllocations
|
|
123
|
+
.map((e) => e.rateLimiting?.allocationPercentage || 0)
|
|
124
|
+
.reduce((sum, next) => sum + next, 0);
|
|
125
|
+
if (totalExplicitAllocation > 100) {
|
|
126
|
+
throw new Error('The total allocation set for all endpoints summed cannot exceed 100%');
|
|
127
|
+
}
|
|
128
|
+
if (totalExplicitAllocation === 100 &&
|
|
129
|
+
numberOfEndpoints - endpointsWithExplicitAllocations.length > 0) {
|
|
130
|
+
throw new Error('The explicit allocation is at 100% but there are endpoints with implicit allocation');
|
|
131
|
+
}
|
|
132
|
+
const implicitAllocation = 100 - totalExplicitAllocation;
|
|
133
|
+
logger.debug('Adapter rate limit allocations:');
|
|
134
|
+
for (const endpoint of this.endpoints) {
|
|
135
|
+
if (!endpoint.rateLimiting) {
|
|
136
|
+
endpoint.rateLimiting = {
|
|
137
|
+
allocationPercentage: implicitAllocation / (numberOfEndpoints - endpointsWithExplicitAllocations.length),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
logger.debug(`Endpoint [${endpoint.name}] - ${endpoint.rateLimiting?.allocationPercentage}%`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Creates a list of key/value pairs that need to be censored in the logs
|
|
145
|
+
* using the sensitive flag in the adapter config
|
|
146
|
+
*/
|
|
147
|
+
buildCensorList() {
|
|
148
|
+
const censorList = Object.entries(config_1.BaseSettings)
|
|
149
|
+
.concat(Object.entries(this.customSettings || {}))
|
|
150
|
+
.filter(([name, setting]) => setting && setting.type === 'string' && setting.sensitive && this.config[name])
|
|
151
|
+
.map(([name]) => ({
|
|
152
|
+
key: name,
|
|
153
|
+
// Escaping potential special characters in values before creating regex
|
|
154
|
+
value: new RegExp(
|
|
155
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
156
|
+
this.config[name].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')),
|
|
157
|
+
}));
|
|
158
|
+
censor_list_1.default.set(censorList);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* This function will process dependencies for an adapter, such as caches or rate limiters,
|
|
162
|
+
* in order to inject them into transports and other relevant places later in the lifecycle.
|
|
163
|
+
*
|
|
164
|
+
* @param inputDependencies - a partial obj of initialized dependencies to override the created ones
|
|
165
|
+
* @returns a set of AdapterDependencies all initialized
|
|
166
|
+
*/
|
|
167
|
+
initializeDependencies(inputDependencies) {
|
|
168
|
+
const dependencies = inputDependencies || {};
|
|
169
|
+
if (!dependencies.redisClient) {
|
|
170
|
+
if (this.config.CACHE_TYPE === 'redis') {
|
|
171
|
+
dependencies.redisClient = new ioredis_1.default({
|
|
172
|
+
enableAutoPipelining: true,
|
|
173
|
+
host: this.config.CACHE_REDIS_HOST,
|
|
174
|
+
port: this.config.CACHE_REDIS_PORT,
|
|
175
|
+
password: this.config.CACHE_REDIS_PASSWORD,
|
|
176
|
+
path: this.config.CACHE_REDIS_PATH,
|
|
177
|
+
timeout: this.config.CACHE_REDIS_TIMEOUT,
|
|
178
|
+
});
|
|
179
|
+
dependencies.redisClient.on('connect', () => {
|
|
180
|
+
cacheMetrics.redisConnectionsOpen.inc();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (!dependencies.cache) {
|
|
185
|
+
dependencies.cache = cache_1.CacheFactory.buildCache(this.config.CACHE_TYPE, dependencies.redisClient);
|
|
186
|
+
}
|
|
187
|
+
const rateLimitingTier = (0, rate_limiting_1.getRateLimitingTier)(this.config, this.rateLimiting?.tiers);
|
|
188
|
+
if (!dependencies.requestRateLimiter) {
|
|
189
|
+
dependencies.requestRateLimiter = new rate_limiting_1.SimpleCountingRateLimiter().initialize(this.endpoints, rateLimitingTier);
|
|
190
|
+
}
|
|
191
|
+
if (!dependencies.backgroundExecuteRateLimiter) {
|
|
192
|
+
dependencies.backgroundExecuteRateLimiter = new rate_limiting_1.FixedFrequencyRateLimiter().initialize(this.endpoints, rateLimitingTier);
|
|
193
|
+
}
|
|
194
|
+
if (!dependencies.subscriptionSetFactory) {
|
|
195
|
+
dependencies.subscriptionSetFactory = new util_1.SubscriptionSetFactory(this.config, dependencies.redisClient, this.name);
|
|
196
|
+
}
|
|
197
|
+
return dependencies;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
exports.Adapter = Adapter;
|
package/adapter.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/cache/redis.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
|
-
import Redis from 'ioredis';
|
|
1
|
+
import Redis, { Callback } from 'ioredis';
|
|
2
2
|
import { Cache, CacheEntry } from './index';
|
|
3
|
+
/**
|
|
4
|
+
* Common callback for redis commands that logs success/fail and throws on fail
|
|
5
|
+
* @param {string} message - message to log on error
|
|
6
|
+
* @param {string} functionName - name of the redis function where this callback was used, used for metrics
|
|
7
|
+
*/
|
|
3
8
|
/**
|
|
4
9
|
* Redis implementation of a Cache. It uses a simple js Object, storing entries with both
|
|
5
10
|
* a value and an expiration timestamp. Expired entries are deleted on reads (i.e. no background gc/upkeep).
|
|
6
11
|
*
|
|
7
12
|
* @typeParam T - the type for the entries' values
|
|
13
|
+
* @param {boolean} alwaysFail - if true, error callback will always throw an error (used for testing)
|
|
8
14
|
*/
|
|
9
15
|
export declare class RedisCache<T = unknown> implements Cache<T> {
|
|
10
16
|
private client;
|
|
11
17
|
constructor(client: Redis);
|
|
18
|
+
commandCallback(message: string, functionName: string): Callback;
|
|
12
19
|
get(key: string): Promise<T | undefined>;
|
|
13
20
|
delete(key: string): Promise<void>;
|
|
14
21
|
set(key: string, value: T, ttl: number): Promise<void>;
|
package/cache/redis.js
CHANGED
|
@@ -25,25 +25,52 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.RedisCache = void 0;
|
|
27
27
|
const util_1 = require("../util");
|
|
28
|
+
const metrics_1 = require("./metrics");
|
|
28
29
|
const cacheMetrics = __importStar(require("./metrics"));
|
|
29
30
|
const logger = (0, util_1.makeLogger)('RedisCache');
|
|
31
|
+
const recordRedisCommandMetric = (status, functionName) => {
|
|
32
|
+
cacheMetrics.redisCommandsSentCount
|
|
33
|
+
.labels({ status: cacheMetrics.CMD_SENT_STATUS[status], function_name: functionName })
|
|
34
|
+
.inc();
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Common callback for redis commands that logs success/fail and throws on fail
|
|
38
|
+
* @param {string} message - message to log on error
|
|
39
|
+
* @param {string} functionName - name of the redis function where this callback was used, used for metrics
|
|
40
|
+
*/
|
|
30
41
|
/**
|
|
31
42
|
* Redis implementation of a Cache. It uses a simple js Object, storing entries with both
|
|
32
43
|
* a value and an expiration timestamp. Expired entries are deleted on reads (i.e. no background gc/upkeep).
|
|
33
44
|
*
|
|
34
45
|
* @typeParam T - the type for the entries' values
|
|
46
|
+
* @param {boolean} alwaysFail - if true, error callback will always throw an error (used for testing)
|
|
35
47
|
*/
|
|
36
48
|
class RedisCache {
|
|
37
49
|
constructor(client) {
|
|
38
50
|
this.client = client;
|
|
51
|
+
// Global error handler in case one of the commands is missing a callback
|
|
52
|
+
this.client.on('error', (err) => {
|
|
53
|
+
logger.error(`Encountered unhandled error in RedisCache: ${err}`);
|
|
54
|
+
// Record error command sent to Redis
|
|
55
|
+
recordRedisCommandMetric(metrics_1.CMD_SENT_STATUS.FAIL, 'outermost');
|
|
56
|
+
throw err;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
commandCallback(message, functionName) {
|
|
60
|
+
return (err) => {
|
|
61
|
+
if (err) {
|
|
62
|
+
logger.error(`${message}: ${err}`);
|
|
63
|
+
recordRedisCommandMetric(metrics_1.CMD_SENT_STATUS.FAIL, functionName);
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
recordRedisCommandMetric(metrics_1.CMD_SENT_STATUS.SUCCESS, functionName);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
39
70
|
}
|
|
40
71
|
async get(key) {
|
|
41
72
|
logger.trace(`Getting key ${key}`);
|
|
42
|
-
const value = await this.client.get(key);
|
|
43
|
-
// Record get command sent to Redis
|
|
44
|
-
cacheMetrics.redisCommandsSentCount
|
|
45
|
-
.labels({ status: cacheMetrics.CMD_SENT_STATUS.SUCCESS, function_name: 'get' })
|
|
46
|
-
.inc();
|
|
73
|
+
const value = await this.client.get(key, this.commandCallback(`Error getting key "${key}"`, 'get'));
|
|
47
74
|
if (!value) {
|
|
48
75
|
logger.debug(`No entry in redis cache for key "${key}", returning undefined`);
|
|
49
76
|
return undefined;
|
|
@@ -52,38 +79,30 @@ class RedisCache {
|
|
|
52
79
|
}
|
|
53
80
|
async delete(key) {
|
|
54
81
|
logger.trace(`Deleting key ${key}`);
|
|
55
|
-
await this.client.del(key);
|
|
56
|
-
// Record delete command sent to Redis
|
|
57
|
-
cacheMetrics.redisCommandsSentCount
|
|
58
|
-
.labels({ status: cacheMetrics.CMD_SENT_STATUS.SUCCESS, function_name: 'delete' })
|
|
59
|
-
.inc();
|
|
82
|
+
await this.client.del(key, this.commandCallback(`Error deleting key "${key}"`, 'delete'));
|
|
60
83
|
}
|
|
61
84
|
async set(key, value, ttl) {
|
|
62
85
|
logger.trace(`Setting key ${key}`);
|
|
63
|
-
|
|
64
|
-
// Only record metrics if feed Id is present, otherwise assuming value is not adapter response to record
|
|
86
|
+
// Only record metrics if feed id is present, otherwise assuming value is not adapter response to record
|
|
65
87
|
const feedId = value.meta?.metrics?.feedId;
|
|
66
88
|
if (feedId) {
|
|
67
89
|
// Record cache set count, max age, and staleness (set to 0 for cache set)
|
|
68
90
|
const label = cacheMetrics.cacheMetricsLabel(key, feedId, cacheMetrics.CacheTypes.Redis);
|
|
69
91
|
cacheMetrics.cacheSet(label, ttl);
|
|
70
92
|
}
|
|
71
|
-
|
|
72
|
-
cacheMetrics.redisCommandsSentCount
|
|
73
|
-
.labels({ status: cacheMetrics.CMD_SENT_STATUS.SUCCESS, function_name: 'set' })
|
|
74
|
-
.inc();
|
|
93
|
+
await this.client.set(key, JSON.stringify(value), 'PX', ttl, this.commandCallback(`Error setting key "${key}"`, 'set'));
|
|
75
94
|
}
|
|
76
95
|
async setMany(entries, ttl) {
|
|
77
96
|
logger.trace(`Setting a bunch of keys`);
|
|
78
97
|
// Unfortunately, there's no ttl for mset
|
|
79
98
|
let chain = this.client.multi();
|
|
80
99
|
for (const entry of entries) {
|
|
81
|
-
chain = chain.set(entry.key, JSON.stringify(entry.value), 'PX', ttl);
|
|
100
|
+
chain = chain.set(entry.key, JSON.stringify(entry.value), 'PX', ttl, this.commandCallback(`Error setting key "${entry.key}"`, 'setMany'));
|
|
82
101
|
}
|
|
83
|
-
await chain.exec();
|
|
102
|
+
await chain.exec(this.commandCallback(`Exec failed`, 'exec')); // TODO Not sure this will be hit since an individual set will throw
|
|
84
103
|
// Loop again, but this time to record these in metrics
|
|
85
104
|
for (const entry of entries) {
|
|
86
|
-
// Only record metrics if feed
|
|
105
|
+
// Only record metrics if feed id is present, otherwise assuming value is not adapter response to record
|
|
87
106
|
const feedId = entry.value.meta?.metrics?.feedId;
|
|
88
107
|
if (feedId) {
|
|
89
108
|
// Record cache set count, max age, and staleness (set to 0 for cache set)
|
|
@@ -92,9 +111,7 @@ class RedisCache {
|
|
|
92
111
|
}
|
|
93
112
|
}
|
|
94
113
|
// Record setMany command sent to Redis
|
|
95
|
-
|
|
96
|
-
.labels({ status: cacheMetrics.CMD_SENT_STATUS.SUCCESS, function_name: 'exec' })
|
|
97
|
-
.inc();
|
|
114
|
+
recordRedisCommandMetric(metrics_1.CMD_SENT_STATUS.SUCCESS, 'exec');
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
exports.RedisCache = RedisCache;
|
package/cache/redis.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/cache/redis.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,kCAAqD;AAErD,wDAAyC;AAEzC,MAAM,MAAM,GAAG,IAAA,iBAAU,EAAC,YAAY,CAAC,CAAA;AAEvC
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/cache/redis.ts"],"names":[],"mappings":"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"}
|
package/config/index.d.ts
CHANGED
|
@@ -191,7 +191,7 @@ export declare const BaseSettings: {
|
|
|
191
191
|
readonly description: "Maximum amount of characters that the common part of the cache key or feed ID can have";
|
|
192
192
|
readonly type: "number";
|
|
193
193
|
readonly default: 300;
|
|
194
|
-
readonly validate: (value?: number) => "MAX_COMMON_KEY_SIZE must be a number between 150 and 500" | undefined;
|
|
194
|
+
readonly validate: (value?: number | undefined) => "MAX_COMMON_KEY_SIZE must be a number between 150 and 500" | undefined;
|
|
195
195
|
};
|
|
196
196
|
readonly REST_TRANSPORT_MAX_RATE_LIMIT_RETRIES: {
|
|
197
197
|
readonly description: "Maximum amount of times the Rest Transport will attempt to set up a request when blocked by the rate limiter";
|
|
@@ -6,7 +6,7 @@ export declare const customSettings: {
|
|
|
6
6
|
readonly type: "number";
|
|
7
7
|
readonly required: false;
|
|
8
8
|
readonly default: 500;
|
|
9
|
-
readonly validate: (value?: number) => string | undefined;
|
|
9
|
+
readonly validate: (value?: number | undefined) => string | undefined;
|
|
10
10
|
};
|
|
11
11
|
readonly PRIVATE_KEY: {
|
|
12
12
|
readonly description: "";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.batchEndpoint = void 0;
|
|
4
|
+
const adapter_1 = require("../../adapter");
|
|
5
|
+
const batch_warming_1 = require("../../transports/batch-warming");
|
|
6
|
+
const DEFAULT_URL = 'https://pro-api.coingecko.com/api/v3';
|
|
7
|
+
const inputParameters = {
|
|
8
|
+
coinid: {
|
|
9
|
+
description: 'The CoinGecko id or array of ids of the coin(s) to query (Note: because of current limitations to use a dummy base will need to be supplied)',
|
|
10
|
+
required: false,
|
|
11
|
+
},
|
|
12
|
+
base: {
|
|
13
|
+
aliases: ['from', 'coin'],
|
|
14
|
+
description: 'The symbol or array of symbols of the currency to query',
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
quote: {
|
|
18
|
+
aliases: ['to', 'market'],
|
|
19
|
+
description: 'The symbol of the currency to convert to',
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const batchEndpointTransport = new batch_warming_1.BatchWarmingTransport({
|
|
24
|
+
prepareRequest: (params, context) => {
|
|
25
|
+
return {
|
|
26
|
+
baseURL: DEFAULT_URL,
|
|
27
|
+
url: '/simple/price',
|
|
28
|
+
method: 'GET',
|
|
29
|
+
params: {
|
|
30
|
+
ids: [...new Set(params.map((p) => p.base))].join(','),
|
|
31
|
+
vs_currencies: [...new Set(params.map((p) => p.quote))].join(','),
|
|
32
|
+
x_cg_pro_api_key: context.adapterConfig.API_KEY,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
parseResponse: (res) => {
|
|
37
|
+
const entries = [];
|
|
38
|
+
for (const [base, entry] of Object.entries(res.data)) {
|
|
39
|
+
for (const [quote, price] of Object.entries(entry)) {
|
|
40
|
+
entries.push({
|
|
41
|
+
params: { base, quote },
|
|
42
|
+
value: price,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return entries;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
exports.batchEndpoint = new adapter_1.AdapterEndpoint({
|
|
50
|
+
name: 'batch',
|
|
51
|
+
transport: batchEndpointTransport,
|
|
52
|
+
inputParameters,
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=batch-warming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-warming.js","sourceRoot":"","sources":["../../../../src/examples/coingecko/batch-warming.ts"],"names":[],"mappings":";;;AACA,2CAA+D;AAC/D,kEAAsE;AAItE,MAAM,WAAW,GAAG,sCAAsC,CAAA;AAO1D,MAAM,eAAe,GAAoB;IACvC,MAAM,EAAE;QACN,WAAW,EACT,8IAA8I;QAChJ,QAAQ,EAAE,KAAK;KAChB;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,yDAAyD;QACtE,QAAQ,EAAE,IAAI;KACf;IACD,KAAK,EAAE;QACL,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC;QACzB,WAAW,EAAE,0CAA0C;QACvD,QAAQ,EAAE,IAAI;KACf;CACF,CAAA;AAYD,MAAM,sBAAsB,GAAG,IAAI,qCAAqB,CAAC;IACvD,cAAc,EAAE,CACd,MAA8B,EAC9B,OAAuB,EACkB,EAAE;QAC3C,OAAO;YACL,OAAO,EAAE,WAAW;YACpB,GAAG,EAAE,eAAe;YACpB,MAAM,EAAE,KAAK;YACb,MAAM,EAAE;gBACN,GAAG,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACtD,aAAa,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBACjE,gBAAgB,EAAE,OAAO,CAAC,aAAa,CAAC,OAAO;aAChD;SACF,CAAA;IACH,CAAC;IACD,aAAa,EAAE,CACb,GAAwC,EACA,EAAE;QAC1C,MAAM,OAAO,GAAG,EAA4C,CAAA;QAC5D,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACpD,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBAClD,OAAO,CAAC,IAAI,CAAC;oBACX,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;oBACvB,KAAK,EAAE,KAAK;iBACb,CAAC,CAAA;aACH;SACF;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;CACF,CAAC,CAAA;AAEW,QAAA,aAAa,GAAG,IAAI,yBAAe,CAAC;IAC/C,IAAI,EAAE,OAAO;IACb,SAAS,EAAE,sBAAsB;IACjC,eAAe;CAChB,CAAC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.adapter = void 0;
|
|
4
|
+
const adapter_1 = require("../../adapter");
|
|
5
|
+
const batch_warming_1 = require("./batch-warming");
|
|
6
|
+
const rest_1 = require("./rest");
|
|
7
|
+
exports.adapter = new adapter_1.Adapter({
|
|
8
|
+
name: 'coingecko',
|
|
9
|
+
defaultEndpoint: 'batch',
|
|
10
|
+
endpoints: [rest_1.restEndpoint, batch_warming_1.batchEndpoint],
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/examples/coingecko/index.ts"],"names":[],"mappings":";;;AAAA,2CAAuC;AACvC,mDAA+C;AAC/C,iCAAqC;AAExB,QAAA,OAAO,GAAG,IAAI,iBAAO,CAAC;IACjC,IAAI,EAAE,WAAW;IACjB,eAAe,EAAE,OAAO;IACxB,SAAS,EAAE,CAAC,mBAAY,EAAE,6BAAa,CAAC;CACzC,CAAC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AdapterEndpoint } from '../../adapter';
|
|
2
|
+
interface AdapterRequestParams {
|
|
3
|
+
base: string;
|
|
4
|
+
quote: string;
|
|
5
|
+
}
|
|
6
|
+
interface ProviderResponseBody {
|
|
7
|
+
[base: string]: {
|
|
8
|
+
[quote: string]: number;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare const restEndpoint: AdapterEndpoint<AdapterRequestParams, ProviderResponseBody, import("../../config").SettingsMap>;
|
|
12
|
+
export {};
|