splitio-client 9.6.2__tar.gz → 10.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- splitio_client-10.0.0/PKG-INFO +100 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/README.md +1 -1
- {splitio_client-9.6.2 → splitio_client-10.0.0}/setup.cfg +4 -2
- {splitio_client-9.6.2 → splitio_client-10.0.0}/setup.py +12 -8
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/__init__.py +1 -1
- splitio_client-10.0.0/splitio/api/__init__.py +46 -0
- splitio_client-10.0.0/splitio/api/auth.py +109 -0
- splitio_client-10.0.0/splitio/api/client.py +336 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/api/commons.py +17 -5
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/api/events.py +71 -25
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/api/impressions.py +98 -26
- splitio_client-10.0.0/splitio/api/segments.py +130 -0
- splitio_client-10.0.0/splitio/api/splits.py +121 -0
- splitio_client-10.0.0/splitio/api/telemetry.py +187 -0
- splitio_client-10.0.0/splitio/client/client.py +1039 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/config.py +0 -1
- splitio_client-10.0.0/splitio/client/factory.py +1311 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/input_validator.py +163 -64
- splitio_client-10.0.0/splitio/client/listener.py +122 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/localhost.py +31 -0
- splitio_client-10.0.0/splitio/client/manager.py +198 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/util.py +1 -0
- splitio_client-10.0.0/splitio/engine/evaluator.py +185 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/hashfns/legacy.py +1 -0
- splitio_client-10.0.0/splitio/engine/impressions/__init__.py +138 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/adapters.py +184 -13
- splitio_client-10.0.0/splitio/engine/impressions/impressions.py +41 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/manager.py +4 -2
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/strategies.py +15 -28
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/unique_keys_tracker.py +87 -22
- splitio_client-10.0.0/splitio/engine/telemetry.py +687 -0
- splitio_client-10.0.0/splitio/models/__init__.py +6 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/condition.py +2 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/__init__.py +15 -3
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/base.py +1 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/keys.py +2 -5
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/misc.py +4 -2
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/numeric.py +4 -0
- splitio_client-10.0.0/splitio/models/grammar/matchers/semver.py +260 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/sets.py +8 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/string.py +7 -0
- splitio_client-10.0.0/splitio/models/grammar/matchers/utils/utils.py +168 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/notification.py +1 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/splits.py +38 -1
- splitio_client-10.0.0/splitio/models/telemetry.py +1954 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/token.py +1 -0
- splitio_client-10.0.0/splitio/optional/loaders.py +21 -0
- splitio_client-10.0.0/splitio/push/__init__.py +13 -0
- splitio_client-10.0.0/splitio/push/manager.py +534 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/parser.py +7 -3
- splitio_client-10.0.0/splitio/push/processor.py +190 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/splitsse.py +140 -39
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/sse.py +103 -11
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/status_tracker.py +183 -37
- splitio_client-10.0.0/splitio/push/workers.py +371 -0
- splitio_client-10.0.0/splitio/recorder/recorder.py +431 -0
- splitio_client-10.0.0/splitio/spec.py +1 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/__init__.py +4 -3
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/adapters/cache_trait.py +102 -37
- splitio_client-10.0.0/splitio/storage/adapters/redis.py +976 -0
- splitio_client-10.0.0/splitio/storage/inmemmory.py +1906 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/pluggable.py +1182 -389
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/redis.py +892 -185
- splitio_client-10.0.0/splitio/sync/event.py +129 -0
- splitio_client-10.0.0/splitio/sync/impression.py +191 -0
- splitio_client-10.0.0/splitio/sync/manager.py +323 -0
- splitio_client-10.0.0/splitio/sync/segment.py +639 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/split.py +466 -150
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/synchronizer.py +592 -76
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/telemetry.py +82 -5
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/unique_keys.py +80 -19
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/events_sync.py +44 -15
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/impressions_sync.py +75 -19
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/segment_sync.py +36 -10
- splitio_client-10.0.0/splitio/tasks/split_sync.py +69 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/telemetry_sync.py +45 -16
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/unique_keys_sync.py +74 -19
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/util/asynctask.py +154 -2
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/util/workerpool.py +94 -1
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/storage_helper.py +28 -0
- splitio_client-10.0.0/splitio/version.py +1 -0
- splitio_client-10.0.0/splitio_client.egg-info/PKG-INFO +100 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/SOURCES.txt +7 -2
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/requires.txt +13 -6
- splitio_client-9.6.2/PKG-INFO +0 -21
- splitio_client-9.6.2/splitio/api/__init__.py +0 -15
- splitio_client-9.6.2/splitio/api/auth.py +0 -61
- splitio_client-9.6.2/splitio/api/client.py +0 -149
- splitio_client-9.6.2/splitio/api/segments.py +0 -74
- splitio_client-9.6.2/splitio/api/splits.py +0 -68
- splitio_client-9.6.2/splitio/api/telemetry.py +0 -104
- splitio_client-9.6.2/splitio/client/client.py +0 -541
- splitio_client-9.6.2/splitio/client/factory.py +0 -725
- splitio_client-9.6.2/splitio/client/listener.py +0 -65
- splitio_client-9.6.2/splitio/client/manager.py +0 -104
- splitio_client-9.6.2/splitio/engine/evaluator.py +0 -201
- splitio_client-9.6.2/splitio/engine/impressions/__init__.py +0 -50
- splitio_client-9.6.2/splitio/engine/impressions/impressions.py +0 -61
- splitio_client-9.6.2/splitio/engine/telemetry.py +0 -354
- splitio_client-9.6.2/splitio/models/telemetry.py +0 -1025
- splitio_client-9.6.2/splitio/push/manager.py +0 -250
- splitio_client-9.6.2/splitio/push/processor.py +0 -90
- splitio_client-9.6.2/splitio/push/segmentworker.py +0 -67
- splitio_client-9.6.2/splitio/push/splitworker.py +0 -128
- splitio_client-9.6.2/splitio/recorder/recorder.py +0 -169
- splitio_client-9.6.2/splitio/storage/adapters/redis.py +0 -487
- splitio_client-9.6.2/splitio/storage/inmemmory.py +0 -804
- splitio_client-9.6.2/splitio/sync/event.py +0 -67
- splitio_client-9.6.2/splitio/sync/impression.py +0 -97
- splitio_client-9.6.2/splitio/sync/manager.py +0 -177
- splitio_client-9.6.2/splitio/sync/segment.py +0 -334
- splitio_client-9.6.2/splitio/tasks/split_sync.py +0 -40
- splitio_client-9.6.2/splitio/version.py +0 -1
- splitio_client-9.6.2/splitio_client.egg-info/PKG-INFO +0 -21
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/key.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/cache/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/cache/lru.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/filters.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/hashfns/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/hashfns/murmur3py.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/splitters.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/exceptions.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/factories.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/impressions.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/key.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/datatypes.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/events.py +0 -0
- {splitio_client-9.6.2/splitio/models → splitio_client-10.0.0/splitio/models/grammar}/__init__.py +0 -0
- {splitio_client-9.6.2/splitio/models/grammar → splitio_client-10.0.0/splitio/models/grammar/matchers/utils}/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/partitions.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/impressions.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/segments.py +0 -0
- {splitio_client-9.6.2/splitio/push → splitio_client-10.0.0/splitio/optional}/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/recorder/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/adapters/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/adapters/util.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/util.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/util/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/__init__.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/backoff.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/decorators.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/threadutil.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/time.py +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/dependency_links.txt +0 -0
- {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: splitio_client
|
|
3
|
+
Version: 10.0.0
|
|
4
|
+
Summary: Split.io Python Client
|
|
5
|
+
Home-page: https://github.com/splitio/python-client
|
|
6
|
+
Author: Patricio Echague, Sebastian Arrubia
|
|
7
|
+
Author-email: pato@split.io, sebastian@split.io
|
|
8
|
+
License: Apache License 2.0
|
|
9
|
+
Download-URL: https://github.com/splitio/python-client/tarball/10.0.0
|
|
10
|
+
Description: # Split Python SDK
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
This SDK is designed to work with Split, the platform for controlled rollouts, which serves features to your users via a Split feature flag to manage your complete customer experience.
|
|
15
|
+
|
|
16
|
+
[](https://twitter.com/intent/follow?screen_name=splitsoftware)
|
|
17
|
+
|
|
18
|
+
## Compatibility
|
|
19
|
+
This SDK is compatible with **Python 3.7 and higher**.
|
|
20
|
+
|
|
21
|
+
## Getting started
|
|
22
|
+
Below is a simple example that describes the instantiation and most basic usage of our SDK:
|
|
23
|
+
|
|
24
|
+
Run `pip install splitio_client`
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from splitio import get_factory
|
|
29
|
+
from splitio.exceptions import TimeoutException
|
|
30
|
+
factory = get_factory('YOUR_SDK_TYPE_API_KEY', config=config)
|
|
31
|
+
try:
|
|
32
|
+
factory.block_until_ready(5) # wait up to 5 seconds
|
|
33
|
+
split = factory.client()
|
|
34
|
+
treatment = split.get_treatment('CUSTOMER_ID', 'FEATURE_FLAG_NAME')
|
|
35
|
+
if treatment == "on":
|
|
36
|
+
# insert code here to show on treatment
|
|
37
|
+
elif treatment == "off":
|
|
38
|
+
# insert code here to show off treatment
|
|
39
|
+
else:
|
|
40
|
+
# insert your control treatment code here
|
|
41
|
+
except TimeoutException:
|
|
42
|
+
# Now the user can choose whether to abort the whole execution, or just keep going
|
|
43
|
+
# without a ready client, which if configured properly, should become ready at some point.
|
|
44
|
+
pass
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Please refer to [our official docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK) to learn about all the functionality provided by our SDK and the configuration options available for tailoring it to your current application setup.
|
|
48
|
+
|
|
49
|
+
## Submitting issues
|
|
50
|
+
The Split team monitors all issues submitted to this [issue tracker](https://github.com/splitio/python-client/issues). We encourage you to use this issue tracker to submit any bug reports, feedback, and feature enhancements. We'll do our best to respond in a timely manner.
|
|
51
|
+
|
|
52
|
+
## Contributing
|
|
53
|
+
Please see [Contributors Guide](CONTRIBUTORS-GUIDE.md) to find all you need to submit a Pull Request (PR).
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/).
|
|
57
|
+
|
|
58
|
+
## About Split
|
|
59
|
+
|
|
60
|
+
Split is the leading Feature Delivery Platform for engineering teams that want to confidently deploy features as fast as they can develop them. Split’s fine-grained management, real-time monitoring, and data-driven experimentation ensure that new features will improve the customer experience without breaking or degrading performance. Companies like Twilio, Salesforce, GoDaddy and WePay trust Split to power their feature delivery.
|
|
61
|
+
|
|
62
|
+
To learn more about Split, contact hello@split.io, or get started with feature flags for free at https://www.split.io/signup.
|
|
63
|
+
|
|
64
|
+
Split has built and maintains SDKs for:
|
|
65
|
+
|
|
66
|
+
* .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
|
|
67
|
+
* Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK)
|
|
68
|
+
* Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities)
|
|
69
|
+
* GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK)
|
|
70
|
+
* iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK)
|
|
71
|
+
* Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
|
|
72
|
+
* JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
|
|
73
|
+
* JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
|
|
74
|
+
* Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
|
|
75
|
+
* PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)
|
|
76
|
+
* Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK)
|
|
77
|
+
* React [Github](https://github.com/splitio/react-client) [Docs](https://help.split.io/hc/en-us/articles/360038825091-React-SDK)
|
|
78
|
+
* React Native [Github](https://github.com/splitio/react-native-client) [Docs](https://help.split.io/hc/en-us/articles/4406066357901-React-Native-SDK)
|
|
79
|
+
* Redux [Github](https://github.com/splitio/redux-client) [Docs](https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK)
|
|
80
|
+
* Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK)
|
|
81
|
+
|
|
82
|
+
For a comprehensive list of open source projects visit our [Github page](https://github.com/splitio?utf8=%E2%9C%93&query=%20only%3Apublic%20).
|
|
83
|
+
|
|
84
|
+
**Learn more about Split:**
|
|
85
|
+
|
|
86
|
+
Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information.
|
|
87
|
+
|
|
88
|
+
Platform: UNKNOWN
|
|
89
|
+
Classifier: Environment :: Console
|
|
90
|
+
Classifier: Intended Audience :: Developers
|
|
91
|
+
Classifier: Programming Language :: Python
|
|
92
|
+
Classifier: Programming Language :: Python :: 2
|
|
93
|
+
Classifier: Programming Language :: Python :: 3
|
|
94
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
95
|
+
Description-Content-Type: text/markdown
|
|
96
|
+
Provides-Extra: test
|
|
97
|
+
Provides-Extra: redis
|
|
98
|
+
Provides-Extra: uwsgi
|
|
99
|
+
Provides-Extra: cpphash
|
|
100
|
+
Provides-Extra: asyncio
|
|
@@ -7,7 +7,7 @@ This SDK is designed to work with Split, the platform for controlled rollouts, w
|
|
|
7
7
|
[](https://twitter.com/intent/follow?screen_name=splitsoftware)
|
|
8
8
|
|
|
9
9
|
## Compatibility
|
|
10
|
-
This SDK is compatible with **Python 3 and higher**.
|
|
10
|
+
This SDK is compatible with **Python 3.7 and higher**.
|
|
11
11
|
|
|
12
12
|
## Getting started
|
|
13
13
|
Below is a simple example that describes the instantiation and most basic usage of our SDK:
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
universal = 1
|
|
3
3
|
|
|
4
4
|
[metadata]
|
|
5
|
-
|
|
5
|
+
name = splitio_client
|
|
6
|
+
description = This SDK is designed to work with Split, the platform for controlled rollouts, which serves features to your users via a Split feature flag to manage your complete customer experience.
|
|
7
|
+
long_description = file: README.md
|
|
8
|
+
long_description_content_type = text/markdown
|
|
6
9
|
|
|
7
10
|
[flake8]
|
|
8
11
|
max-line-length = 100
|
|
@@ -12,7 +15,6 @@ exclude = tests/*
|
|
|
12
15
|
test = pytest
|
|
13
16
|
|
|
14
17
|
[tool:pytest]
|
|
15
|
-
ignore_glob = ./splitio/_OLD/*
|
|
16
18
|
addopts = --verbose --cov=splitio --cov-report xml
|
|
17
19
|
python_classes = *Tests
|
|
18
20
|
|
|
@@ -7,18 +7,21 @@ from setuptools import setup, find_packages
|
|
|
7
7
|
TESTS_REQUIRES = [
|
|
8
8
|
'flake8',
|
|
9
9
|
'pytest==7.0.1',
|
|
10
|
-
'pytest-mock==3.
|
|
11
|
-
'coverage
|
|
12
|
-
'pytest-cov',
|
|
13
|
-
'importlib-metadata==
|
|
10
|
+
'pytest-mock==3.11.1',
|
|
11
|
+
'coverage',
|
|
12
|
+
'pytest-cov==4.1.0',
|
|
13
|
+
'importlib-metadata==6.7',
|
|
14
14
|
'tomli==1.2.3',
|
|
15
15
|
'iniconfig==1.1.1',
|
|
16
|
-
'attrs==22.1.0'
|
|
16
|
+
'attrs==22.1.0',
|
|
17
|
+
'pytest-asyncio==0.21.0',
|
|
18
|
+
'aiohttp>=3.8.4',
|
|
19
|
+
'aiofiles>=23.1.0'
|
|
17
20
|
]
|
|
18
21
|
|
|
19
22
|
INSTALL_REQUIRES = [
|
|
20
|
-
'requests
|
|
21
|
-
'pyyaml
|
|
23
|
+
'requests',
|
|
24
|
+
'pyyaml',
|
|
22
25
|
'docopt>=0.6.2',
|
|
23
26
|
'enum34;python_version<"3.4"',
|
|
24
27
|
'bloom-filter2>=2.0.0'
|
|
@@ -43,8 +46,9 @@ setup(
|
|
|
43
46
|
'redis': ['redis>=2.10.5'],
|
|
44
47
|
'uwsgi': ['uwsgi>=2.0.0'],
|
|
45
48
|
'cpphash': ['mmh3cffi==0.2.1'],
|
|
49
|
+
'asyncio': ['aiohttp>=3.8.4', 'aiofiles>=23.1.0']
|
|
46
50
|
},
|
|
47
|
-
setup_requires=['pytest-runner', 'pluggy==1.0.0;python_version<"3.
|
|
51
|
+
setup_requires=['pytest-runner', 'pluggy==1.0.0;python_version<"3.8"'],
|
|
48
52
|
classifiers=[
|
|
49
53
|
'Environment :: Console',
|
|
50
54
|
'Intended Audience :: Developers',
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Split API module."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class APIException(Exception):
|
|
5
|
+
"""Exception to raise when an API call fails."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, custom_message, status_code=None):
|
|
8
|
+
"""Constructor."""
|
|
9
|
+
Exception.__init__(self, custom_message)
|
|
10
|
+
self._status_code = status_code if status_code else -1
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def status_code(self):
|
|
14
|
+
"""Return HTTP status code."""
|
|
15
|
+
return self._status_code
|
|
16
|
+
|
|
17
|
+
class APIUriException(APIException):
|
|
18
|
+
"""Exception to raise when an API call fails due to 414 http error."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, custom_message, status_code=None):
|
|
21
|
+
"""Constructor."""
|
|
22
|
+
APIException.__init__(self, custom_message, status_code)
|
|
23
|
+
|
|
24
|
+
def headers_from_metadata(sdk_metadata, client_key=None):
|
|
25
|
+
"""
|
|
26
|
+
Generate a dict with headers required by data-recording API endpoints.
|
|
27
|
+
:param sdk_metadata: SDK Metadata object, generated at sdk initialization time.
|
|
28
|
+
:type sdk_metadata: splitio.client.util.SdkMetadata
|
|
29
|
+
:param client_key: client key.
|
|
30
|
+
:type client_key: str
|
|
31
|
+
:return: A dictionary with headers.
|
|
32
|
+
:rtype: dict
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
metadata = {
|
|
36
|
+
'SplitSDKVersion': sdk_metadata.sdk_version,
|
|
37
|
+
'SplitSDKMachineIP': sdk_metadata.instance_ip,
|
|
38
|
+
'SplitSDKMachineName': sdk_metadata.instance_name
|
|
39
|
+
} if sdk_metadata.instance_ip != 'NA' and sdk_metadata.instance_ip != 'unknown' else {
|
|
40
|
+
'SplitSDKVersion': sdk_metadata.sdk_version,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if client_key is not None:
|
|
44
|
+
metadata['SplitSDKClientKey'] = client_key
|
|
45
|
+
|
|
46
|
+
return metadata
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Auth API module."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from splitio.api import APIException, headers_from_metadata
|
|
7
|
+
from splitio.api.commons import headers_from_metadata, record_telemetry
|
|
8
|
+
from splitio.spec import SPEC_VERSION
|
|
9
|
+
from splitio.util.time import get_current_epoch_time_ms
|
|
10
|
+
from splitio.api.client import HttpClientException
|
|
11
|
+
from splitio.models.token import from_raw
|
|
12
|
+
from splitio.models.telemetry import HTTPExceptionsAndLatencies
|
|
13
|
+
|
|
14
|
+
_LOGGER = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AuthAPI(object): # pylint: disable=too-few-public-methods
|
|
18
|
+
"""Class that uses an httpClient to communicate with the SDK Auth Service API."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer):
|
|
21
|
+
"""
|
|
22
|
+
Class constructor.
|
|
23
|
+
|
|
24
|
+
:param client: HTTP Client responsble for issuing calls to the backend.
|
|
25
|
+
:type client: HttpClient
|
|
26
|
+
:param sdk_key: User sdk key.
|
|
27
|
+
:type sdk_key: string
|
|
28
|
+
:param sdk_metadata: SDK version & machine name & IP.
|
|
29
|
+
:type sdk_metadata: splitio.client.util.SdkMetadata
|
|
30
|
+
"""
|
|
31
|
+
self._client = client
|
|
32
|
+
self._sdk_key = sdk_key
|
|
33
|
+
self._metadata = headers_from_metadata(sdk_metadata)
|
|
34
|
+
self._telemetry_runtime_producer = telemetry_runtime_producer
|
|
35
|
+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.TOKEN, self._telemetry_runtime_producer)
|
|
36
|
+
|
|
37
|
+
def authenticate(self):
|
|
38
|
+
"""
|
|
39
|
+
Perform authentication.
|
|
40
|
+
|
|
41
|
+
:return: Json representation of an authentication.
|
|
42
|
+
:rtype: splitio.models.token.Token
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
response = self._client.get(
|
|
46
|
+
'auth',
|
|
47
|
+
'v2/auth?s=' + SPEC_VERSION,
|
|
48
|
+
self._sdk_key,
|
|
49
|
+
extra_headers=self._metadata,
|
|
50
|
+
)
|
|
51
|
+
if 200 <= response.status_code < 300:
|
|
52
|
+
payload = json.loads(response.body)
|
|
53
|
+
return from_raw(payload)
|
|
54
|
+
|
|
55
|
+
else:
|
|
56
|
+
if (response.status_code >= 400 and response.status_code < 500):
|
|
57
|
+
self._telemetry_runtime_producer.record_auth_rejections()
|
|
58
|
+
raise APIException(response.body, response.status_code)
|
|
59
|
+
except HttpClientException as exc:
|
|
60
|
+
_LOGGER.error('Exception raised while authenticating')
|
|
61
|
+
_LOGGER.debug('Exception information: ', exc_info=True)
|
|
62
|
+
raise APIException('Could not perform authentication.') from exc
|
|
63
|
+
|
|
64
|
+
class AuthAPIAsync(object): # pylint: disable=too-few-public-methods
|
|
65
|
+
"""Async Class that uses an httpClient to communicate with the SDK Auth Service API."""
|
|
66
|
+
|
|
67
|
+
def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer):
|
|
68
|
+
"""
|
|
69
|
+
Class constructor.
|
|
70
|
+
|
|
71
|
+
:param client: HTTP Client responsble for issuing calls to the backend.
|
|
72
|
+
:type client: HttpClient
|
|
73
|
+
:param sdk_key: User sdk key.
|
|
74
|
+
:type sdk_key: string
|
|
75
|
+
:param sdk_metadata: SDK version & machine name & IP.
|
|
76
|
+
:type sdk_metadata: splitio.client.util.SdkMetadata
|
|
77
|
+
"""
|
|
78
|
+
self._client = client
|
|
79
|
+
self._sdk_key = sdk_key
|
|
80
|
+
self._metadata = headers_from_metadata(sdk_metadata)
|
|
81
|
+
self._telemetry_runtime_producer = telemetry_runtime_producer
|
|
82
|
+
self._client.set_telemetry_data(HTTPExceptionsAndLatencies.TOKEN, self._telemetry_runtime_producer)
|
|
83
|
+
|
|
84
|
+
async def authenticate(self):
|
|
85
|
+
"""
|
|
86
|
+
Perform authentication.
|
|
87
|
+
|
|
88
|
+
:return: Json representation of an authentication.
|
|
89
|
+
:rtype: splitio.models.token.Token
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
response = await self._client.get(
|
|
93
|
+
'auth',
|
|
94
|
+
'v2/auth?s=' + SPEC_VERSION,
|
|
95
|
+
self._sdk_key,
|
|
96
|
+
extra_headers=self._metadata,
|
|
97
|
+
)
|
|
98
|
+
if 200 <= response.status_code < 300:
|
|
99
|
+
payload = json.loads(response.body)
|
|
100
|
+
return from_raw(payload)
|
|
101
|
+
|
|
102
|
+
else:
|
|
103
|
+
if (response.status_code >= 400 and response.status_code < 500):
|
|
104
|
+
await self._telemetry_runtime_producer.record_auth_rejections()
|
|
105
|
+
raise APIException(response.body, response.status_code)
|
|
106
|
+
except HttpClientException as exc:
|
|
107
|
+
_LOGGER.error('Exception raised while authenticating')
|
|
108
|
+
_LOGGER.debug('Exception information: ', exc_info=True)
|
|
109
|
+
raise APIException('Could not perform authentication.') from exc
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
"""Synchronous HTTP Client for split API."""
|
|
2
|
+
from collections import namedtuple
|
|
3
|
+
import requests
|
|
4
|
+
import urllib
|
|
5
|
+
import abc
|
|
6
|
+
import logging
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from splitio.optional.loaders import aiohttp
|
|
10
|
+
from splitio.util.time import get_current_epoch_time_ms
|
|
11
|
+
|
|
12
|
+
SDK_URL = 'https://sdk.split.io/api'
|
|
13
|
+
EVENTS_URL = 'https://events.split.io/api'
|
|
14
|
+
AUTH_URL = 'https://auth.split.io/api'
|
|
15
|
+
TELEMETRY_URL = 'https://telemetry.split.io/api'
|
|
16
|
+
|
|
17
|
+
_LOGGER = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
HttpResponse = namedtuple('HttpResponse', ['status_code', 'body', 'headers'])
|
|
21
|
+
|
|
22
|
+
def _build_url(server, path, urls):
|
|
23
|
+
"""
|
|
24
|
+
Build URL according to server specified.
|
|
25
|
+
|
|
26
|
+
:param server: Server for whith the request is being made.
|
|
27
|
+
:type server: str
|
|
28
|
+
:param path: URL path to be appended to base host.
|
|
29
|
+
:type path: str
|
|
30
|
+
|
|
31
|
+
:return: A fully qualified URL.
|
|
32
|
+
:rtype: str
|
|
33
|
+
"""
|
|
34
|
+
url = urls[server]
|
|
35
|
+
url += '/' if urls[server][:-1] != '/' else ''
|
|
36
|
+
return urllib.parse.urljoin(url, path)
|
|
37
|
+
|
|
38
|
+
def _construct_urls(sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
|
|
39
|
+
return {
|
|
40
|
+
'sdk': sdk_url if sdk_url is not None else SDK_URL,
|
|
41
|
+
'events': events_url if events_url is not None else EVENTS_URL,
|
|
42
|
+
'auth': auth_url if auth_url is not None else AUTH_URL,
|
|
43
|
+
'telemetry': telemetry_url if telemetry_url is not None else TELEMETRY_URL,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def _build_basic_headers(sdk_key):
|
|
47
|
+
"""
|
|
48
|
+
Build basic headers with auth.
|
|
49
|
+
|
|
50
|
+
:param sdk_key: API token used to identify backend calls.
|
|
51
|
+
:type sdk_key: str
|
|
52
|
+
"""
|
|
53
|
+
return {
|
|
54
|
+
'Content-Type': 'application/json',
|
|
55
|
+
'Authorization': "Bearer %s" % sdk_key
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class HttpClientException(Exception):
|
|
59
|
+
"""HTTP Client exception."""
|
|
60
|
+
|
|
61
|
+
def __init__(self, message):
|
|
62
|
+
"""
|
|
63
|
+
Class constructor.
|
|
64
|
+
|
|
65
|
+
:param message: Information on why this exception happened.
|
|
66
|
+
:type message: str
|
|
67
|
+
"""
|
|
68
|
+
Exception.__init__(self, message)
|
|
69
|
+
|
|
70
|
+
class HttpClientBase(object, metaclass=abc.ABCMeta):
|
|
71
|
+
"""HttpClient wrapper template."""
|
|
72
|
+
|
|
73
|
+
@abc.abstractmethod
|
|
74
|
+
def get(self, server, path, apikey):
|
|
75
|
+
"""http get request"""
|
|
76
|
+
|
|
77
|
+
@abc.abstractmethod
|
|
78
|
+
def post(self, server, path, apikey):
|
|
79
|
+
"""http post request"""
|
|
80
|
+
|
|
81
|
+
def set_telemetry_data(self, metric_name, telemetry_runtime_producer):
|
|
82
|
+
"""
|
|
83
|
+
Set the data needed for telemetry call
|
|
84
|
+
|
|
85
|
+
:param metric_name: metric name for telemetry
|
|
86
|
+
:type metric_name: str
|
|
87
|
+
|
|
88
|
+
:param telemetry_runtime_producer: telemetry recording instance
|
|
89
|
+
:type telemetry_runtime_producer: splitio.engine.telemetry.TelemetryRuntimeProducer
|
|
90
|
+
"""
|
|
91
|
+
self._telemetry_runtime_producer = telemetry_runtime_producer
|
|
92
|
+
self._metric_name = metric_name
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class HttpClient(HttpClientBase):
|
|
96
|
+
"""HttpClient wrapper."""
|
|
97
|
+
|
|
98
|
+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
|
|
99
|
+
"""
|
|
100
|
+
Class constructor.
|
|
101
|
+
|
|
102
|
+
:param timeout: How many milliseconds to wait until the server responds.
|
|
103
|
+
:type timeout: int
|
|
104
|
+
:param sdk_url: Optional alternative sdk URL.
|
|
105
|
+
:type sdk_url: str
|
|
106
|
+
:param events_url: Optional alternative events URL.
|
|
107
|
+
:type events_url: str
|
|
108
|
+
:param auth_url: Optional alternative auth URL.
|
|
109
|
+
:type auth_url: str
|
|
110
|
+
:param telemetry_url: Optional alternative telemetry URL.
|
|
111
|
+
:type telemetry_url: str
|
|
112
|
+
"""
|
|
113
|
+
self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
|
|
114
|
+
self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
|
|
115
|
+
|
|
116
|
+
def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
117
|
+
"""
|
|
118
|
+
Issue a get request.
|
|
119
|
+
|
|
120
|
+
:param server: Whether the request is for SDK server, Events server or Auth server.
|
|
121
|
+
:typee server: str
|
|
122
|
+
:param path: path to append to the host url.
|
|
123
|
+
:type path: str
|
|
124
|
+
:param sdk_key: sdk key.
|
|
125
|
+
:type sdk_key: str
|
|
126
|
+
:param query: Query string passed as dictionary.
|
|
127
|
+
:type query: dict
|
|
128
|
+
:param extra_headers: key/value pairs of possible extra headers.
|
|
129
|
+
:type extra_headers: dict
|
|
130
|
+
|
|
131
|
+
:return: Tuple of status_code & response text
|
|
132
|
+
:rtype: HttpResponse
|
|
133
|
+
"""
|
|
134
|
+
headers = _build_basic_headers(sdk_key)
|
|
135
|
+
if extra_headers is not None:
|
|
136
|
+
headers.update(extra_headers)
|
|
137
|
+
|
|
138
|
+
start = get_current_epoch_time_ms()
|
|
139
|
+
try:
|
|
140
|
+
response = requests.get(
|
|
141
|
+
_build_url(server, path, self._urls),
|
|
142
|
+
params=query,
|
|
143
|
+
headers=headers,
|
|
144
|
+
timeout=self._timeout
|
|
145
|
+
)
|
|
146
|
+
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
|
|
147
|
+
return HttpResponse(response.status_code, response.text, response.headers)
|
|
148
|
+
|
|
149
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
150
|
+
raise HttpClientException('requests library is throwing exceptions') from exc
|
|
151
|
+
|
|
152
|
+
def post(self, server, path, sdk_key, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
153
|
+
"""
|
|
154
|
+
Issue a POST request.
|
|
155
|
+
|
|
156
|
+
:param server: Whether the request is for SDK server or Events server.
|
|
157
|
+
:typee server: str
|
|
158
|
+
:param path: path to append to the host url.
|
|
159
|
+
:type path: str
|
|
160
|
+
:param sdk_key: sdk key.
|
|
161
|
+
:type sdk_key: str
|
|
162
|
+
:param body: body sent in the request.
|
|
163
|
+
:type body: str
|
|
164
|
+
:param query: Query string passed as dictionary.
|
|
165
|
+
:type query: dict
|
|
166
|
+
:param extra_headers: key/value pairs of possible extra headers.
|
|
167
|
+
:type extra_headers: dict
|
|
168
|
+
|
|
169
|
+
:return: Tuple of status_code & response text
|
|
170
|
+
:rtype: HttpResponse
|
|
171
|
+
"""
|
|
172
|
+
headers = _build_basic_headers(sdk_key)
|
|
173
|
+
|
|
174
|
+
if extra_headers is not None:
|
|
175
|
+
headers.update(extra_headers)
|
|
176
|
+
|
|
177
|
+
start = get_current_epoch_time_ms()
|
|
178
|
+
try:
|
|
179
|
+
response = requests.post(
|
|
180
|
+
_build_url(server, path, self._urls),
|
|
181
|
+
json=body,
|
|
182
|
+
params=query,
|
|
183
|
+
headers=headers,
|
|
184
|
+
timeout=self._timeout
|
|
185
|
+
)
|
|
186
|
+
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
|
|
187
|
+
return HttpResponse(response.status_code, response.text, response.headers)
|
|
188
|
+
|
|
189
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
190
|
+
raise HttpClientException('requests library is throwing exceptions') from exc
|
|
191
|
+
|
|
192
|
+
def _record_telemetry(self, status_code, elapsed):
|
|
193
|
+
"""
|
|
194
|
+
Record Telemetry info
|
|
195
|
+
|
|
196
|
+
:param status_code: http request status code
|
|
197
|
+
:type status_code: int
|
|
198
|
+
|
|
199
|
+
:param elapsed: response time elapsed.
|
|
200
|
+
:type status_code: int
|
|
201
|
+
"""
|
|
202
|
+
self._telemetry_runtime_producer.record_sync_latency(self._metric_name, elapsed)
|
|
203
|
+
if 200 <= status_code < 300:
|
|
204
|
+
self._telemetry_runtime_producer.record_successful_sync(self._metric_name, get_current_epoch_time_ms())
|
|
205
|
+
return
|
|
206
|
+
self._telemetry_runtime_producer.record_sync_error(self._metric_name, status_code)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class HttpClientAsync(HttpClientBase):
|
|
210
|
+
"""HttpClientAsync wrapper."""
|
|
211
|
+
|
|
212
|
+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
|
|
213
|
+
"""
|
|
214
|
+
Class constructor.
|
|
215
|
+
:param timeout: How many milliseconds to wait until the server responds.
|
|
216
|
+
:type timeout: int
|
|
217
|
+
:param sdk_url: Optional alternative sdk URL.
|
|
218
|
+
:type sdk_url: str
|
|
219
|
+
:param events_url: Optional alternative events URL.
|
|
220
|
+
:type events_url: str
|
|
221
|
+
:param auth_url: Optional alternative auth URL.
|
|
222
|
+
:type auth_url: str
|
|
223
|
+
:param telemetry_url: Optional alternative telemetry URL.
|
|
224
|
+
:type telemetry_url: str
|
|
225
|
+
"""
|
|
226
|
+
self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
|
|
227
|
+
self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
|
|
228
|
+
self._session = aiohttp.ClientSession()
|
|
229
|
+
|
|
230
|
+
async def get(self, server, path, apikey, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
231
|
+
"""
|
|
232
|
+
Issue a get request.
|
|
233
|
+
:param server: Whether the request is for SDK server, Events server or Auth server.
|
|
234
|
+
:typee server: str
|
|
235
|
+
:param path: path to append to the host url.
|
|
236
|
+
:type path: str
|
|
237
|
+
:param apikey: api token.
|
|
238
|
+
:type apikey: str
|
|
239
|
+
:param query: Query string passed as dictionary.
|
|
240
|
+
:type query: dict
|
|
241
|
+
:param extra_headers: key/value pairs of possible extra headers.
|
|
242
|
+
:type extra_headers: dict
|
|
243
|
+
:return: Tuple of status_code & response text
|
|
244
|
+
:rtype: HttpResponse
|
|
245
|
+
"""
|
|
246
|
+
headers = _build_basic_headers(apikey)
|
|
247
|
+
if extra_headers is not None:
|
|
248
|
+
headers.update(extra_headers)
|
|
249
|
+
start = get_current_epoch_time_ms()
|
|
250
|
+
try:
|
|
251
|
+
url = _build_url(server, path, self._urls)
|
|
252
|
+
_LOGGER.debug("GET request: %s", url)
|
|
253
|
+
_LOGGER.debug("query params: %s", query)
|
|
254
|
+
_LOGGER.debug("headers: %s", headers)
|
|
255
|
+
async with self._session.get(
|
|
256
|
+
url,
|
|
257
|
+
params=query,
|
|
258
|
+
headers=headers,
|
|
259
|
+
timeout=self._timeout
|
|
260
|
+
) as response:
|
|
261
|
+
body = await response.text()
|
|
262
|
+
_LOGGER.debug("Response:")
|
|
263
|
+
_LOGGER.debug(response)
|
|
264
|
+
_LOGGER.debug(body)
|
|
265
|
+
await self._record_telemetry(response.status, get_current_epoch_time_ms() - start)
|
|
266
|
+
return HttpResponse(response.status, body, response.headers)
|
|
267
|
+
|
|
268
|
+
except aiohttp.ClientError as exc: # pylint: disable=broad-except
|
|
269
|
+
raise HttpClientException('aiohttp library is throwing exceptions') from exc
|
|
270
|
+
|
|
271
|
+
async def post(self, server, path, apikey, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
272
|
+
"""
|
|
273
|
+
Issue a POST request.
|
|
274
|
+
:param server: Whether the request is for SDK server or Events server.
|
|
275
|
+
:typee server: str
|
|
276
|
+
:param path: path to append to the host url.
|
|
277
|
+
:type path: str
|
|
278
|
+
:param apikey: api token.
|
|
279
|
+
:type apikey: str
|
|
280
|
+
:param body: body sent in the request.
|
|
281
|
+
:type body: str
|
|
282
|
+
:param query: Query string passed as dictionary.
|
|
283
|
+
:type query: dict
|
|
284
|
+
:param extra_headers: key/value pairs of possible extra headers.
|
|
285
|
+
:type extra_headers: dict
|
|
286
|
+
:return: Tuple of status_code & response text
|
|
287
|
+
:rtype: HttpResponse
|
|
288
|
+
"""
|
|
289
|
+
headers = _build_basic_headers(apikey)
|
|
290
|
+
if extra_headers is not None:
|
|
291
|
+
headers.update(extra_headers)
|
|
292
|
+
start = get_current_epoch_time_ms()
|
|
293
|
+
try:
|
|
294
|
+
headers['Accept-Encoding'] = 'gzip'
|
|
295
|
+
_LOGGER.debug("POST request: %s", _build_url(server, path, self._urls))
|
|
296
|
+
_LOGGER.debug("query params: %s", query)
|
|
297
|
+
_LOGGER.debug("headers: %s", headers)
|
|
298
|
+
_LOGGER.debug("payload: ")
|
|
299
|
+
_LOGGER.debug(str(json.dumps(body)).encode('utf-8'))
|
|
300
|
+
async with self._session.post(
|
|
301
|
+
_build_url(server, path, self._urls),
|
|
302
|
+
params=query,
|
|
303
|
+
headers=headers,
|
|
304
|
+
json=body,
|
|
305
|
+
timeout=self._timeout
|
|
306
|
+
) as response:
|
|
307
|
+
body = await response.text()
|
|
308
|
+
_LOGGER.debug("Response:")
|
|
309
|
+
_LOGGER.debug(response)
|
|
310
|
+
_LOGGER.debug(body)
|
|
311
|
+
await self._record_telemetry(response.status, get_current_epoch_time_ms() - start)
|
|
312
|
+
return HttpResponse(response.status, body, response.headers)
|
|
313
|
+
|
|
314
|
+
except aiohttp.ClientError as exc: # pylint: disable=broad-except
|
|
315
|
+
raise HttpClientException('aiohttp library is throwing exceptions') from exc
|
|
316
|
+
|
|
317
|
+
async def _record_telemetry(self, status_code, elapsed):
|
|
318
|
+
"""
|
|
319
|
+
Record Telemetry info
|
|
320
|
+
|
|
321
|
+
:param status_code: http request status code
|
|
322
|
+
:type status_code: int
|
|
323
|
+
|
|
324
|
+
:param elapsed: response time elapsed.
|
|
325
|
+
:type status_code: int
|
|
326
|
+
"""
|
|
327
|
+
await self._telemetry_runtime_producer.record_sync_latency(self._metric_name, elapsed)
|
|
328
|
+
if 200 <= status_code < 300:
|
|
329
|
+
await self._telemetry_runtime_producer.record_successful_sync(self._metric_name, get_current_epoch_time_ms())
|
|
330
|
+
return
|
|
331
|
+
|
|
332
|
+
await self._telemetry_runtime_producer.record_sync_error(self._metric_name, status_code)
|
|
333
|
+
|
|
334
|
+
async def close_session(self):
|
|
335
|
+
if not self._session.closed:
|
|
336
|
+
await self._session.close()
|