Skip to content

Commit c175dda

Browse files
Merge pull request #16 from BenjamenMeyer/enhancement_session_data
Enhancement session data
2 parents 8efd1c9 + 17a20d2 commit c175dda

5 files changed

Lines changed: 429 additions & 20 deletions

File tree

stackinawsgi/admin/admin.py

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
"""
22
Stack-In-A-WSGI: StackInAWsgiAdmin
33
"""
4+
import json
45
import logging
6+
import re
57

68
from stackinabox.services.service import StackInABoxService
79

810
from stackinawsgi.exceptions import InvalidSessionId
11+
from stackinawsgi.session.service import (
12+
global_sessions,
13+
session_regex
14+
)
915

1016

1117
logger = logging.getLogger(__name__)
@@ -29,6 +35,12 @@ def __init__(self, session_manager, base_uri):
2935
self.manager = session_manager
3036
self.base_uri = base_uri
3137

38+
self.register(
39+
StackInABoxService.GET,
40+
re.compile('^{0}$'.format(session_regex)),
41+
StackInAWsgiAdmin.get_session_info
42+
)
43+
3244
self.register(
3345
StackInABoxService.DELETE, '/', StackInAWsgiAdmin.remove_session
3446
)
@@ -39,7 +51,7 @@ def __init__(self, session_manager, base_uri):
3951
StackInABoxService.PUT, '/', StackInAWsgiAdmin.reset_session
4052
)
4153
self.register(
42-
StackInABoxService.GET, '/', StackInAWsgiAdmin.get_session_info
54+
StackInABoxService.GET, '/', StackInAWsgiAdmin.get_sessions
4355
)
4456

4557
@property
@@ -84,6 +96,30 @@ def helper_get_session_id(self, headers):
8496
logger.debug('Found Session Id: {0}'.format(session_id))
8597
return session_id
8698

99+
def helper_get_session_id_from_uri(self, uri):
100+
"""
101+
Helper to retrieve the Session-ID FROM a URI
102+
103+
:param text_type uri: complete URI
104+
:returns: text_type with the session-id
105+
"""
106+
matcher = re.compile(session_regex)
107+
try:
108+
matched_groups = matcher.match(uri)
109+
session_id = matched_groups.group(0)[1:]
110+
logger.debug(
111+
'Helper Get Session From URI - URI: "{0}", '
112+
'Session ID: "{1}"'.format(
113+
uri,
114+
session_id
115+
)
116+
)
117+
118+
except Exception:
119+
logger.exception('Failed to find session-id')
120+
session_id = None
121+
return session_id
122+
87123
def helper_get_uri(self, session_id):
88124
"""
89125
Helper to build the session URL
@@ -214,10 +250,78 @@ def get_session_info(self, request, uri, headers):
214250
:returns: tuple for StackInABox HTTP Response
215251
216252
HTTP Request:
217-
GET /admin/
253+
GET /admin/{X-Session-ID}
218254
X-Session-ID: (Required) Session-ID to reset
219255
220256
HTTP Responses:
221-
500 - Not Implemented
257+
200 - Session Data in JSON format
258+
"""
259+
requested_session_id = self.helper_get_session_id_from_uri(
260+
uri
261+
)
262+
263+
session_info = {
264+
'session_valid': requested_session_id in global_sessions,
265+
'created-time': None,
266+
'accessed-time': None,
267+
'accessed-count': 0,
268+
'http-status': {}
269+
}
270+
271+
if session_info['session_valid']:
272+
session = global_sessions[requested_session_id]
273+
session_info['created-time'] = session.created_at.isoformat()
274+
session_info['accessed-time'] = (
275+
session.last_accessed_at.isoformat()
276+
)
277+
session_info['accessed-count'] = session.access_count
278+
session_info['http-status'] = session.status_tracker
279+
280+
data = {
281+
'base_url': self.base_uri,
282+
'services': {
283+
svc().name: svc.__name__
284+
for svc in self.manager.services
285+
},
286+
'trackers': {
287+
'created-time': session_info['created-time'],
288+
'accessed': {
289+
'time': session_info['accessed-time'],
290+
'count': session_info['accessed-count']
291+
},
292+
'status': session_info['http-status']
293+
},
294+
'session_valid': session_info['session_valid']
295+
}
296+
297+
return (200, headers, json.dumps(data))
298+
299+
def get_sessions(self, request, uri, headers):
300+
"""
301+
Get Session List - TBD
302+
303+
:param :obj:`Request` request: object containing the HTTP Request
304+
:param text_type uri: the URI for the request per StackInABox
305+
:param dict headers: case insensitive header dictionary
306+
307+
:returns: tuple for StackInABox HTTP Response
308+
309+
HTTP Request:
310+
GET /admin/
311+
312+
HTTP Responses:
313+
200 - Session List in JSON format
222314
"""
223-
return (500, headers, 'Not Implemented')
315+
data = {
316+
'base_url': self.base_uri,
317+
'services': {
318+
svc().name: svc.__name__
319+
for svc in self.manager.services
320+
},
321+
'sessions': [
322+
requested_session_id
323+
for requested_session_id in global_sessions
324+
]
325+
}
326+
327+
return (200, headers, json.dumps(data))

stackinawsgi/session/service.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
# must be able to be pickled, which we can't guarantee. So
2222
# we're stuck with threading.
2323
global_sessions = dict()
24+
session_regex = '^\/([\w-]+)'
25+
session_regex_instance = '{0}\/.*'.format(session_regex)
2426

2527

2628
logger = logging.getLogger(__name__)
@@ -66,7 +68,7 @@ def extract_session_id(uri):
6668
uri
6769
)
6870
)
69-
matcher = re.compile('^\/([\w-]+)\/.*')
71+
matcher = re.compile(session_regex_instance)
7072

7173
matches = matcher.match(uri)
7274
if matches:
@@ -128,6 +130,8 @@ def create_session(self, session_id=None):
128130
129131
:returns: text_type with the session id
130132
"""
133+
global global_sessions
134+
131135
logger.debug(
132136
'Requesting creation of session. Optional Session Id: {0}'.format(
133137
session_id
@@ -199,6 +203,8 @@ def remove_session(self, session_id):
199203
200204
:raises: InvalidSessionId if session id is not found
201205
"""
206+
global global_sessions
207+
202208
if session_id in global_sessions:
203209
del global_sessions[session_id]
204210
else:

stackinawsgi/session/session.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
from __future__ import absolute_import
55

6+
import datetime
67
import logging
78
from threading import Lock
89

@@ -58,6 +59,52 @@ def __init__(self, session_id, services):
5859
self.stack = StackInABox()
5960
self.stack.base_url = self.session_id
6061
self.init_services()
62+
self.created_at = datetime.datetime.utcnow()
63+
self._last_accessed_time = self.created_at
64+
self._access_count = 0
65+
self._http_status_dict = {}
66+
67+
def _update_trackers(self):
68+
"""
69+
Update the session trackers
70+
"""
71+
self._access_count = self._access_count + 1
72+
self._last_accessed_time = datetime.datetime.utcnow()
73+
74+
def _track_result(self, result):
75+
"""
76+
Track the results from StackInABox
77+
"""
78+
status, _, _ = result
79+
if status not in self._http_status_dict:
80+
self._http_status_dict[status] = 0
81+
82+
self._http_status_dict[status] = (
83+
self._http_status_dict[status] + 1
84+
)
85+
86+
return result
87+
88+
@property
89+
def last_accessed_at(self):
90+
"""
91+
Return the time the session was last accessed
92+
"""
93+
return self._last_accessed_time
94+
95+
@property
96+
def access_count(self):
97+
"""
98+
Return the number of times the session has been called
99+
"""
100+
return self._access_count
101+
102+
@property
103+
def status_tracker(self):
104+
"""
105+
Return the current copy of HTTP Status Code Trackers
106+
"""
107+
return self._http_status_dict
61108

62109
def init_services(self):
63110
"""
@@ -72,6 +119,7 @@ def init_services(self):
72119
)
73120
)
74121
self.stack.register(svc)
122+
self._http_status_dict = {}
75123

76124
@property
77125
def base_url(self):
@@ -104,6 +152,7 @@ def reset(self):
104152
Reset the StackInABox instance to the initial state by
105153
resetting the instance then re-registering all the services.
106154
"""
155+
self._update_trackers()
107156
logger.debug(
108157
'Session {0}: Waiting for lock'.format(
109158
self.session_id
@@ -123,6 +172,7 @@ def call(self, *args, **kwargs):
123172
"""
124173
Wrapper to same in the StackInABox instance
125174
"""
175+
self._update_trackers()
126176
logger.debug(
127177
'Session {0}: Waiting for lock'.format(
128178
self.session_id
@@ -135,12 +185,15 @@ def call(self, *args, **kwargs):
135185
)
136186
)
137187

138-
return self.stack.call(*args, **kwargs)
188+
return self._track_result(
189+
self.stack.call(*args, **kwargs)
190+
)
139191

140192
def try_handle_route(self, *args, **kwargs):
141193
"""
142194
Wrapper to same in the StackInABox instance
143195
"""
196+
self._update_trackers()
144197
logger.debug(
145198
'Session {0}: Waiting for lock'.format(
146199
self.session_id
@@ -153,12 +206,15 @@ def try_handle_route(self, *args, **kwargs):
153206
)
154207
)
155208

156-
return self.stack.try_handle_route(*args, **kwargs)
209+
return self._track_result(
210+
self.stack.try_handle_route(*args, **kwargs)
211+
)
157212

158213
def request(self, *args, **kwargs):
159214
"""
160215
Wrapper to same in the StackInABox instance
161216
"""
217+
self._update_trackers()
162218
logger.debug(
163219
'Session {0}: Waiting for lock'.format(
164220
self.session_id
@@ -171,12 +227,15 @@ def request(self, *args, **kwargs):
171227
)
172228
)
173229

174-
return self.stack.request(*args, **kwargs)
230+
return self._track_result(
231+
self.stack.request(*args, **kwargs)
232+
)
175233

176234
def sub_request(self, *args, **kwargs):
177235
"""
178236
Pass-thru to the StackInABox instance's sub_request
179237
"""
238+
self._update_trackers()
180239
logger.debug(
181240
'Session {0}: Waiting for lock'.format(
182241
self.session_id
@@ -189,4 +248,6 @@ def sub_request(self, *args, **kwargs):
189248
)
190249
)
191250

192-
return self.stack.sub_request(*args, **kwargs)
251+
return self._track_result(
252+
self.stack.sub_request(*args, **kwargs)
253+
)

0 commit comments

Comments
 (0)