Skip to content

Commit fda3c99

Browse files
authored
Merge pull request #121 from splitio/feature/oneSingleQueue
[SDKS]: Single Queue With Input Validation
2 parents 4673e55 + 963b225 commit fda3c99

File tree

13 files changed

+732
-235
lines changed

13 files changed

+732
-235
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
6.3.0 ()
22
- Stored Impressions in Queue.
33
- Fixed bug related to Machine Name and Machine IP.
4+
- Updated Input Validation.
45
6.2.2 (Dec 17, 2018)
56
- Fixed issue on selecting db for Sentinel.
67
6.2.1 (Dec 6, 2018)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ Split has built and maintains a SDKs for:
2828
* PHP [Github](https://github.com/splitio/php-client) [Docs](http://docs.split.io/docs/php-sdk-overview)
2929
* Python [Github](https://github.com/splitio/python-client) [Docs](http://docs.split.io/docs/python-sdk-overview)
3030
* GO [Github](https://github.com/splitio/go-client) [Docs](http://docs.split.io/docs/go-sdk-overview)
31-
* Android [Github](https://github.com/splitio/android-client) [Docs](https://docs.split.io/v1/docs/android-sdk-overview)
32-
* IOS [Github](https://github.com/splitio/ios-client) [Docs](https://docs.split.io/v1/docs/ios-sdk-overview)
31+
* Android [Github](https://github.com/splitio/android-client) [Docs](https://docs.split.io/docs/android-sdk-overview)
32+
* IOS [Github](https://github.com/splitio/ios-client) [Docs](https://docs.split.io/docs/ios-sdk-overview)
3333

3434
For a comprehensive list of opensource projects visit our [Github page](https://github.com/splitio?utf8=%E2%9C%93&query=%20only%3Apublic%20).
3535

splitio/api.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import requests
66
import json
77

8+
from splitio.exceptions import ForbiddenException
89
from splitio.config import SDK_API_BASE_URL, EVENTS_API_BASE_URL, SDK_VERSION
910

1011
_SEGMENT_CHANGES_URL_TEMPLATE = '{base_url}/segmentChanges/{segment_name}/'
@@ -92,7 +93,10 @@ def _build_headers(self):
9293
return headers
9394

9495
def _logHttpError(self, response):
95-
if response.status_code < 200 or response.status_code >= 400:
96+
if response.status_code == requests.codes.forbidden:
97+
raise ForbiddenException()
98+
99+
if response.status_code < requests.codes.ok or response.status_code >= requests.codes.bad:
96100
respJson = response.json()
97101
if 'message' in respJson:
98102
self._logger.error(

splitio/clients.py

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,16 @@ def get_treatment(self, key, feature, attributes=None):
8181
:rtype: str
8282
"""
8383
if self._destroyed:
84-
self._logger.warning("Client has already been destroyed, returning CONTROL")
84+
self._logger.error("Client has already been destroyed - no calls possible")
8585
return CONTROL
8686

8787
start = int(round(time.time() * 1000))
8888

89-
matching_key, bucketing_key = input_validator.validate_key(key)
89+
matching_key, bucketing_key = input_validator.validate_key(key, 'get_treatment')
9090
feature = input_validator.validate_feature_name(feature)
9191

92-
if (matching_key is None and bucketing_key is None) or feature is None:
93-
impression = self._build_impression(matching_key, feature, CONTROL, Label.EXCEPTION,
94-
0, bucketing_key, start)
95-
self._record_stats(impression, start, SDK_GET_TREATMENT)
92+
if (matching_key is None and bucketing_key is None) or feature is None or\
93+
input_validator.validate_attributes(attributes, 'get_treatment') is False:
9694
return CONTROL
9795

9896
try:
@@ -151,52 +149,50 @@ def get_treatments(self, key, features, attributes=None):
151149
:rtype: dict
152150
"""
153151
if self._destroyed:
154-
self._logger.warning("Client has already been destroyed, returning None")
155-
return None
152+
self._logger.error("Client has already been destroyed - no calls possible")
153+
return input_validator.generate_control_treatments(features)
156154

157155
start = int(round(time.time() * 1000))
158156

157+
matching_key, bucketing_key = input_validator.validate_key(key, 'get_treatments')
158+
if matching_key is None and bucketing_key is None:
159+
return input_validator.generate_control_treatments(features)
160+
161+
if input_validator.validate_attributes(attributes, 'get_treatment') is False:
162+
return input_validator.generate_control_treatments(features)
163+
159164
features = input_validator.validate_features_get_treatments(features)
160165
if features is None:
161-
return None
162-
163-
matching_key, bucketing_key = input_validator.validate_key(key)
166+
return {}
164167

165168
bulk_impressions = []
166169
treatments = {}
167170

168-
if matching_key is None and bucketing_key is None:
169-
for feature in features:
170-
impression = self._build_impression(matching_key, feature, CONTROL, Label.EXCEPTION,
171-
0, bucketing_key, start)
172-
bulk_impressions.insert(impression)
171+
for feature in features:
172+
try:
173+
treatment = self._evaluator.evaluate_treatment(
174+
feature,
175+
matching_key,
176+
bucketing_key,
177+
attributes
178+
)
179+
180+
impression = self._build_impression(matching_key,
181+
feature,
182+
treatment['treatment'],
183+
treatment['impression']['label'],
184+
treatment['impression']['change_number'],
185+
bucketing_key,
186+
start)
187+
188+
bulk_impressions.append(impression)
189+
treatments[feature] = treatment['treatment']
190+
191+
except Exception:
192+
self._logger.exception('get_treatments: An exception occured when evaluating '
193+
'feature ' + feature + ' returning CONTROL.')
173194
treatments[feature] = CONTROL
174-
else:
175-
for feature in features:
176-
try:
177-
treatment = self._evaluator.evaluate_treatment(
178-
feature,
179-
matching_key,
180-
bucketing_key,
181-
attributes
182-
)
183-
184-
impression = self._build_impression(matching_key,
185-
feature,
186-
treatment['treatment'],
187-
treatment['impression']['label'],
188-
treatment['impression']['change_number'],
189-
bucketing_key,
190-
start)
191-
192-
bulk_impressions.append(impression)
193-
treatments[feature] = treatment['treatment']
194-
195-
except Exception:
196-
self._logger.exception('get_treatments: An exception occured when evaluating '
197-
'feature ' + feature + ' returning CONTROL.')
198-
treatments[feature] = CONTROL
199-
continue
195+
continue
200196

201197
# Register impressions
202198
try:
@@ -268,6 +264,10 @@ def track(self, key, traffic_type, event_type, value=None):
268264
269265
:rtype: bool
270266
"""
267+
if self._destroyed:
268+
self._logger.error("Client has already been destroyed - no calls possible")
269+
return False
270+
271271
key = input_validator.validate_track_key(key)
272272
event_type = input_validator.validate_event_type(event_type)
273273
traffic_type = input_validator.validate_traffic_type(traffic_type)

splitio/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44

55
class TimeoutException(Exception):
66
pass
7+
8+
9+
class ForbiddenException(Exception):
10+
pass

splitio/factories.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from splitio.managers import RedisSplitManager, SelfRefreshingSplitManager, \
77
LocalhostSplitManager, UWSGISplitManager
88
from splitio.impressions import ImpressionListenerWrapper
9+
from . import input_validator
910

1011
import logging
1112

@@ -36,9 +37,7 @@ class MainSplitFactory(SplitFactory):
3637
def __init__(self, api_key, **kwargs):
3738
super(MainSplitFactory, self).__init__()
3839

39-
config = dict()
40-
if 'config' in kwargs:
41-
config = kwargs['config']
40+
config = kwargs.get('config', {})
4241

4342
labels_enabled = config.get('labelsEnabled', True)
4443

@@ -109,6 +108,13 @@ def get_factory(api_key, **kwargs):
109108
:param kwargs:
110109
:return:
111110
"""
111+
config = kwargs.get('config', {})
112+
sdk_api_base_url = kwargs.get('sdk_api_base_url', None)
113+
if 'redisHost' not in config and 'redisSentinels' not in config \
114+
and input_validator.validate_factory_instantiation(api_key, config, sdk_api_base_url) \
115+
is False:
116+
return None
117+
112118
if api_key == 'localhost':
113119
return LocalhostSplitFactory(**kwargs)
114120
else:

0 commit comments

Comments
 (0)