88import requests
99from builtins import object
1010
11- from ldclient .event_consumer import EventConsumerImpl
11+ from ldclient .config import Config as Config
1212from ldclient .feature_requester import FeatureRequesterImpl
13- from ldclient .feature_store import InMemoryFeatureStore
1413from ldclient .flag import evaluate
15- from ldclient .interfaces import FeatureStore
1614from ldclient .polling import PollingUpdateProcessor
1715from ldclient .streaming import StreamingUpdateProcessor
1816from ldclient .util import check_uwsgi , log
2725from cachecontrol import CacheControl
2826from threading import Lock
2927
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-
9828
9929class 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 ):
10131 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+
10443 self ._session = CacheControl (requests .Session ())
10544 self ._queue = queue .Queue (self ._config .events_max_pending )
10645 self ._event_consumer = None
@@ -110,39 +49,36 @@ def __init__(self, sdk_key, config=None, start_wait=5):
11049 """ :type: FeatureStore """
11150
11251 if self ._config .offline :
113- self ._config .events_enabled = False
11452 log .info ("Started LaunchDarkly Client in offline mode" )
11553 return
11654
11755 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 )
12057 self ._event_consumer .start ()
12158
12259 if self ._config .use_ldd :
12360 log .info ("Started LaunchDarkly Client in LDD mode" )
12461 return
12562
12663 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 )
12965 else :
130- self ._feature_requester = FeatureRequesterImpl (sdk_key , self ._config )
66+ self ._feature_requester = FeatureRequesterImpl (self ._config )
13167 """ :type: FeatureRequester """
13268
13369 update_processor_ready = threading .Event ()
13470
13571 if self ._config .update_processor_class :
13672 log .info ("Using user-specified update processor: " + str (self ._config .update_processor_class ))
13773 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 )
13975 else :
14076 if self ._config .stream :
14177 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 )
14379 else :
14480 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 )
14682 """ :type: UpdateProcessor """
14783
14884 self ._update_processor .start ()
@@ -155,9 +91,8 @@ def __init__(self, sdk_key, config=None, start_wait=5):
15591 log .warn ("Initialization timeout exceeded for LaunchDarkly Client or an error occurred. "
15692 "Feature Flags may not yet be available." )
15793
158- @property
159- def sdk_key (self ):
160- return self ._sdk_key
94+ def get_sdk_key (self ):
95+ return self ._config .sdk_key
16196
16297 def close (self ):
16398 log .info ("Closing LaunchDarkly client.." )
@@ -285,9 +220,9 @@ def _evaluate_multi(self, user, flags):
285220 return {k : self ._evaluate (v , user )[0 ] for k , v in flags .items () or {}}
286221
287222 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 :
289224 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 ()
291226
292227 @staticmethod
293228 def _sanitize_user (user ):
0 commit comments