1
- var traverse = require ( 'traverse' ) ;
2
-
3
1
/**
4
2
* Try to parse provided value as JSON, or some other value
5
3
* @param {string } val - value to parse
@@ -17,6 +15,8 @@ var defaultParser = function(val) {
17
15
}
18
16
else if ( Array . isArray ( parsedVal ) ) {
19
17
val = parsedVal ;
18
+ } else if ( typeof parsedVal === 'object' ) {
19
+ val = parsedVal ;
20
20
}
21
21
}
22
22
catch ( error ) {
@@ -25,56 +25,122 @@ var defaultParser = function(val) {
25
25
return val ;
26
26
} ;
27
27
28
+ const OVERRIDES = {
29
+ MONGODB : {
30
+ REPLSETSERVERS : 'replSetServers' ,
31
+ REPLICANAME : 'replicaName' ,
32
+ MAX_POOL_SIZE : 'max_pool_size' ,
33
+ DBOPTIONS : 'dbOptions' ,
34
+ SERVEROPTIONS : 'serverOptions'
35
+ } ,
36
+
37
+ API : {
38
+ MAX_SOCKETS : 'max_sockets' ,
39
+ } ,
40
+
41
+ WEB : {
42
+ USE_INTERCOM : 'use_intercom' ,
43
+ SECURE_COOKIES : 'secure_cookies'
44
+ } ,
45
+
46
+ IGNOREPROXIES : 'ignoreProxies' ,
47
+ FILESTORAGE : 'fileStorage' ,
48
+ RELOADCONFIGAFTER : 'reloadConfigAfter'
49
+ } ;
50
+
28
51
/**
29
- * Try to process configuration
30
- * @param {object } config - configuration to process
31
- * @param {function } parser - parser to use on each property
32
- **/
33
- var read = function ( config , parser ) {
34
- var tc = traverse ( config ) ;
35
- var tcKeyMap = { } ;
36
-
37
- // make paths case-insensitive. Useful while converting from uppercase env
38
- // vars to camelCase variables.
39
- tc . paths ( ) . forEach ( function ( path ) {
40
- // store paths as lowercase with their corresponding actual paths. will be
41
- // used while updating the value
42
- tcKeyMap [ path . join ( '_' ) . toLowerCase ( ) ] = path ;
43
- } ) ;
52
+ * Digs one level down in config document
53
+ *
54
+ * @param {[type] } config [description]
55
+ * @param {[type] } over [description]
56
+ * @param {[type] } name [description]
57
+ * @param {[type] } value [description]
58
+ * @return {[type] } [description]
59
+ */
60
+ function dig ( config , over , name , value ) {
61
+ let comps = name . split ( '_' ) ;
62
+
63
+ for ( let i = comps . length ; i > 0 ; i -- ) {
64
+ let n = comps . slice ( 0 , i ) . join ( '_' ) ;
65
+
66
+ if ( n in over ) {
67
+ let sub ;
44
68
45
- var ref = process . env ;
46
- var env ;
47
- for ( env in ref ) {
48
- var val = ref [ env ] ;
69
+ if ( typeof over [ n ] === 'string' ) {
70
+ sub = over [ n ] ;
71
+ over [ n ] = { } ;
72
+ } else {
73
+ sub = Object . keys ( config ) . filter ( k => k . toUpperCase ( ) === n ) [ 0 ] ;
74
+ }
49
75
50
- // we only care about env vars starting with "countly"
51
- if ( ! env . startsWith ( 'COUNTLY_' ) ) {
52
- continue ;
76
+ name = comps . slice ( i ) . join ( '_' ) ;
77
+
78
+ if ( ! name || comps . length === 1 ) {
79
+ config [ sub ] = value ;
80
+ return true ;
81
+ }
82
+
83
+ if ( typeof config [ sub ] === 'object' ) {
84
+ return dig ( config [ sub ] , over [ n ] , name , value ) ;
85
+ } else if ( sub ) {
86
+ config [ sub ] = { } ;
87
+ return dig ( config [ sub ] , over [ n ] , name , value ) ;
88
+ } else {
89
+ config [ n ] = { } ;
90
+ return dig ( config [ n ] , over [ n ] , name , value ) ;
91
+ }
92
+ } else if ( n === over ) {
93
+ name = over ;
94
+ config [ name ] = value ;
95
+ return true ;
53
96
}
54
- var path = env . split ( '_' ) ;
55
- if ( path . length < 2 ) {
56
- continue ;
97
+ }
98
+
99
+ for ( let i = 1 ; i <= comps . length ; i ++ ) {
100
+ let n = comps . slice ( 0 , i ) . join ( '_' ) ,
101
+ sub = Object . keys ( config ) . filter ( k => k . toUpperCase ( ) === n ) [ 0 ] ,
102
+ name = comps . slice ( i ) . join ( '_' ) ;
103
+
104
+ if ( sub ) {
105
+ if ( comps . length === 1 ) {
106
+ config [ sub ] = value ;
107
+ return true ;
108
+ } else {
109
+ config [ sub ] = typeof config [ sub ] === 'object' ? config [ sub ] : { } ;
110
+ return dig ( config [ sub ] , { } , name , value ) ;
111
+ }
57
112
}
113
+ }
58
114
59
- // get the underlying value of env var
60
- val = parser ( val ) ;
61
- if ( ! val ) {
62
- continue ;
115
+ comps . forEach ( ( c , i ) => {
116
+ if ( i === comps . length - 1 ) {
117
+ config [ c . toLowerCase ( ) ] = value ;
118
+ } else {
119
+ config = config [ c . toLowerCase ( ) ] = { } ;
63
120
}
121
+ } )
64
122
65
- // generate path from env vars, while removing the first COUNTLY_ part
66
- var newPath = path . slice ( 1 ) . map ( function ( node ) {
67
- return parser ( node . toLowerCase ( ) ) ;
68
- } ) ;
123
+ return true ;
124
+ }
69
125
70
- // if we dont have the new path defined in config, we might be creating a
71
- // new node
72
- var location = tcKeyMap [ newPath . join ( '_' ) ] || newPath ;
73
- tc . set ( location , val ) ;
126
+ module . exports = function ( mode , config , opts ) {
127
+ // back compatibility
128
+ if ( typeof mode === 'object' ) {
129
+ config = mode ;
130
+ mode = 'API' ;
131
+ opts = process . env ;
74
132
}
75
- } ;
133
+
134
+ if ( [ 'API' , 'FRONTEND' ] . indexOf ( mode ) === - 1 ) {
135
+ throw new Error ( 'Invalid config mode ' + mode ) ;
136
+ }
137
+
138
+ config = JSON . parse ( JSON . stringify ( config ) ) ;
139
+
140
+ Object . keys ( opts ) . filter ( n => n . indexOf ( `COUNTLY_CONFIG_${ mode } _` ) === 0 ) . forEach ( n => {
141
+ let comps = n . split ( '_' ) . slice ( 3 ) ;
142
+ dig ( config , OVERRIDES , comps . join ( '_' ) , parser ( opts [ n ] ) ) ;
143
+ } ) ;
76
144
77
- module . exports = function ( config ) {
78
- read ( config , defaultParser ) ;
79
145
return config ;
80
146
} ;
0 commit comments