8
8
import requests
9
9
from builtins import object
10
10
11
- from ldclient .event_consumer import EventConsumerImpl
11
+ from ldclient .config import Config as Config
12
12
from ldclient .feature_requester import FeatureRequesterImpl
13
- from ldclient .feature_store import InMemoryFeatureStore
14
13
from ldclient .flag import evaluate
15
- from ldclient .interfaces import FeatureStore
16
14
from ldclient .polling import PollingUpdateProcessor
17
15
from ldclient .streaming import StreamingUpdateProcessor
18
16
from ldclient .util import check_uwsgi , log
27
25
from cachecontrol import CacheControl
28
26
from threading import Lock
29
27
30
- GET_LATEST_FEATURES_PATH = '/sdk/latest-flags'
31
- STREAM_FEATURES_PATH = '/flags'
32
-
33
-
34
- class Config (object ):
35
- def __init__ (self ,
36
- base_uri = 'https://app.launchdarkly.com' ,
37
- events_uri = 'https://events.launchdarkly.com' ,
38
- connect_timeout = 10 ,
39
- read_timeout = 15 ,
40
- events_upload_max_batch_size = 100 ,
41
- events_max_pending = 10000 ,
42
- stream_uri = 'https://stream.launchdarkly.com' ,
43
- stream = True ,
44
- verify_ssl = True ,
45
- defaults = None ,
46
- events_enabled = True ,
47
- update_processor_class = None ,
48
- poll_interval = 1 ,
49
- use_ldd = False ,
50
- feature_store = InMemoryFeatureStore (),
51
- feature_requester_class = None ,
52
- event_consumer_class = None ,
53
- offline = False ):
54
- """
55
-
56
- :param update_processor_class: A factory for an UpdateProcessor implementation taking the sdk key, config,
57
- and FeatureStore implementation
58
- :type update_processor_class: (str, Config, FeatureStore) -> UpdateProcessor
59
- :param feature_store: A FeatureStore implementation
60
- :type feature_store: FeatureStore
61
- :param feature_requester_class: A factory for a FeatureRequester implementation taking the sdk key and config
62
- :type feature_requester_class: (str, Config, FeatureStore) -> FeatureRequester
63
- :param event_consumer_class: A factory for an EventConsumer implementation taking the event queue, sdk key, and config
64
- :type event_consumer_class: (queue.Queue, str, Config) -> EventConsumer
65
- """
66
- if defaults is None :
67
- defaults = {}
68
-
69
- self .base_uri = base_uri .rstrip ('\\ ' )
70
- self .get_latest_features_uri = self .base_uri + GET_LATEST_FEATURES_PATH
71
- self .events_uri = events_uri .rstrip ('\\ ' ) + '/bulk'
72
- self .stream_uri = stream_uri .rstrip ('\\ ' ) + STREAM_FEATURES_PATH
73
- self .update_processor_class = update_processor_class
74
- self .stream = stream
75
- if poll_interval < 1 :
76
- poll_interval = 1
77
- self .poll_interval = poll_interval
78
- self .use_ldd = use_ldd
79
- self .feature_store = InMemoryFeatureStore () if not feature_store else feature_store
80
- self .event_consumer_class = EventConsumerImpl if not event_consumer_class else event_consumer_class
81
- self .feature_requester_class = feature_requester_class
82
- self .connect_timeout = connect_timeout
83
- self .read_timeout = read_timeout
84
- self .events_enabled = events_enabled
85
- self .events_upload_max_batch_size = events_upload_max_batch_size
86
- self .events_max_pending = events_max_pending
87
- self .verify_ssl = verify_ssl
88
- self .defaults = defaults
89
- self .offline = offline
90
-
91
- def get_default (self , key , default ):
92
- return default if key not in self .defaults else self .defaults [key ]
93
-
94
- @classmethod
95
- def default (cls ):
96
- return cls ()
97
-
98
28
99
29
class LDClient (object ):
100
- def __init__ (self , sdk_key , config = None , start_wait = 5 ):
30
+ def __init__ (self , sdk_key = None , config = None , start_wait = 5 ):
101
31
check_uwsgi ()
102
- self ._sdk_key = sdk_key
103
- self ._config = config or Config .default ()
32
+
33
+ if config is not None and config .sdk_key is not None and sdk_key is not None :
34
+ raise Exception ("LaunchDarkly client init received both sdk_key and config with sdk_key. "
35
+ "Only one of either is expected" )
36
+
37
+ if sdk_key is not None :
38
+ log .warn ("Deprecated sdk_key argument was passed to init. Use config object instead." )
39
+ self ._config = Config (sdk_key = sdk_key )
40
+ else :
41
+ self ._config = config or Config .default ()
42
+
104
43
self ._session = CacheControl (requests .Session ())
105
44
self ._queue = queue .Queue (self ._config .events_max_pending )
106
45
self ._event_consumer = None
@@ -110,39 +49,36 @@ def __init__(self, sdk_key, config=None, start_wait=5):
110
49
""" :type: FeatureStore """
111
50
112
51
if self ._config .offline :
113
- self ._config .events_enabled = False
114
52
log .info ("Started LaunchDarkly Client in offline mode" )
115
53
return
116
54
117
55
if self ._config .events_enabled :
118
- self ._event_consumer = self ._config .event_consumer_class (
119
- self ._queue , self ._sdk_key , self ._config )
56
+ self ._event_consumer = self ._config .event_consumer_class (self ._queue , self ._config )
120
57
self ._event_consumer .start ()
121
58
122
59
if self ._config .use_ldd :
123
60
log .info ("Started LaunchDarkly Client in LDD mode" )
124
61
return
125
62
126
63
if self ._config .feature_requester_class :
127
- self ._feature_requester = self ._config .feature_requester_class (
128
- sdk_key , self ._config )
64
+ self ._feature_requester = self ._config .feature_requester_class (self ._config )
129
65
else :
130
- self ._feature_requester = FeatureRequesterImpl (sdk_key , self ._config )
66
+ self ._feature_requester = FeatureRequesterImpl (self ._config )
131
67
""" :type: FeatureRequester """
132
68
133
69
update_processor_ready = threading .Event ()
134
70
135
71
if self ._config .update_processor_class :
136
72
log .info ("Using user-specified update processor: " + str (self ._config .update_processor_class ))
137
73
self ._update_processor = self ._config .update_processor_class (
138
- sdk_key , self ._config , self ._feature_requester , self ._store , update_processor_ready )
74
+ self ._config , self ._feature_requester , self ._store , update_processor_ready )
139
75
else :
140
76
if self ._config .stream :
141
77
self ._update_processor = StreamingUpdateProcessor (
142
- sdk_key , self ._config , self ._feature_requester , self ._store , update_processor_ready )
78
+ self ._config , self ._feature_requester , self ._store , update_processor_ready )
143
79
else :
144
80
self ._update_processor = PollingUpdateProcessor (
145
- sdk_key , self ._config , self ._feature_requester , self ._store , update_processor_ready )
81
+ self ._config , self ._feature_requester , self ._store , update_processor_ready )
146
82
""" :type: UpdateProcessor """
147
83
148
84
self ._update_processor .start ()
@@ -155,9 +91,8 @@ def __init__(self, sdk_key, config=None, start_wait=5):
155
91
log .warn ("Initialization timeout exceeded for LaunchDarkly Client or an error occurred. "
156
92
"Feature Flags may not yet be available." )
157
93
158
- @property
159
- def sdk_key (self ):
160
- return self ._sdk_key
94
+ def get_sdk_key (self ):
95
+ return self ._config .sdk_key
161
96
162
97
def close (self ):
163
98
log .info ("Closing LaunchDarkly client.." )
@@ -285,9 +220,9 @@ def _evaluate_multi(self, user, flags):
285
220
return {k : self ._evaluate (v , user )[0 ] for k , v in flags .items () or {}}
286
221
287
222
def secure_mode_hash (self , user ):
288
- if user .get ('key' ) is None :
223
+ if user .get ('key' ) is None or self . _config . sdk_key is None :
289
224
return ""
290
- return hmac .new (self ._sdk_key .encode (), user .get ('key' ).encode (), hashlib .sha256 ).hexdigest ()
225
+ return hmac .new (self ._config . sdk_key .encode (), user .get ('key' ).encode (), hashlib .sha256 ).hexdigest ()
291
226
292
227
@staticmethod
293
228
def _sanitize_user (user ):
0 commit comments