// Copyright (C) 2018 Zilliqa
//
// This file is part of zilliqa-js
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
import { RPCMethod } from '../net';
import { Matcher, ReqMiddlewareFn, ResMiddlewareFn } from '../util';
const enum MiddlewareType {
REQ,
RES,
}
export class BaseProvider {
middleware = {
request: {
use: (fn: ReqMiddlewareFn, match: Matcher = '*') => {
this.pushMiddleware(fn, MiddlewareType.REQ, match);
},
},
response: {
use: (fn: ResMiddlewareFn, match: Matcher = '*') => {
this.pushMiddleware(fn, MiddlewareType.RES, match);
},
},
};
protected nodeURL: string;
protected reqMiddleware: Map;
protected resMiddleware: Map;
constructor(
nodeURL: string,
reqMiddleware: Map = new Map(),
resMiddleware: Map = new Map(),
) {
this.nodeURL = nodeURL;
this.reqMiddleware = reqMiddleware;
this.resMiddleware = resMiddleware;
}
/**
* pushMiddleware
*
* Adds the middleware to the appropriate middleware map.
*
* @param {ResMiddlewareFn}
* @param {T} type
* @param {Matcher} match
* @returns {void}
*/
protected pushMiddleware(
fn: T extends MiddlewareType.REQ ? ReqMiddlewareFn : ResMiddlewareFn,
type: T,
match: Matcher,
): void {
if (type !== MiddlewareType.REQ && type !== MiddlewareType.RES) {
throw new Error('Please specify the type of middleware being added');
}
if (type === MiddlewareType.REQ) {
const current = this.reqMiddleware.get(match) || [];
this.reqMiddleware.set(match, [...current, fn]);
} else {
const current = this.resMiddleware.get(match) || [];
this.resMiddleware.set(match, [...current, fn]);
}
}
/**
* getMiddleware
*
* Returns the middleware that matches the matcher provided. Note that
* middleware are called in order of specificity: string -> regexp ->
* wildcard.
*
* @param {Matcher} match
* @returns {[ReqMiddlewareFn[], ResMiddlewareFn[]]}
*/
protected getMiddleware(
method: RPCMethod,
): [ReqMiddlewareFn[], ResMiddlewareFn[]] {
const reqFns: ReqMiddlewareFn[] = [];
const resFns: ResMiddlewareFn[] = [];
for (const [key, transformers] of this.reqMiddleware.entries()) {
if (typeof key === 'string' && key !== '*' && key === method) {
reqFns.push(...transformers);
}
if (key instanceof RegExp && key.test(method)) {
reqFns.push(...transformers);
}
if (key === '*') {
reqFns.push(...transformers);
}
}
for (const [key, transformers] of this.resMiddleware.entries()) {
if (typeof key === 'string' && key !== '*' && key === method) {
resFns.push(...transformers);
}
if (key instanceof RegExp && key.test(method)) {
resFns.push(...transformers);
}
if (key === '*') {
resFns.push(...transformers);
}
}
return [reqFns, resFns];
}
}