Skip to content

Commit f59190d

Browse files
author
Inbal Tako
committed
Refactor event manager and api manager
1 parent 791dcc4 commit f59190d

12 files changed

Lines changed: 214 additions & 145 deletions

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
requests~=2.23.0
22
pycrypto~=2.6.1
3-
aiohttp~=3.6.2
43
crypto~=1.4.1

securenative/__init__.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +0,0 @@
1-
from securenative.config import sdk_version
2-
import securenative.event_types
3-
from securenative.sdk import SecureNative, SecureNativeOptions
4-
from securenative.event_options import Event, User
5-
from securenative.singleton import init, flush, track, verify_webhook, verify

securenative/api_manager.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from securenative.enums.api_route import ApiRoute
2+
from securenative.enums.failover_strategy import FailOverStrategy
3+
from securenative.enums.risk_level import RiskLevel
4+
from securenative.logger import Logger
5+
from securenative.models.sdk_event import SDKEvent
6+
from securenative.models.verify_result import VerifyResult
7+
8+
9+
class ApiManager(object):
10+
11+
def __init__(self, event_manager, securenative_options):
12+
self.event_manager = event_manager
13+
self.options = securenative_options
14+
15+
def track(self, event_options):
16+
Logger.debug("Track event call")
17+
event = SDKEvent(event_options, self.options)
18+
self.event_manager.send_async(event, ApiRoute.TRACK, True)
19+
20+
def verify(self, event_options):
21+
Logger.debug("Verify event call")
22+
event = SDKEvent(event_options, self.options)
23+
try:
24+
self.event_manager.send_sync(VerifyResult, event, ApiRoute.VERIFY)
25+
except Exception as e:
26+
Logger.debug("Failed to call verify; {}".format(e))
27+
if self.options.fail_over_startegy is FailOverStrategy.FAIL_OPEN:
28+
return VerifyResult(RiskLevel.LOW, 0, None)
29+
return VerifyResult(RiskLevel.HIGH, 1, None)

securenative/event_manager.py

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,50 @@
1+
import copy
12
import json
23
import threading
3-
import copy
4+
import time
45

5-
from securenative.http.http_client import HttpClient
6-
from securenative.sdk_options import SecureNativeOptions
6+
from securenative.config.securenative_options import SecureNativeOptions
7+
from securenative.exceptions.securenative_http_exception import SecureNativeHttpException
8+
from securenative.http.securenative_http_client import SecureNativeHttpClient
9+
from securenative.logger import Logger
710

811

912
class QueueItem:
10-
def __init__(self, url, body):
13+
def __init__(self, url, body, retry):
1114
self.url = url
1215
self.body = body
16+
self.retry = retry
1317

1418

1519
class EventManager:
16-
def __init__(self, api_key, options=SecureNativeOptions(), http_client=HttpClient()):
17-
if api_key is None:
20+
def __init__(self, options=SecureNativeOptions(), http_client=None):
21+
if options.api_url is None:
1822
raise ValueError('API key cannot be None, please get your API key from SecureNative console.')
1923

20-
self.http_client = http_client
21-
self.api_key = api_key
24+
if not http_client:
25+
self.http_client = SecureNativeHttpClient(options)
26+
else:
27+
self.http_client = http_client
28+
2229
self.options = options
2330
self.queue = list()
31+
self.send_enabled = False
32+
self.attempt = 0
33+
self.coefficients = [1, 1, 2, 3, 5, 8, 13]
2434

25-
if self.options.auto_send and self.options.is_sdk_enabled:
35+
if self.options.auto_send and not self.options.disable:
2636
interval_seconds = max(options.interval // 1000, 1)
2737
threading.Timer(interval_seconds, self.flush).start()
2838

2939
def send_async(self, event, resource_path):
40+
if self.options.disable:
41+
Logger.warn("SDK is disabled. no operation will be performed")
42+
return
43+
3044
item = QueueItem(
31-
self._build_url(resource_path),
32-
json.dumps(event.as_dict())
45+
resource_path,
46+
json.dumps(event.as_dict()),
47+
False
3348
)
3449

3550
self.queue.insert(0, item)
@@ -41,17 +56,70 @@ def flush(self):
4156
self.queue = list()
4257

4358
for item in queue_copy:
44-
self.http_client.post(item.url, self.api_key, item.body)
59+
self.http_client.post(item.url, item.body)
60+
61+
def send_sync(self, event, resource_path, retry):
62+
if self.options.disable:
63+
Logger.warn("SDK is disabled. no operation will be performed")
64+
return
4565

46-
def send_sync(self, event, resources_path):
47-
return self.http_client.post(
48-
self._build_url(resources_path),
49-
self.api_key,
66+
Logger.debug("Attempting to send event {}".format(event.as_dict()))
67+
res = self.http_client.post(
68+
resource_path,
5069
json.dumps(event.as_dict())
5170
)
71+
if res.status != 200:
72+
Logger.info("SecureNative failed to call endpoint {} with event {}. adding back to queue")
5273

53-
def _build_url(self, resource_path):
54-
return self.options.api_url + "/" + resource_path
74+
item = QueueItem(
75+
resource_path,
76+
json.dumps(event.as_dict()),
77+
retry
78+
)
79+
self.queue.insert(0, item)
80+
if self._is_queue_full():
81+
self.queue = self.queue[:len(self.queue - 1)]
5582

5683
def _is_queue_full(self):
5784
return len(self.queue) > self.options.max_events
85+
86+
def _send_events(self):
87+
if len(self.queue) > 0 and self.send_enabled:
88+
for item in self.queue:
89+
try:
90+
res = self.http_client.post(item.url, item.body)
91+
if res.status is 401:
92+
item.retry = False
93+
elif res.status != 200:
94+
raise SecureNativeHttpException(res.status)
95+
96+
Logger.debug("Event successfully sent; {}".format(item.body))
97+
self.queue.remove(item)
98+
except Exception as e:
99+
Logger.error("Failed to send event; {}".format(e))
100+
if item.retry:
101+
if len(self.coefficients) == self.attempt + 1:
102+
self.attempt = 0
103+
104+
back_off = self.coefficients[self.attempt] * self.options.interval
105+
Logger.debug("Automatic back-off of {}".format(back_off))
106+
self.send_enabled = False
107+
time.sleep(back_off)
108+
self.send_enabled = True
109+
else:
110+
self.queue.remove(item)
111+
112+
def start_event_persist(self):
113+
Logger.debug("Starting automatic event persistence")
114+
if self.options.auto_send or self.send_enabled:
115+
self.send_enabled = True
116+
# TODO add scheduler
117+
else:
118+
Logger.debug("Automatic event persistence is disabled, you should persist events manually")
119+
120+
def stop_event_persist(self):
121+
if self.send_enabled:
122+
Logger.debug("Attempting to stop automatic event persistence")
123+
# TODO shut down scheduler
124+
125+
Logger.debug("Stopped event persistence")

securenative/logger.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import logging
22

3-
enable_sn_logging = False
43

4+
class Logger(object): # TODO!
55

6-
def sn_logging(msg):
7-
if enable_sn_logging:
6+
@staticmethod
7+
def init_logger(level):
8+
pass
9+
10+
@staticmethod
11+
def info(msg):
812
logging.info(msg)
13+
14+
@staticmethod
15+
def debug(msg):
16+
pass
17+
18+
@staticmethod
19+
def warn(msg):
20+
pass
21+
22+
@staticmethod
23+
def error(msg):
24+
pass

securenative/models/verify_result.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class VerifyRequest(object):
1+
class VerifyResult(object):
22

33
def __init__(self, risk_level=None, score=None, triggers=None):
44
self.risk_level = risk_level

securenative/sdk.py

Lines changed: 0 additions & 66 deletions
This file was deleted.

securenative/securenative.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
from securenative.api_manager import ApiManager
2+
from securenative.config.configuration_builder import ConfigurationBuilder
3+
from securenative.config.configuration_manager import ConfigurationManager
4+
from securenative.context.context_builder import ContextBuilder
5+
from securenative.event_manager import EventManager
6+
from securenative.exceptions.securenative_config_exception import SecureNativeConfigException
7+
from securenative.exceptions.securenative_sdk_exception import SecureNativeSDKException
8+
from securenative.logger import Logger
9+
from securenative.utils.utils import Utils
10+
11+
12+
class SecureNative:
13+
14+
def __init__(self, options):
15+
if Utils.is_null_or_empty(options.api_key):
16+
raise SecureNativeSDKException("You must pass your SecureNative api key")
17+
18+
self._options = options
19+
self._event_manager = EventManager(self._options)
20+
21+
if self._options.api_url:
22+
self._event_manager.start_event_persist()
23+
24+
self._api_manager = ApiManager(self._event_manager, self._options)
25+
self._securenative = None
26+
Logger.init_logger(self._options.log_level)
27+
28+
def init(self, options):
29+
if self._securenative is None:
30+
self._securenative = SecureNative(options)
31+
return self._securenative
32+
else:
33+
Logger.debug('This SDK was already initialized.')
34+
raise SecureNativeSDKException(u'This SDK was already initialized.')
35+
36+
def init(self, api_key):
37+
if Utils.is_null_or_empty(api_key):
38+
raise SecureNativeConfigException("You must pass your SecureNative api key")
39+
40+
if self._securenative is None:
41+
builder = ConfigurationBuilder().default_config_builder()
42+
options = builder.with_api_key(api_key)
43+
self._securenative = SecureNative(options)
44+
return self._securenative
45+
else:
46+
Logger.debug('This SDK was already initialized.')
47+
raise SecureNativeSDKException(u'This SDK was already initialized.')
48+
49+
def init(self):
50+
options = ConfigurationManager.load_config()
51+
return self.init(options)
52+
53+
def get_instance(self):
54+
return self._securenative
55+
56+
def get_options(self):
57+
return self._options
58+
59+
@staticmethod
60+
def config_builder():
61+
return ConfigurationBuilder.default_config_builder()
62+
63+
@staticmethod
64+
def context_builder():
65+
return ContextBuilder.default_context_builder()
66+
67+
def track(self, event_options):
68+
self._api_manager.track(event_options)
69+
70+
def verify(self, event_options):
71+
self._api_manager.verify(event_options)

0 commit comments

Comments
 (0)