14
14
#
15
15
# for additional information, contact:
16
16
17
+ import uuid
17
18
18
19
import requests
19
20
20
- from typing import Iterator , List
21
+ from typing import Iterator , List , Optional , Tuple
21
22
from warnings import warn
22
23
23
24
from epl .protobuf .v1 import stac_pb2
29
30
30
31
31
32
class NSLClient :
32
- def __init__ (self , nsl_only = True ):
33
+ def __init__ (self , nsl_only = True , nsl_id = None , profile_name = None ):
33
34
"""
34
35
Create a client connection to a gRPC STAC service. nsl_only limits all queries to only return data from Near
35
36
Space Labs.
36
37
:param nsl_only:
37
38
"""
38
39
self ._stac_service = stac_singleton
39
40
self ._nsl_only = nsl_only
41
+ if profile_name :
42
+ nsl_id = bearer_auth ._get_auth_info (profile_name = profile_name ).nsl_id
43
+ if nsl_id :
44
+ bearer_auth ._default_nsl_id = nsl_id
40
45
41
46
@property
42
47
def default_nsl_id (self ):
@@ -67,7 +72,8 @@ def search_one(self,
67
72
stac_request : stac_pb2 .StacRequest ,
68
73
timeout = 15 ,
69
74
nsl_id : str = None ,
70
- profile_name : str = None ) -> stac_pb2 .StacItem :
75
+ profile_name : str = None ,
76
+ correlation_id : str = None ) -> stac_pb2 .StacItem :
71
77
"""
72
78
search for one item from the db that matches the stac request
73
79
:param timeout: timeout for request
@@ -77,20 +83,23 @@ def search_one(self,
77
83
NSLClient object's set_credentials to set credentials
78
84
:param profile_name: if a ~/.nsl/credentials file exists, you can override the [default] credential usage, by
79
85
using a different profile name
86
+ :param correlation_id: is a unique identifier that is added to the very first interaction (incoming request)
87
+ to identify the context and is passed to all components that are involved in the transaction flow
80
88
:return: StacItem
81
89
"""
82
90
# limit to only search Near Space Labs SWIFT data
83
91
if self ._nsl_only :
84
92
stac_request .mission_enum = stac_pb2 .SWIFT
85
93
86
- metadata = (( 'authorization' , bearer_auth . auth_header (nsl_id = nsl_id , profile_name = profile_name )), )
94
+ metadata = self . _grpc_headers (nsl_id , profile_name , correlation_id )
87
95
return self ._stac_service .stub .SearchOneItem (stac_request , timeout = timeout , metadata = metadata )
88
96
89
97
def count (self ,
90
98
stac_request : stac_pb2 .StacRequest ,
91
99
timeout = 15 ,
92
100
nsl_id : str = None ,
93
- profile_name : str = None ) -> int :
101
+ profile_name : str = None ,
102
+ correlation_id : str = None ) -> int :
94
103
"""
95
104
count all the items in the database that match the stac request
96
105
:param timeout: timeout for request
@@ -100,13 +109,15 @@ def count(self,
100
109
NSLClient object's set_credentials to set credentials
101
110
:param profile_name: if a ~/.nsl/credentials file exists, you can override the [default] credential usage, by
102
111
using a different profile name
112
+ :param correlation_id: is a unique identifier that is added to the very first interaction (incoming request)
113
+ to identify the context and is passed to all components that are involved in the transaction flow
103
114
:return: int
104
115
"""
105
116
# limit to only search Near Space Labs SWIFT data
106
117
if self ._nsl_only :
107
118
stac_request .mission_enum = stac_pb2 .SWIFT
108
119
109
- metadata = (( 'authorization' , bearer_auth . auth_header (nsl_id = nsl_id , profile_name = profile_name )), )
120
+ metadata = self . _grpc_headers (nsl_id , profile_name , correlation_id )
110
121
db_result = self ._stac_service .stub .CountItems (stac_request , timeout = timeout , metadata = metadata )
111
122
if db_result .status :
112
123
# print db_result
@@ -119,7 +130,9 @@ def search(self,
119
130
nsl_id : str = None ,
120
131
profile_name : str = None ,
121
132
auto_paginate : bool = False ,
122
- only_accessible : bool = False ) -> Iterator [stac_pb2 .StacItem ]:
133
+ only_accessible : bool = False ,
134
+ page_size : int = 50 ,
135
+ correlation_id : str = None ) -> Iterator [stac_pb2 .StacItem ]:
123
136
"""
124
137
search for stac items by using StacRequest. return a stream of StacItems
125
138
:param timeout: timeout for request
@@ -136,13 +149,16 @@ def search(self,
136
149
- If set to `False` (the default), `stac_request.limit` and `stac_request.offset` can be used to manually
137
150
page through StacItems.
138
151
:param only_accessible: limits results to only StacItems downloadable by your level of sample/paid access
152
+ :param page_size: how many results to page at a time
139
153
:return: stream of StacItems
140
154
"""
141
155
for item in self ._search_all (stac_request ,
142
156
timeout ,
143
157
nsl_id = nsl_id ,
144
158
profile_name = profile_name ,
145
- auto_paginate = auto_paginate ):
159
+ auto_paginate = auto_paginate ,
160
+ page_size = page_size ,
161
+ correlation_id = correlation_id ):
146
162
if not only_accessible or \
147
163
bearer_auth .is_valid_for (item_region (item ), nsl_id = nsl_id , profile_name = profile_name ):
148
164
yield item
@@ -151,8 +167,10 @@ def search_collections(self,
151
167
collection_request : stac_pb2 .CollectionRequest ,
152
168
timeout = 15 ,
153
169
nsl_id : str = None ,
154
- profile_name : str = None ) -> Iterator [stac_pb2 .Collection ]:
155
- metadata = (('authorization' , bearer_auth .auth_header (nsl_id = nsl_id , profile_name = profile_name )),)
170
+ profile_name : str = None ,
171
+ correlation_id : str = None ) -> Iterator [stac_pb2 .Collection ]:
172
+
173
+ metadata = self ._grpc_headers (nsl_id , profile_name , correlation_id )
156
174
for item in self ._stac_service .stub .SearchCollections (collection_request , timeout = timeout , metadata = metadata ):
157
175
yield item
158
176
@@ -173,7 +191,7 @@ def subscribe(self,
173
191
if self ._nsl_only :
174
192
stac_request .mission_enum = stac_pb2 .SWIFT
175
193
res = requests .post (f'{ AUTH0_TENANT } /subscription' ,
176
- headers = NSLClient ._json_headers (nsl_id , profile_name ),
194
+ headers = self ._json_headers (nsl_id , profile_name ),
177
195
json = dict (stac_request = utils .stac_request_to_b64 (stac_request ),
178
196
destination = destination .to_json_str (),
179
197
is_active = is_active ))
@@ -186,7 +204,7 @@ def subscribe(self,
186
204
def resubscribe (self , sub_id : str , nsl_id : str = None , profile_name : str = None ):
187
205
"""Reactivates a subscription with the given `sub_id`."""
188
206
res = requests .put (f'{ AUTH0_TENANT } /subscription/{ sub_id } ' ,
189
- headers = NSLClient ._json_headers (nsl_id , profile_name ))
207
+ headers = self ._json_headers (nsl_id , profile_name ))
190
208
191
209
NSLClient ._handle_json_response (res , 200 )
192
210
print (f'reactivated subscription with id: { sub_id } ' )
@@ -195,7 +213,7 @@ def resubscribe(self, sub_id: str, nsl_id: str = None, profile_name: str = None)
195
213
def unsubscribe (self , sub_id : str , nsl_id : str = None , profile_name : str = None ):
196
214
"""Deactivates a subscription with the given `sub_id`."""
197
215
res = requests .delete (f'{ AUTH0_TENANT } /subscription/{ sub_id } ' ,
198
- headers = NSLClient ._json_headers (nsl_id , profile_name ))
216
+ headers = self ._json_headers (nsl_id , profile_name ))
199
217
200
218
NSLClient ._handle_json_response (res , 202 )
201
219
print (f'deactivated subscription with id: { sub_id } ' )
@@ -204,7 +222,7 @@ def unsubscribe(self, sub_id: str, nsl_id: str = None, profile_name: str = None)
204
222
def subscriptions (self , nsl_id : str = None , profile_name : str = None ) -> List [Subscription ]:
205
223
"""Fetches all subscriptions."""
206
224
res = requests .get (f'{ AUTH0_TENANT } /subscription' ,
207
- headers = NSLClient ._json_headers (nsl_id , profile_name ))
225
+ headers = self ._json_headers (nsl_id , profile_name ))
208
226
209
227
NSLClient ._handle_json_response (res , 200 )
210
228
return list (Subscription (response_dict ) for response_dict in res .json ()['results' ])
@@ -214,48 +232,63 @@ def _search_all(self,
214
232
timeout = 15 ,
215
233
nsl_id : str = None ,
216
234
profile_name : str = None ,
217
- auto_paginate : bool = False ) -> Iterator [stac_pb2 .StacItem ]:
235
+ auto_paginate : bool = False ,
236
+ page_size : int = 50 ,
237
+ correlation_id : str = None ) -> Iterator [stac_pb2 .StacItem ]:
218
238
# limit to only search Near Space Labs SWIFT data
219
239
if self ._nsl_only :
220
240
stac_request .mission_enum = stac_pb2 .SWIFT
221
241
222
242
if not auto_paginate :
223
- metadata = (( 'authorization' , bearer_auth . auth_header (nsl_id = nsl_id , profile_name = profile_name )), )
243
+ metadata = self . _grpc_headers (nsl_id , profile_name , correlation_id )
224
244
for item in self ._stac_service .stub .SearchItems (stac_request , timeout = timeout , metadata = metadata ):
225
245
if not item .id :
226
- warn ("STAC item missing STAC id; ending search" )
246
+ warn (f "STAC item missing STAC id: \n { item } ; \n ending search" )
227
247
return
228
248
else :
229
249
yield item
230
250
else :
231
- limit = stac_request .limit if stac_request .limit > 0 else None
251
+ original_limit = stac_request .limit if stac_request .limit > 0 else None
232
252
offset = stac_request .offset
233
- page_size = 500
234
253
count = 0
235
254
236
- stac_request .limit = page_size
237
- items = list (self .search (stac_request , timeout = timeout , nsl_id = nsl_id , profile_name = profile_name ))
255
+ stac_request .limit = page_size if original_limit is None else max (original_limit , page_size )
256
+ items = list (self ._search_all (stac_request , timeout = timeout ,
257
+ nsl_id = nsl_id , profile_name = profile_name ,
258
+ page_size = page_size , correlation_id = correlation_id ))
238
259
while len (items ) > 0 :
239
260
for item in items :
240
- if limit is None or (limit is not None and count < limit ):
261
+ if original_limit is None or (original_limit is not None and count < original_limit ):
241
262
yield item
242
263
count += 1
243
- if limit is not None and count >= limit :
264
+ if original_limit is not None and count >= original_limit :
244
265
break
245
266
246
- if limit is not None and count >= limit :
267
+ if original_limit is not None and count >= original_limit :
247
268
break
248
269
249
- stac_request .offset += page_size
250
- items = list (self .search (stac_request , timeout = timeout , nsl_id = nsl_id , profile_name = profile_name ))
270
+ stac_request .offset += len (items )
271
+ items = list (self ._search_all (stac_request , timeout = timeout ,
272
+ nsl_id = nsl_id , profile_name = profile_name ,
273
+ page_size = page_size , correlation_id = correlation_id ))
251
274
252
275
stac_request .offset = offset
253
- stac_request .limit = limit if limit is not None else 0
254
-
255
- @staticmethod
256
- def _json_headers (nsl_id : str = None , profile_name : str = None ) -> dict :
257
- return {'content-type' : 'application/json' ,
258
- 'Authorization' : bearer_auth .auth_header (nsl_id = nsl_id , profile_name = profile_name )}
276
+ stac_request .limit = original_limit if original_limit is not None else 0
277
+
278
+ def _json_headers (self ,
279
+ nsl_id : str = None ,
280
+ profile_name : str = None ,
281
+ correlation_id : str = None ) -> dict :
282
+ headers = {k : v for (k , v ) in self ._grpc_headers (nsl_id , profile_name , correlation_id )}
283
+ return {'content-type' : 'application/json' , ** headers }
284
+
285
+ def _grpc_headers (self ,
286
+ nsl_id : str = None ,
287
+ profile_name : str = None ,
288
+ correlation_id : str = None ) -> Tuple [Tuple [str , str ], ...]:
289
+ correlation_id = str (uuid .uuid4 ()) if correlation_id is None else correlation_id
290
+ return (('x-correlation-id' , correlation_id ),
291
+ ('authorization' , bearer_auth .auth_header (nsl_id = nsl_id , profile_name = profile_name )))
259
292
260
293
@staticmethod
261
294
def _handle_json_response (res , status_code : int ):
0 commit comments