1 | import InvalidJsonBodyError from '../errors/invalid-json-body-error'
|
2 | import { constantCase } from 'change-case'
|
3 | import { create as createLogger } from '../common/log'
|
4 | import { Config as ConfigSchemaTyping } from '../schemas/Config'
|
5 | const log = createLogger('config')
|
6 | const schema = require('../schemas/Config.json')
|
7 | const {
|
8 | extractDefaultsFromSchema
|
9 | } = require('../lib/utils')
|
10 | import Ajv = require('ajv')
|
11 |
|
12 | const ajv = new Ajv()
|
13 |
|
14 | const ENV_PREFIX = 'CONNECTOR_'
|
15 |
|
16 | const BOOLEAN_VALUES = {
|
17 | '1': true,
|
18 | 'true': true,
|
19 | '0': false,
|
20 | 'false': false,
|
21 | '': false
|
22 | }
|
23 |
|
24 | export default class Config extends ConfigSchemaTyping {
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | public store!: string
|
31 | public quoteExpiry!: number
|
32 | public routeExpiry!: number
|
33 | public minMessageWindow!: number
|
34 | public maxHoldTime!: number
|
35 | public routeBroadcastInterval!: number
|
36 |
|
37 | protected _validate: Ajv.ValidateFunction
|
38 | protected _validateAccount: Ajv.ValidateFunction
|
39 |
|
40 | constructor () {
|
41 | super()
|
42 |
|
43 | this.loadDefaults()
|
44 |
|
45 | this._validate = ajv.compile(schema)
|
46 | this._validateAccount = ajv.compile(schema.properties.accounts.additionalProperties)
|
47 | }
|
48 |
|
49 | loadDefaults () {
|
50 | Object.assign(this, extractDefaultsFromSchema(schema))
|
51 | }
|
52 |
|
53 | loadFromEnv (env?: NodeJS.ProcessEnv) {
|
54 | if (!env) {
|
55 | env = process.env
|
56 | }
|
57 |
|
58 |
|
59 |
|
60 | const unrecognizedEnvKeys = new Set(
|
61 | Object.keys(env).filter(key => key.startsWith(ENV_PREFIX))
|
62 | )
|
63 |
|
64 | const config = {}
|
65 | for (let key of Object.keys(schema.properties)) {
|
66 | const envKey = ENV_PREFIX + constantCase(key)
|
67 | const envValue = env[envKey]
|
68 |
|
69 | unrecognizedEnvKeys.delete(envKey)
|
70 |
|
71 | if (typeof envValue === 'string') {
|
72 | switch (schema.properties[key].type) {
|
73 | case 'string':
|
74 | config[key] = envValue
|
75 | break
|
76 | case 'object':
|
77 | case 'array':
|
78 | try {
|
79 | config[key] = JSON.parse(envValue)
|
80 | } catch (err) {
|
81 | log.error('unable to parse config. key=%s', envKey)
|
82 | }
|
83 | break
|
84 | case 'boolean':
|
85 | config[key] = BOOLEAN_VALUES[envValue] || false
|
86 | break
|
87 | case 'integer':
|
88 | case 'number':
|
89 | config[key] = Number(envValue)
|
90 | break
|
91 | default:
|
92 | throw new TypeError('Unknown JSON schema type: ' + schema.properties[key].type)
|
93 | }
|
94 | }
|
95 | }
|
96 |
|
97 | for (const key of unrecognizedEnvKeys) {
|
98 | log.warn('unrecognized environment variable. key=%s', key)
|
99 | }
|
100 |
|
101 | this.validate(config)
|
102 |
|
103 | Object.assign(this, config)
|
104 | }
|
105 |
|
106 | loadFromOpts (opts: object) {
|
107 | this.validate(opts)
|
108 |
|
109 | Object.assign(this, opts)
|
110 | }
|
111 |
|
112 | validate (config: object) {
|
113 | if (!this._validate(config)) {
|
114 | const firstError = this._validate.errors && this._validate.errors[0]
|
115 | ? this._validate.errors[0]
|
116 | : { message: 'unknown validation error', dataPath: '' }
|
117 | throw new InvalidJsonBodyError('config failed to validate. error=' + firstError.message + ' dataPath=' + firstError.dataPath, this._validate.errors || [])
|
118 | }
|
119 | }
|
120 |
|
121 | validateAccount (id: string, accountInfo: any) {
|
122 | if (!this._validateAccount(accountInfo)) {
|
123 | throw new InvalidJsonBodyError('account config failed to validate. id=' + id, this._validateAccount.errors || [])
|
124 | }
|
125 | }
|
126 |
|
127 | get (key: string) {
|
128 | return this[key]
|
129 | }
|
130 | }
|