1+ import copy
12import json
23import 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
912class 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
1519class 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" )
0 commit comments