elements-api 2025.11.4__py3-none-any.whl
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.
- elements_api/__init__.py +8 -0
- elements_api/async_client.py +43 -0
- elements_api/async_interceptors.py +105 -0
- elements_api/elements_base_api.py +454 -0
- elements_api/models/__init__.py +47 -0
- elements_api/models/algorithm_computation_execution_pb2.py +48 -0
- elements_api/models/algorithm_computation_execution_pb2.pyi +84 -0
- elements_api/models/algorithm_computation_pb2.py +61 -0
- elements_api/models/algorithm_computation_pb2.pyi +134 -0
- elements_api/models/algorithm_config_pb2.py +90 -0
- elements_api/models/algorithm_config_pb2.pyi +185 -0
- elements_api/models/algorithm_manifest_pb2.py +43 -0
- elements_api/models/algorithm_manifest_pb2.pyi +25 -0
- elements_api/models/algorithm_pb2.py +57 -0
- elements_api/models/algorithm_pb2.pyi +96 -0
- elements_api/models/algorithm_version_pb2.py +88 -0
- elements_api/models/algorithm_version_pb2.pyi +233 -0
- elements_api/models/analysis_computation_pb2.py +69 -0
- elements_api/models/analysis_computation_pb2.pyi +159 -0
- elements_api/models/analysis_config_pb2.py +127 -0
- elements_api/models/analysis_config_pb2.pyi +180 -0
- elements_api/models/analysis_pb2.py +57 -0
- elements_api/models/analysis_pb2.pyi +98 -0
- elements_api/models/analysis_version_pb2.py +77 -0
- elements_api/models/analysis_version_pb2.pyi +141 -0
- elements_api/models/aoi_catalog_pb2.py +71 -0
- elements_api/models/aoi_catalog_pb2.pyi +162 -0
- elements_api/models/aoi_collection_pb2.py +67 -0
- elements_api/models/aoi_collection_pb2.pyi +146 -0
- elements_api/models/aoi_export_pb2.py +48 -0
- elements_api/models/aoi_export_pb2.pyi +62 -0
- elements_api/models/aoi_pb2.py +66 -0
- elements_api/models/aoi_pb2.pyi +191 -0
- elements_api/models/aoi_transaction_pb2.py +52 -0
- elements_api/models/aoi_transaction_pb2.pyi +56 -0
- elements_api/models/aoi_version_pb2.py +63 -0
- elements_api/models/aoi_version_pb2.pyi +171 -0
- elements_api/models/common_models_pb2.py +36 -0
- elements_api/models/common_models_pb2.pyi +15 -0
- elements_api/models/credit_pb2.py +79 -0
- elements_api/models/credit_pb2.pyi +216 -0
- elements_api/models/data_source_pb2.py +53 -0
- elements_api/models/data_source_pb2.pyi +86 -0
- elements_api/models/data_tracking_pb2.py +60 -0
- elements_api/models/data_tracking_pb2.pyi +127 -0
- elements_api/models/data_type_pb2.py +51 -0
- elements_api/models/data_type_pb2.pyi +74 -0
- elements_api/models/filter_pb2.py +63 -0
- elements_api/models/filter_pb2.pyi +133 -0
- elements_api/models/forgot_password_pb2.py +42 -0
- elements_api/models/forgot_password_pb2.pyi +19 -0
- elements_api/models/notification_pb2.py +82 -0
- elements_api/models/notification_pb2.pyi +180 -0
- elements_api/models/order_pb2.py +68 -0
- elements_api/models/order_pb2.pyi +181 -0
- elements_api/models/order_recommendation_pb2.py +53 -0
- elements_api/models/order_recommendation_pb2.pyi +99 -0
- elements_api/models/permission_pb2.py +84 -0
- elements_api/models/permission_pb2.pyi +177 -0
- elements_api/models/project_analysis_config_pb2.py +154 -0
- elements_api/models/project_analysis_config_pb2.pyi +76 -0
- elements_api/models/project_aoi_pb2.py +66 -0
- elements_api/models/project_aoi_pb2.pyi +118 -0
- elements_api/models/project_collaborator_pb2.py +54 -0
- elements_api/models/project_collaborator_pb2.pyi +74 -0
- elements_api/models/project_filter_pb2.py +55 -0
- elements_api/models/project_filter_pb2.pyi +61 -0
- elements_api/models/project_group_pb2.py +198 -0
- elements_api/models/project_group_pb2.pyi +119 -0
- elements_api/models/project_pb2.py +217 -0
- elements_api/models/project_pb2.pyi +314 -0
- elements_api/models/project_result_pb2.py +123 -0
- elements_api/models/project_result_pb2.pyi +221 -0
- elements_api/models/provider_quotas_pb2.py +42 -0
- elements_api/models/provider_quotas_pb2.pyi +33 -0
- elements_api/models/resource_pb2.py +64 -0
- elements_api/models/resource_pb2.pyi +133 -0
- elements_api/models/result_pb2.py +65 -0
- elements_api/models/result_pb2.pyi +158 -0
- elements_api/models/s3_pb2.py +52 -0
- elements_api/models/s3_pb2.pyi +49 -0
- elements_api/models/subject_pb2.py +36 -0
- elements_api/models/subject_pb2.pyi +11 -0
- elements_api/models/system_pb2.py +47 -0
- elements_api/models/system_pb2.pyi +28 -0
- elements_api/models/tasking_order_pb2.py +75 -0
- elements_api/models/tasking_order_pb2.pyi +156 -0
- elements_api/models/tile_pb2.py +52 -0
- elements_api/models/tile_pb2.pyi +77 -0
- elements_api/models/toi_pb2.py +67 -0
- elements_api/models/toi_pb2.pyi +138 -0
- elements_api/models/token_pb2.py +42 -0
- elements_api/models/token_pb2.pyi +23 -0
- elements_api/models/user_collection_pb2.py +78 -0
- elements_api/models/user_collection_pb2.pyi +172 -0
- elements_api/models/user_pb2.py +86 -0
- elements_api/models/user_pb2.pyi +183 -0
- elements_api/models/visualization_pb2.py +70 -0
- elements_api/models/visualization_pb2.pyi +187 -0
- elements_api/stubs/__init__.py +47 -0
- elements_api/stubs/algorithm_computation_execution_pb2_grpc.py +111 -0
- elements_api/stubs/algorithm_computation_pb2_grpc.py +251 -0
- elements_api/stubs/algorithm_config_pb2_grpc.py +377 -0
- elements_api/stubs/algorithm_manifest_pb2_grpc.py +99 -0
- elements_api/stubs/algorithm_pb2_grpc.py +239 -0
- elements_api/stubs/algorithm_version_pb2_grpc.py +336 -0
- elements_api/stubs/analysis_computation_pb2_grpc.py +239 -0
- elements_api/stubs/analysis_config_pb2_grpc.py +283 -0
- elements_api/stubs/analysis_pb2_grpc.py +192 -0
- elements_api/stubs/analysis_version_pb2_grpc.py +198 -0
- elements_api/stubs/aoi_catalog_pb2_grpc.py +273 -0
- elements_api/stubs/aoi_collection_pb2_grpc.py +327 -0
- elements_api/stubs/aoi_export_pb2_grpc.py +144 -0
- elements_api/stubs/aoi_pb2_grpc.py +241 -0
- elements_api/stubs/aoi_transaction_pb2_grpc.py +145 -0
- elements_api/stubs/aoi_version_pb2_grpc.py +192 -0
- elements_api/stubs/common_models_pb2_grpc.py +24 -0
- elements_api/stubs/credit_pb2_grpc.py +418 -0
- elements_api/stubs/data_source_pb2_grpc.py +144 -0
- elements_api/stubs/data_tracking_pb2_grpc.py +140 -0
- elements_api/stubs/data_type_pb2_grpc.py +189 -0
- elements_api/stubs/filter_pb2_grpc.py +234 -0
- elements_api/stubs/forgot_password_pb2_grpc.py +100 -0
- elements_api/stubs/notification_pb2_grpc.py +414 -0
- elements_api/stubs/order_pb2_grpc.py +279 -0
- elements_api/stubs/order_recommendation_pb2_grpc.py +183 -0
- elements_api/stubs/permission_pb2_grpc.py +282 -0
- elements_api/stubs/project_analysis_config_pb2_grpc.py +99 -0
- elements_api/stubs/project_aoi_pb2_grpc.py +279 -0
- elements_api/stubs/project_collaborator_pb2_grpc.py +189 -0
- elements_api/stubs/project_filter_pb2_grpc.py +144 -0
- elements_api/stubs/project_group_pb2_grpc.py +234 -0
- elements_api/stubs/project_pb2_grpc.py +504 -0
- elements_api/stubs/project_result_pb2_grpc.py +234 -0
- elements_api/stubs/provider_quotas_pb2_grpc.py +99 -0
- elements_api/stubs/resource_pb2_grpc.py +228 -0
- elements_api/stubs/result_pb2_grpc.py +99 -0
- elements_api/stubs/s3_pb2_grpc.py +99 -0
- elements_api/stubs/subject_pb2_grpc.py +24 -0
- elements_api/stubs/system_pb2_grpc.py +142 -0
- elements_api/stubs/tasking_order_pb2_grpc.py +279 -0
- elements_api/stubs/tile_pb2_grpc.py +99 -0
- elements_api/stubs/toi_pb2_grpc.py +281 -0
- elements_api/stubs/token_pb2_grpc.py +100 -0
- elements_api/stubs/user_collection_pb2_grpc.py +370 -0
- elements_api/stubs/user_pb2_grpc.py +559 -0
- elements_api/stubs/visualization_pb2_grpc.py +234 -0
- elements_api/sync_client.py +34 -0
- elements_api-2025.11.4.dist-info/METADATA +11 -0
- elements_api-2025.11.4.dist-info/RECORD +153 -0
- elements_api-2025.11.4.dist-info/WHEEL +5 -0
- elements_api-2025.11.4.dist-info/licenses/LICENSE +7 -0
- elements_api-2025.11.4.dist-info/top_level.txt +1 -0
elements_api/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Copyright 2017-2021 Orbital Insight Inc., all rights reserved.
|
|
2
|
+
# Contains confidential and trade secret information.
|
|
3
|
+
# Government Users: Commercial Computer Software - Use governed by
|
|
4
|
+
# terms of Orbital Insight commercial license agreement.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from elements_api.sync_client import ElementsSyncClient # noqa
|
|
8
|
+
from elements_api.async_client import ElementsAsyncClient # noqa
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright 2017-2021 Orbital Insight Inc., all rights reserved.
|
|
2
|
+
# Contains confidential and trade secret information.
|
|
3
|
+
# Government Users: Commercial Computer Software - Use governed by
|
|
4
|
+
# terms of Orbital Insight commercial license agreement.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
import grpc
|
|
8
|
+
from elements_api.elements_base_api import ElementsBaseApi
|
|
9
|
+
from elements_api import models
|
|
10
|
+
from elements_api.async_interceptors import (
|
|
11
|
+
ContextInjectorUnaryUnary, ContextInjectorStreamUnary, ContextInjectorUnaryStream, ContextInjectorStreamStream
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ElementsAsyncClient:
|
|
16
|
+
def __init__(self, oi_papi_url, port=443, secure=True, api_token=None, root_certificates_file=None):
|
|
17
|
+
self.api = ElementsAsyncApi(oi_papi_url, port, secure, api_token=api_token,
|
|
18
|
+
root_certificates_file=root_certificates_file)
|
|
19
|
+
self.models = models
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ElementsAsyncApi(ElementsBaseApi):
|
|
23
|
+
def __init__(self, oi_papi_url, port=443, secure=True, api_token=None, root_certificates_file=None):
|
|
24
|
+
self.context_injecting_interceptors = [
|
|
25
|
+
# materialize distributed context from request headers
|
|
26
|
+
ContextInjectorUnaryUnary(), ContextInjectorUnaryStream(),
|
|
27
|
+
ContextInjectorStreamUnary(), ContextInjectorStreamStream()
|
|
28
|
+
]
|
|
29
|
+
super(ElementsAsyncApi, self).__init__(oi_papi_url, port, secure, api_token,
|
|
30
|
+
root_certificates_file)
|
|
31
|
+
|
|
32
|
+
def _get_channel(self, channel_credentials: grpc.ChannelCredentials):
|
|
33
|
+
token_creds = grpc.access_token_call_credentials(self.access_token)
|
|
34
|
+
creds = grpc.composite_channel_credentials(channel_credentials, token_creds)
|
|
35
|
+
return grpc.aio.secure_channel(f"{self._oi_papi_url}:{self._port}",
|
|
36
|
+
creds,
|
|
37
|
+
options=self.options,
|
|
38
|
+
compression=None,
|
|
39
|
+
interceptors=self.context_injecting_interceptors)
|
|
40
|
+
|
|
41
|
+
# TODO: async destructor
|
|
42
|
+
def __adel__(self):
|
|
43
|
+
self._channel.close()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from typing import Callable, Union
|
|
3
|
+
|
|
4
|
+
import grpc
|
|
5
|
+
from grpc.aio import \
|
|
6
|
+
UnaryUnaryClientInterceptor, \
|
|
7
|
+
UnaryStreamClientInterceptor, \
|
|
8
|
+
StreamUnaryClientInterceptor, \
|
|
9
|
+
StreamStreamClientInterceptor, \
|
|
10
|
+
ClientCallDetails
|
|
11
|
+
from grpc.aio._call import \
|
|
12
|
+
UnaryUnaryCall, \
|
|
13
|
+
UnaryStreamCall, \
|
|
14
|
+
StreamUnaryCall, \
|
|
15
|
+
StreamStreamCall
|
|
16
|
+
|
|
17
|
+
from grpc.aio._typing import RequestType, ResponseIterableType, ResponseType, \
|
|
18
|
+
RequestIterableType
|
|
19
|
+
|
|
20
|
+
if importlib.util.find_spec('oi_tracing'):
|
|
21
|
+
from oi_tracing import inject_current_span
|
|
22
|
+
else:
|
|
23
|
+
def inject_current_span(_headers):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
if importlib.util.find_spec('mercury_client'):
|
|
27
|
+
from mercury_client.context import context_as_dict
|
|
28
|
+
else:
|
|
29
|
+
def context_as_dict():
|
|
30
|
+
return {}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def inject_current_context_into_header(client_call_details: ClientCallDetails)\
|
|
34
|
+
-> ClientCallDetails:
|
|
35
|
+
|
|
36
|
+
if client_call_details.metadata is None: # grpc.aio._metadata.Metadata
|
|
37
|
+
client_call_details.metadata = grpc.aio._metadata.Metadata()
|
|
38
|
+
|
|
39
|
+
new_headers = context_as_dict()
|
|
40
|
+
# Remove any Auth headers and let this be controlled by Papi's token setting
|
|
41
|
+
for key in ('Authorization', 'X-Orbitalinsight-Auth-Token'):
|
|
42
|
+
new_headers.pop(key, None)
|
|
43
|
+
|
|
44
|
+
inject_current_span(new_headers)
|
|
45
|
+
# inject_current_auth(new_headers)
|
|
46
|
+
|
|
47
|
+
for k, v in new_headers.items():
|
|
48
|
+
client_call_details.metadata.add(k, str(v))
|
|
49
|
+
# todo not clear if it is safe to modify or a new copy needs to be made
|
|
50
|
+
# at this point returning modified original object
|
|
51
|
+
return client_call_details
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ContextInjectorUnaryUnary(UnaryUnaryClientInterceptor):
|
|
55
|
+
|
|
56
|
+
async def intercept_unary_unary(
|
|
57
|
+
self, continuation: Callable[[ClientCallDetails, RequestType],
|
|
58
|
+
UnaryUnaryCall],
|
|
59
|
+
client_call_details: ClientCallDetails,
|
|
60
|
+
request: RequestType) \
|
|
61
|
+
-> Union[UnaryUnaryCall, ResponseType]:
|
|
62
|
+
new_details = inject_current_context_into_header(client_call_details)
|
|
63
|
+
response = continuation(new_details, request)
|
|
64
|
+
return await response
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ContextInjectorUnaryStream(UnaryStreamClientInterceptor):
|
|
68
|
+
|
|
69
|
+
async def intercept_unary_stream(
|
|
70
|
+
self,
|
|
71
|
+
continuation: Callable[[ClientCallDetails, RequestType],
|
|
72
|
+
UnaryStreamCall],
|
|
73
|
+
client_call_details: ClientCallDetails,
|
|
74
|
+
request: RequestType) \
|
|
75
|
+
-> Union[ResponseIterableType, UnaryStreamCall]:
|
|
76
|
+
new_details = inject_current_context_into_header(client_call_details)
|
|
77
|
+
response = continuation(new_details, request)
|
|
78
|
+
return await response
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ContextInjectorStreamUnary(StreamUnaryClientInterceptor):
|
|
82
|
+
|
|
83
|
+
async def intercept_stream_unary(
|
|
84
|
+
self,
|
|
85
|
+
continuation: Callable[[ClientCallDetails, RequestType],
|
|
86
|
+
StreamUnaryCall],
|
|
87
|
+
client_call_details: ClientCallDetails,
|
|
88
|
+
request_iterator: RequestIterableType,
|
|
89
|
+
) -> StreamUnaryCall:
|
|
90
|
+
new_details = inject_current_context_into_header(client_call_details)
|
|
91
|
+
response = continuation(new_details, request_iterator)
|
|
92
|
+
return await response
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ContextInjectorStreamStream(StreamStreamClientInterceptor):
|
|
96
|
+
async def intercept_stream_stream(
|
|
97
|
+
self,
|
|
98
|
+
continuation: Callable[[ClientCallDetails, RequestType],
|
|
99
|
+
StreamStreamCall],
|
|
100
|
+
client_call_details: ClientCallDetails,
|
|
101
|
+
request_iterator: RequestIterableType,
|
|
102
|
+
) -> Union[ResponseIterableType, StreamStreamCall]:
|
|
103
|
+
new_details = inject_current_context_into_header(client_call_details)
|
|
104
|
+
response = continuation(new_details, request_iterator)
|
|
105
|
+
return await response
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# Copyright 2017-2021 Orbital Insight Inc., all rights reserved.
|
|
2
|
+
# Contains confidential and trade secret information.
|
|
3
|
+
# Government Users: Commercial Computer Software - Use governed by
|
|
4
|
+
# terms of Orbital Insight commercial license agreement.
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
import json
|
|
9
|
+
import time
|
|
10
|
+
import base64
|
|
11
|
+
from typing import Optional
|
|
12
|
+
from functools import lru_cache, wraps
|
|
13
|
+
import requests
|
|
14
|
+
|
|
15
|
+
import grpc
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
API_TOKEN = 'TERRASCOPE_API_TOKEN'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@lru_cache(maxsize=128)
|
|
22
|
+
def json_from_jwt(jwt_token: str) -> dict[str, object]:
|
|
23
|
+
# see also similar function in user svc client
|
|
24
|
+
# returns claims dict
|
|
25
|
+
try:
|
|
26
|
+
[_header, payload, _signature] = jwt_token.split('.')
|
|
27
|
+
payload_text = base64.b64decode(payload + "===", '-_')
|
|
28
|
+
payload_json = json.loads(payload_text)
|
|
29
|
+
return payload_json
|
|
30
|
+
except BaseException:
|
|
31
|
+
return {}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def is_token_expiring(jwt_token_str, within_secs=300) -> bool:
|
|
35
|
+
claims = json_from_jwt(jwt_token_str)
|
|
36
|
+
return claims.get('exp') < time.time() + within_secs
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def is_offline_token(jwt_token_str) -> bool:
|
|
40
|
+
claims = json_from_jwt(jwt_token_str)
|
|
41
|
+
return claims.get('typ') == 'Offline'
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def check_access_token(func) -> bool:
|
|
45
|
+
# decorator
|
|
46
|
+
@wraps(func)
|
|
47
|
+
def wrapper(*args, **kwargs): # The instance is passed as the first argument
|
|
48
|
+
self = args[0]
|
|
49
|
+
# check if current access token is expired
|
|
50
|
+
self.refresh_access_token_and_recreate_stubs()
|
|
51
|
+
result = func(self)
|
|
52
|
+
return result
|
|
53
|
+
return wrapper
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ElementsBaseApi(ABC):
|
|
57
|
+
|
|
58
|
+
def __init__(self, oi_papi_url: str, port: int = 443, secure=True, api_token: str = None, root_certificates_file=None):
|
|
59
|
+
self._oi_papi_url = oi_papi_url
|
|
60
|
+
self._port = port
|
|
61
|
+
self._secure = secure
|
|
62
|
+
self._root_certificates_file = root_certificates_file
|
|
63
|
+
self._channel = None
|
|
64
|
+
self.api_token: Optional[str] = os.environ.get(API_TOKEN, "").strip() if api_token is None else api_token.strip()
|
|
65
|
+
|
|
66
|
+
# check if this is an offline token, which is a refresh token, and obtain access tokens from it periodically
|
|
67
|
+
self.is_offline_token: bool = is_offline_token(self.api_token)
|
|
68
|
+
self.access_token: Optional[str] = self.api_token if not is_offline_token else None
|
|
69
|
+
self.access_token_expiration_threshold = int(os.getenv('ACCESS_TOKEN_EXPIRATION_THRESHOLD', '300'))
|
|
70
|
+
# (token will be renewed when it has less than this threshhold before expiry)
|
|
71
|
+
self.options = [('grpc.max_send_message_length', -1),
|
|
72
|
+
('grpc.max_receive_message_length', -1),
|
|
73
|
+
('grpc.max_metadata_size', 16000)]
|
|
74
|
+
service_config_json: str = json.dumps({
|
|
75
|
+
"methodConfig": [{
|
|
76
|
+
"name": [{}], # Apply retry to all methods by using [{}]
|
|
77
|
+
"retryPolicy": {
|
|
78
|
+
"maxAttempts": 5,
|
|
79
|
+
"initialBackoff": "1.0s",
|
|
80
|
+
"maxBackoff": "60s",
|
|
81
|
+
"backoffMultiplier": 2,
|
|
82
|
+
"retryableStatusCodes": ["UNAVAILABLE"],
|
|
83
|
+
},
|
|
84
|
+
}]
|
|
85
|
+
})
|
|
86
|
+
self.options.append(("grpc.service_config", service_config_json))
|
|
87
|
+
|
|
88
|
+
self.refresh_access_token()
|
|
89
|
+
self.new_channel()
|
|
90
|
+
self.recreate_stubs()
|
|
91
|
+
|
|
92
|
+
def recreate_stubs(self):
|
|
93
|
+
from elements_api import stubs
|
|
94
|
+
# unauthenticated users can access forgot_password
|
|
95
|
+
self._forgot_password = stubs.forgot_password.ForgotPasswordApiStub(self._channel)
|
|
96
|
+
|
|
97
|
+
if self.api_token:
|
|
98
|
+
self._algorithm = stubs.algorithm.AlgorithmApiStub(self._channel)
|
|
99
|
+
self._algorithm_version = stubs.algorithm_version.AlgorithmVersionApiStub(self._channel)
|
|
100
|
+
self._algorithm_config = stubs.algorithm_config.AlgorithmConfigApiStub(self._channel)
|
|
101
|
+
self._aoi = stubs.aoi.AOIApiStub(self._channel)
|
|
102
|
+
self._aoi_collection = stubs.aoi_collection.AOICollectionApiStub(self._channel)
|
|
103
|
+
self._aoi_version = stubs.aoi_version.AOIVersionApiStub(self._channel)
|
|
104
|
+
self._aoi_catalog = stubs.aoi_catalog.AOICatalogApiStub(self._channel)
|
|
105
|
+
self._aoi_transaction = stubs.aoi_transaction.AOITransactionApiStub(self._channel)
|
|
106
|
+
self._aoi_export = stubs.aoi_export.AOIExportApiStub(self._channel)
|
|
107
|
+
self._algorithm_computation = stubs.algorithm_computation.AlgorithmComputationApiStub(self._channel)
|
|
108
|
+
self._algorithm_computation_execution = \
|
|
109
|
+
stubs.algorithm_computation_execution.AlgorithmComputationExecutionApiStub(self._channel)
|
|
110
|
+
self._analysis = stubs.analysis.AnalysisApiStub(self._channel)
|
|
111
|
+
self._analysis_version = stubs.analysis_version.AnalysisVersionApiStub(self._channel)
|
|
112
|
+
self._credit = stubs.credit.CreditApiStub(self._channel)
|
|
113
|
+
self._result = stubs.result.ResultApiStub(self._channel)
|
|
114
|
+
self._analysis_config = stubs.analysis_config.AnalysisConfigApiStub(self._channel)
|
|
115
|
+
self._analysis_computation = stubs.analysis_computation.AnalysisComputationApiStub(self._channel)
|
|
116
|
+
self._system = stubs.system.SystemApiStub(self._channel)
|
|
117
|
+
self._toi = stubs.toi.TOIApiStub(self._channel)
|
|
118
|
+
self._permission = stubs.permission.PermissionApiStub(self._channel)
|
|
119
|
+
self._user = stubs.user.UserApiStub(self._channel)
|
|
120
|
+
self._user_collection = stubs.user_collection.UserCollectionApiStub(self._channel)
|
|
121
|
+
self._token = stubs.token.TokenApiStub(self._channel)
|
|
122
|
+
self._visualization = stubs.visualization.VisualizationApiStub(self._channel)
|
|
123
|
+
self._tile = stubs.tile.TileApiStub(self._channel)
|
|
124
|
+
self._notification = stubs.notification.NotificationApiStub(self._channel)
|
|
125
|
+
self._data_source = stubs.data_source.DataSourceAPIStub(self._channel)
|
|
126
|
+
self._data_type = stubs.data_type.DataTypeAPIStub(self._channel)
|
|
127
|
+
self._data_tracking = stubs.data_tracking.DataTrackingApiStub(self._channel)
|
|
128
|
+
self._project = stubs.project.ProjectApiStub(self._channel)
|
|
129
|
+
self._project_analysis_config = stubs.project_analysis_config.ProjectAnalysisConfigApiStub(self._channel)
|
|
130
|
+
self._project_collaborator = stubs.project_collaborator.ProjectCollaboratorApiStub(self._channel)
|
|
131
|
+
self._project_group = stubs.project_group.ProjectGroupApiStub(self._channel)
|
|
132
|
+
self._project_result = stubs.project_result.ProjectResultApiStub(self._channel)
|
|
133
|
+
self._project_filter = stubs.project_filter.ProjectFilterApiStub(self._channel)
|
|
134
|
+
self._filter = stubs.filter.FilterApiStub(self._channel)
|
|
135
|
+
self._project_aoi = stubs.project_aoi.ProjectAOIApiStub(self._channel)
|
|
136
|
+
self._order = stubs.order.OrderApiStub(self._channel)
|
|
137
|
+
self._order_recommendation = stubs.order_recommendation.OrderRecommendationApiStub(self._channel)
|
|
138
|
+
self._tasking_order = stubs.tasking_order.TaskingOrderApiStub(self._channel)
|
|
139
|
+
self._provider_quotas = stubs.provider_quotas.ProviderQuotasApiStub(self._channel)
|
|
140
|
+
self._resource = stubs.resource.ResourceApiStub(self._channel)
|
|
141
|
+
self._s3 = stubs.s3.S3ApiStub(self._channel)
|
|
142
|
+
|
|
143
|
+
def new_channel(self):
|
|
144
|
+
# if self._channel is not None:
|
|
145
|
+
# self._channel.close() # todo this is async, and channel.__del__ takes care of it
|
|
146
|
+
self._channel = self._get_channel(
|
|
147
|
+
self._get_ssl_channel_credentials(
|
|
148
|
+
self._secure,
|
|
149
|
+
root_certificates_file=self._root_certificates_file))
|
|
150
|
+
return self._channel
|
|
151
|
+
|
|
152
|
+
def refresh_access_token(self) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Refreshes the access token if it is expired.
|
|
155
|
+
returns True if the access token was refreshed, False otherwise.
|
|
156
|
+
"""
|
|
157
|
+
# check if current access token is expired
|
|
158
|
+
if self.api_token and not is_offline_token(self.api_token):
|
|
159
|
+
return False # in which case it is an access token, and it was not refreshed
|
|
160
|
+
# check expiration on the access_token
|
|
161
|
+
|
|
162
|
+
if self.access_token and not is_token_expiring(
|
|
163
|
+
self.access_token,
|
|
164
|
+
within_secs=self.access_token_expiration_threshold
|
|
165
|
+
):
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
oidc_base_url = os.getenv(
|
|
169
|
+
'OIDC_BASE_URL',
|
|
170
|
+
'https://keycloak.orbitalinsight.com')
|
|
171
|
+
oidc_realm = os.getenv('OIDC_REALM', 'elements')
|
|
172
|
+
oidc_token_endpoint = os.getenv(
|
|
173
|
+
'OIDC_TOKEN_ENDPOINT',
|
|
174
|
+
f'{oidc_base_url}/realms/{oidc_realm}/protocol/openid-connect/token')
|
|
175
|
+
|
|
176
|
+
# note: api token is an offline token, which is a special refresh token.
|
|
177
|
+
oidc_client_id = os.getenv('OIDC_CLIENT_ID', 'login-ui')
|
|
178
|
+
oidc_client_secret = os.getenv('OIDC_CLIENT_SECRET')
|
|
179
|
+
|
|
180
|
+
request_json = {
|
|
181
|
+
'refresh_token': self.api_token,
|
|
182
|
+
'client_id': oidc_client_id,
|
|
183
|
+
'grant_type': 'refresh_token',
|
|
184
|
+
'scope': 'openid offline_access'
|
|
185
|
+
}
|
|
186
|
+
if oidc_client_secret:
|
|
187
|
+
request_json['client_secret'] = oidc_client_secret
|
|
188
|
+
|
|
189
|
+
response = requests.post(
|
|
190
|
+
oidc_token_endpoint,
|
|
191
|
+
data=request_json,
|
|
192
|
+
headers={'Content-Type': 'application/x-www-form-urlencoded'})
|
|
193
|
+
if not response.ok:
|
|
194
|
+
raise Exception(f"Failed to refresh token: {response.text}")
|
|
195
|
+
|
|
196
|
+
self.access_token = response.json().get('access_token')
|
|
197
|
+
return True
|
|
198
|
+
|
|
199
|
+
def refresh_access_token_and_recreate_stubs(self) -> bool:
|
|
200
|
+
# check if current access token is expired
|
|
201
|
+
if not self.refresh_access_token():
|
|
202
|
+
return False
|
|
203
|
+
self.new_channel()
|
|
204
|
+
self.recreate_stubs()
|
|
205
|
+
return True
|
|
206
|
+
# individual api accessors are properties, since underlying channel may need to change
|
|
207
|
+
# at any time due to its token change. Do not store property result in a variable,
|
|
208
|
+
# as it will not be refreshed automatically when the token changes
|
|
209
|
+
# token freshness is checked in every call, then if it expired and changed,
|
|
210
|
+
# (all) stubs are regenerated. A new channel is created with that token in each stub
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
@check_access_token
|
|
214
|
+
def forgot_password(self):
|
|
215
|
+
return self._forgot_password
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
@check_access_token
|
|
219
|
+
def algorithm(self):
|
|
220
|
+
return self._algorithm
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
@check_access_token
|
|
224
|
+
def algorithm_version(self):
|
|
225
|
+
return self._algorithm_version
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
@check_access_token
|
|
229
|
+
def algorithm_config(self):
|
|
230
|
+
return self._algorithm_config
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
@check_access_token
|
|
234
|
+
def aoi(self):
|
|
235
|
+
return self._aoi
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
@check_access_token
|
|
239
|
+
def aoi_collection(self):
|
|
240
|
+
return self._aoi_collection
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
@check_access_token
|
|
244
|
+
def aoi_version(self):
|
|
245
|
+
return self._aoi_version
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
@check_access_token
|
|
249
|
+
def aoi_catalog(self):
|
|
250
|
+
return self._aoi_catalog
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
@check_access_token
|
|
254
|
+
def aoi_transaction(self):
|
|
255
|
+
return self._aoi_transaction
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
@check_access_token
|
|
259
|
+
def aoi_export(self):
|
|
260
|
+
return self._aoi_export
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
@check_access_token
|
|
264
|
+
def algorithm_computation(self):
|
|
265
|
+
return self._algorithm_computation
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
@check_access_token
|
|
269
|
+
def algorithm_computation_execution(self):
|
|
270
|
+
return self._algorithm_computation_execution
|
|
271
|
+
|
|
272
|
+
@property
|
|
273
|
+
@check_access_token
|
|
274
|
+
def analysis(self):
|
|
275
|
+
return self._analysis
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
@check_access_token
|
|
279
|
+
def analysis_version(self):
|
|
280
|
+
return self._analysis_version
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
@check_access_token
|
|
284
|
+
def credit(self):
|
|
285
|
+
return self._credit
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
@check_access_token
|
|
289
|
+
def result(self):
|
|
290
|
+
return self._result
|
|
291
|
+
|
|
292
|
+
@property
|
|
293
|
+
@check_access_token
|
|
294
|
+
def analysis_config(self):
|
|
295
|
+
return self._analysis_config
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
@check_access_token
|
|
299
|
+
def analysis_computation(self):
|
|
300
|
+
return self._analysis_computation
|
|
301
|
+
|
|
302
|
+
@property
|
|
303
|
+
@check_access_token
|
|
304
|
+
def system(self):
|
|
305
|
+
return self._system
|
|
306
|
+
|
|
307
|
+
@property
|
|
308
|
+
@check_access_token
|
|
309
|
+
def toi(self):
|
|
310
|
+
return self._toi
|
|
311
|
+
|
|
312
|
+
@property
|
|
313
|
+
@check_access_token
|
|
314
|
+
def permission(self):
|
|
315
|
+
return self._permission
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
@check_access_token
|
|
319
|
+
def user(self):
|
|
320
|
+
return self._user
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
@check_access_token
|
|
324
|
+
def user_collection(self):
|
|
325
|
+
return self._user_collection
|
|
326
|
+
|
|
327
|
+
@property
|
|
328
|
+
@check_access_token
|
|
329
|
+
def token(self):
|
|
330
|
+
return self._token
|
|
331
|
+
|
|
332
|
+
@property
|
|
333
|
+
@check_access_token
|
|
334
|
+
def visualization(self):
|
|
335
|
+
return self._visualization
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
@check_access_token
|
|
339
|
+
def tile(self):
|
|
340
|
+
return self._tile
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
@check_access_token
|
|
344
|
+
def notification(self):
|
|
345
|
+
return self._notification
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
@check_access_token
|
|
349
|
+
def data_source(self):
|
|
350
|
+
return self._data_source
|
|
351
|
+
|
|
352
|
+
@property
|
|
353
|
+
@check_access_token
|
|
354
|
+
def data_type(self):
|
|
355
|
+
return self._data_type
|
|
356
|
+
|
|
357
|
+
@property
|
|
358
|
+
@check_access_token
|
|
359
|
+
def data_tracking(self):
|
|
360
|
+
return self._data_tracking
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
@check_access_token
|
|
364
|
+
def project(self):
|
|
365
|
+
return self._project
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
@check_access_token
|
|
369
|
+
def project_analysis_config(self):
|
|
370
|
+
return self._project_analysis_config
|
|
371
|
+
|
|
372
|
+
@property
|
|
373
|
+
@check_access_token
|
|
374
|
+
def project_collaborator(self):
|
|
375
|
+
return self._project_collaborator
|
|
376
|
+
|
|
377
|
+
@property
|
|
378
|
+
@check_access_token
|
|
379
|
+
def project_group(self):
|
|
380
|
+
return self._project_group
|
|
381
|
+
|
|
382
|
+
@property
|
|
383
|
+
@check_access_token
|
|
384
|
+
def project_result(self):
|
|
385
|
+
return self._project_result
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
@check_access_token
|
|
389
|
+
def project_filter(self):
|
|
390
|
+
return self._project_filter
|
|
391
|
+
|
|
392
|
+
@property
|
|
393
|
+
@check_access_token
|
|
394
|
+
def filter(self):
|
|
395
|
+
return self._filter
|
|
396
|
+
|
|
397
|
+
@property
|
|
398
|
+
@check_access_token
|
|
399
|
+
def project_aoi(self):
|
|
400
|
+
return self._project_aoi
|
|
401
|
+
|
|
402
|
+
@property
|
|
403
|
+
@check_access_token
|
|
404
|
+
def order(self):
|
|
405
|
+
return self._order
|
|
406
|
+
|
|
407
|
+
@property
|
|
408
|
+
@check_access_token
|
|
409
|
+
def order_recommendation(self):
|
|
410
|
+
return self._order_recommendation
|
|
411
|
+
|
|
412
|
+
@property
|
|
413
|
+
@check_access_token
|
|
414
|
+
def tasking_order(self):
|
|
415
|
+
return self._tasking_order
|
|
416
|
+
|
|
417
|
+
@property
|
|
418
|
+
@check_access_token
|
|
419
|
+
def provider_quotas(self):
|
|
420
|
+
return self._provider_quotas
|
|
421
|
+
|
|
422
|
+
@property
|
|
423
|
+
@check_access_token
|
|
424
|
+
def provider(self):
|
|
425
|
+
return self._provider
|
|
426
|
+
|
|
427
|
+
@property
|
|
428
|
+
@check_access_token
|
|
429
|
+
def resource(self):
|
|
430
|
+
return self._resource
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
@check_access_token
|
|
434
|
+
def s3(self):
|
|
435
|
+
return self._s3
|
|
436
|
+
|
|
437
|
+
def _get_ssl_channel_credentials(self, secure, root_certificates_file=None):
|
|
438
|
+
# note: with all defaults, gRPC will search for cert as described here:
|
|
439
|
+
# https://github.com/grpc/grpc/blob/7a63bd5407d5e14b30f19a5aaf4b6cd1b80f00e1/include/grpc/grpc_security.h#L287
|
|
440
|
+
# for local env, use local_channel_credentials:
|
|
441
|
+
# https://grpc.github.io/grpc/python/grpc.html#grpc.local_channel_credentials
|
|
442
|
+
if secure:
|
|
443
|
+
root_certificates = None
|
|
444
|
+
if root_certificates_file:
|
|
445
|
+
with open(root_certificates_file, 'rb') as file:
|
|
446
|
+
root_certificates = file.read()
|
|
447
|
+
|
|
448
|
+
return grpc.ssl_channel_credentials(root_certificates=root_certificates,
|
|
449
|
+
private_key=None, certificate_chain=None)
|
|
450
|
+
return grpc.local_channel_credentials()
|
|
451
|
+
|
|
452
|
+
@abstractmethod
|
|
453
|
+
def _get_channel(self, channel_credentials: grpc.ChannelCredentials):
|
|
454
|
+
...
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from . import algorithm_computation_execution_pb2 as algorithm_computation_execution
|
|
2
|
+
from . import algorithm_computation_pb2 as algorithm_computation
|
|
3
|
+
from . import algorithm_config_pb2 as algorithm_config
|
|
4
|
+
from . import algorithm_manifest_pb2 as algorithm_manifest
|
|
5
|
+
from . import algorithm_pb2 as algorithm
|
|
6
|
+
from . import algorithm_version_pb2 as algorithm_version
|
|
7
|
+
from . import analysis_computation_pb2 as analysis_computation
|
|
8
|
+
from . import analysis_config_pb2 as analysis_config
|
|
9
|
+
from . import analysis_pb2 as analysis
|
|
10
|
+
from . import analysis_version_pb2 as analysis_version
|
|
11
|
+
from . import aoi_catalog_pb2 as aoi_catalog
|
|
12
|
+
from . import aoi_collection_pb2 as aoi_collection
|
|
13
|
+
from . import aoi_export_pb2 as aoi_export
|
|
14
|
+
from . import aoi_pb2 as aoi
|
|
15
|
+
from . import aoi_transaction_pb2 as aoi_transaction
|
|
16
|
+
from . import aoi_version_pb2 as aoi_version
|
|
17
|
+
from . import common_models_pb2 as common_models
|
|
18
|
+
from . import credit_pb2 as credit
|
|
19
|
+
from . import data_source_pb2 as data_source
|
|
20
|
+
from . import data_tracking_pb2 as data_tracking
|
|
21
|
+
from . import data_type_pb2 as data_type
|
|
22
|
+
from . import filter_pb2 as filter
|
|
23
|
+
from . import forgot_password_pb2 as forgot_password
|
|
24
|
+
from . import notification_pb2 as notification
|
|
25
|
+
from . import order_pb2 as order
|
|
26
|
+
from . import order_recommendation_pb2 as order_recommendation
|
|
27
|
+
from . import permission_pb2 as permission
|
|
28
|
+
from . import project_analysis_config_pb2 as project_analysis_config
|
|
29
|
+
from . import project_aoi_pb2 as project_aoi
|
|
30
|
+
from . import project_collaborator_pb2 as project_collaborator
|
|
31
|
+
from . import project_filter_pb2 as project_filter
|
|
32
|
+
from . import project_group_pb2 as project_group
|
|
33
|
+
from . import project_pb2 as project
|
|
34
|
+
from . import project_result_pb2 as project_result
|
|
35
|
+
from . import provider_quotas_pb2 as provider_quotas
|
|
36
|
+
from . import resource_pb2 as resource
|
|
37
|
+
from . import result_pb2 as result
|
|
38
|
+
from . import s3_pb2 as s3
|
|
39
|
+
from . import subject_pb2 as subject
|
|
40
|
+
from . import system_pb2 as system
|
|
41
|
+
from . import tasking_order_pb2 as tasking_order
|
|
42
|
+
from . import tile_pb2 as tile
|
|
43
|
+
from . import toi_pb2 as toi
|
|
44
|
+
from . import token_pb2 as token
|
|
45
|
+
from . import user_collection_pb2 as user_collection
|
|
46
|
+
from . import user_pb2 as user
|
|
47
|
+
from . import visualization_pb2 as visualization
|