UNPKG

opennms

Version:

Client API for the OpenNMS network monitoring platform

354 lines (321 loc) 10.4 kB
/* eslint-disable max-classes-per-file */ import {OnmsAuthConfig} from './OnmsAuthConfig'; import {OnmsServer} from './OnmsServer'; import {IHash} from '../internal/IHash'; import {Util} from '../internal/Util'; import cloneDeep from 'lodash/cloneDeep'; /** @hidden */ export const DEFAULT_TIMEOUT = 10000; /** @hidden */ export const TIMEOUT_PROP = Symbol.for('timeout'); /** @hidden */ export const AUTH_PROP = Symbol.for('auth'); /** @hidden */ const isString = (v?: any) => { return v && (typeof v === 'string' || v instanceof String); }; /** * A builder for [[OnmsHTTPOptions]]. Create a new one with [[OnmsHTTPOptions.newBuilder]]. * @category Rest */ /* eslint-disable , @typescript-eslint/naming-convention,no-underscore-dangle,id-denylist,id-match, */ export class OnmsHTTPOptionsBuilder { /** @hidden */ private _timeout?: number; /** @hidden */ private _server?: OnmsServer; /** @hidden */ private _auth?: OnmsAuthConfig; /** @hidden */ private _headers = {} as IHash<string>; /** @hidden */ private _parameters = {} as IHash<string | string[]>; /** @hidden */ private _data?: any; /** * Construct a new builder from an existing options object, if provided. * * NOTE: server, auth, headers, and parameters are cloned, but data is left alone * and assumed to be mutable autside of the builder or elsewhere. */ public constructor(options?: OnmsHTTPOptions) { if (options) { this._timeout = options.timeout; this._server = options.server ? options.server.clone() : undefined; this._auth = options.auth ? options.auth.clone() : undefined; this._headers = options.headers ? cloneDeep(options.headers) : {}; this._parameters = options.parameters ? cloneDeep(options.parameters) : {}; this._data = options.data; } } /** Build the [[OnmsHTTPOptions]] object. */ public build(): OnmsHTTPOptions { return new OnmsHTTPOptions( this._timeout, this._server, this._auth, cloneDeep(this._headers), cloneDeep(this._parameters), this._data, ); } /** * Merge the contents of the provided [[OnmsHTTPOptions]] object, additively. * Timeout, server, auth, and data will be replaced only if set, and headers and parameters * will be overlayed on top of existing. * @param options the options to merge with this builder's current values */ public merge(options?: OnmsHTTPOptions) { if (options) { if (options.timeout) { this.setTimeout(options.timeout); } if (options.server) { this.setServer(options.server); } if (options.auth) { this.setAuth(options.auth); } if (options.headers) { for (const header of Object.keys(options.headers)) { this.setHeader(header, options.headers[header]); } } if (options.parameters) { for (const parameter of Object.keys(options.parameters)) { this.addParameter(parameter, options.parameters[parameter]); } } if (options.data) { this.setData(options.data); } } return this; } /** * The connection timeout for the request. * * If `undefined` is passed, the default timeout will be used. * @param timeout the new timeout */ public setTimeout(timeout?: number) { this._timeout = timeout; return this; } /** * The [[OnmsServer]] to connect to. * * If `undefined` is passed, the default server will be used. * @param server the new server */ public setServer(server?: OnmsServer) { this._server = server; return this; } /** * The authentication config to use when connecting. * * If `undefined` is passed, the default authentication settings will be used. * @param auth the authentication config */ public setAuth(auth?: OnmsAuthConfig) { this._auth = auth; return this; } /** * The headers to set in the request. * * If `undefined` is passed, all headers in the builder will be reset and the default headers will be used. * @param headers the headers to use (or `undefined`) */ public setHeaders(headers?: IHash<string>) { this._headers = headers || {}; return this; } /** * A header to set in the request. * * If `undefined` is passed, that header will be reset to defaults. * @param header the header name * @param value the value of the header */ public setHeader(header: string, value?: string | number | boolean) { const v = value ? String(value) : undefined; const actualKey = Util.insensitiveKey(header, this._headers); delete this._headers[header]; if (actualKey) { delete this._headers[actualKey]; } if (v !== undefined) { this._headers[header] = v; } return this; } /** * A header to set in the request only if it is not already set. * @param header the header name * @param value the value of the header */ public setDefaultHeader(header: string, value: string | number | boolean) { const actualKey = Util.insensitiveKey(header, this._headers); if (!actualKey) { this._headers[header] = String(value); } return this; } /** * The parameters to pass to the request. * * If `undefined` is passed, all parameters in the builder will be reset. * @param parameters the parameters to use (or `undefined`) */ public setParameters(parameters?: IHash<string|string[]>) { if (!parameters) { this._parameters = {}; } else { this._parameters = parameters; } return this; } /** * A parameter to add or append to the request. * * If `undefined` is passed, that parameter will be reset to defaults. * If the value is a string array, the existing value in the builder will be replaced. * Otherwise, if the parameter already exists in the builder, the parameter will be converted to an array * if necessary and this parameter will be added to it. * @param parameter the parameter name * @param value the value of the parameter to add (or `undefined`) */ public addParameter(parameter: string, value?: string | string[] | number | boolean) { // if it's already an array, coerce the contents to a string // otherwise, coerce it as a scalar string const v = Array.isArray(value) ? value.map((vv) => String(vv)) : (value && !isString(value)) ? String(value) : value; // Since parameters can be repeated an arbitrary number of times we will store them in an array in the map // as soon as the occurrence of a given key is > 1 if (this._parameters[parameter]) { if (v === undefined) { delete this._parameters[parameter]; } else if (Array.isArray(v)) { this._parameters[parameter] = v.map((obj) => String(obj)); } else { const currentValue = this._parameters[parameter]; if (Array.isArray(currentValue)) { currentValue.push(String(v)); } else { const newArrayValue = []; newArrayValue.push(currentValue); newArrayValue.push(String(v)); this._parameters[parameter] = newArrayValue; } } } else { if (v) { if (Array.isArray(v)) { this._parameters[parameter] = v.map((obj) => String(obj)); } else { this._parameters[parameter] = String(v); } } } return this; } /** * The data to use in the request. * * If `undefined` is passed, the data will be cleared. * @param data the data */ public setData(data?: any) { this._data = data; return this; } } /* eslint-enable @typescript-eslint/naming-convention, no-underscore-dangle, id-denylist, id-match */ /** * Options to be used when making HTTP ReST calls. * @category Rest */ export class OnmsHTTPOptions { /** * Create a new builder for an [[OnmsHTTPOptions]] object. * @param options if an existing options object is passed, the builder will be pre-populated */ public static newBuilder(options?: OnmsHTTPOptions) { return new OnmsHTTPOptionsBuilder(options); } /** How long to wait for ReST calls to time out. */ public get timeout(): number | undefined { return this[TIMEOUT_PROP] || undefined; } /** The authentication config that should be used. */ public get auth(): OnmsAuthConfig | undefined { const auth = this[AUTH_PROP]; if (auth !== null && auth !== undefined) { return auth; } if (this.server && this.server.auth) { return this.server.auth; } return undefined; } /** The server to use instead of that provided by the HTTP implementation. */ public readonly server: OnmsServer | null; /** HTTP headers to be passed to the request. */ public readonly headers = {} as IHash<string>; /** HTTP parameters to be passed on the URL. */ public readonly parameters = {} as IHash<string | string[]>; /** HTTP data to be passed when POSTing */ public readonly data: any; /** * The default timeout associated with these options. * * This is a trick for making sure serialization to JSON happens properly * without exposing internals. */ private readonly [TIMEOUT_PROP]: number | null; /** * The default authentication credentials associated with these options. * * This is a trick for making sure serialization to JSON happens properly * without exposing internals. */ private readonly [AUTH_PROP]: OnmsAuthConfig | null; /** * Construct a new OnmsHTTPOptions object. * @constructor */ constructor( timeout?: number, server?: OnmsServer, auth?: OnmsAuthConfig, headers?: IHash<string>, parameters?: IHash<string | string[]>, data?: any, ) { this[TIMEOUT_PROP] = timeout || DEFAULT_TIMEOUT; this.server = server || null; this[AUTH_PROP] = null; if (server && auth && auth !== server.auth) { this[AUTH_PROP] = auth; } this.headers = headers || {} as IHash<string>; this.parameters = parameters || {} as IHash<string | string[]>; this.data = data; } /** * Convert the options to a plain JSON object. */ public toJSON(): object { const ret = Object.assign({} as any, this); if (this[TIMEOUT_PROP]) { ret.timeout = this[TIMEOUT_PROP]; } if (this[AUTH_PROP]) { ret.auth = this[AUTH_PROP]; } return ret; } }