appmesh 1.6.13__py3-none-any.whl → 1.6.15__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.
- appmesh/app.py +28 -18
- appmesh/client_http.py +434 -676
- appmesh/client_http_oauth.py +2 -2
- appmesh/client_tcp.py +158 -111
- appmesh/server_http.py +20 -23
- appmesh/server_tcp.py +4 -8
- appmesh/tcp_transport.py +0 -2
- {appmesh-1.6.13.dist-info → appmesh-1.6.15.dist-info}/METADATA +1 -1
- appmesh-1.6.15.dist-info/RECORD +16 -0
- appmesh-1.6.13.dist-info/RECORD +0 -16
- {appmesh-1.6.13.dist-info → appmesh-1.6.15.dist-info}/WHEEL +0 -0
- {appmesh-1.6.13.dist-info → appmesh-1.6.15.dist-info}/top_level.txt +0 -0
appmesh/client_http_oauth.py
CHANGED
@@ -18,8 +18,8 @@ class AppMeshClientOAuth(AppMeshClient):
|
|
18
18
|
self,
|
19
19
|
oauth2: dict, # Required for Keycloak
|
20
20
|
rest_url: str = "https://127.0.0.1:6060",
|
21
|
-
rest_ssl_verify=AppMeshClient.DEFAULT_SSL_CA_CERT_PATH
|
22
|
-
rest_ssl_client_cert=
|
21
|
+
rest_ssl_verify=AppMeshClient.DEFAULT_SSL_CA_CERT_PATH,
|
22
|
+
rest_ssl_client_cert=AppMeshClient.DEFAULT_SSL_CLIENT_CERT_PATH,
|
23
23
|
rest_timeout=(60, 300),
|
24
24
|
jwt_token=None, # Keycloak dict
|
25
25
|
auto_refresh_token: bool = True, # Default to True for Keycloak
|
appmesh/client_tcp.py
CHANGED
@@ -7,6 +7,7 @@ import os
|
|
7
7
|
import socket
|
8
8
|
import sys
|
9
9
|
import uuid
|
10
|
+
from typing import Optional, Tuple, Union
|
10
11
|
|
11
12
|
# Third-party imports
|
12
13
|
import requests
|
@@ -18,8 +19,7 @@ from .tcp_transport import TCPTransport
|
|
18
19
|
|
19
20
|
|
20
21
|
class AppMeshClientTCP(AppMeshClient):
|
21
|
-
"""
|
22
|
-
Client SDK for interacting with the App Mesh service over TCP, with enhanced support for large file transfers.
|
22
|
+
"""Client SDK for interacting with the App Mesh service over TCP.
|
23
23
|
|
24
24
|
The `AppMeshClientTCP` class extends the functionality of `AppMeshClient` by offering a TCP-based communication layer
|
25
25
|
for the App Mesh REST API. It overrides the file download and upload methods to support large file transfers with
|
@@ -28,30 +28,23 @@ class AppMeshClientTCP(AppMeshClient):
|
|
28
28
|
This client is suitable for applications requiring efficient data transfers and high-throughput operations within the
|
29
29
|
App Mesh ecosystem, while maintaining compatibility with all other attributes and methods from `AppMeshClient`.
|
30
30
|
|
31
|
-
Dependency:
|
32
|
-
- Install the required package for message serialization:
|
33
|
-
pip3 install msgpack
|
34
|
-
|
35
|
-
Usage:
|
36
|
-
- Import the client module:
|
37
|
-
from appmesh import AppMeshClientTCP
|
38
|
-
|
39
|
-
Example:
|
40
|
-
client = AppMeshClientTCP()
|
41
|
-
client.login("your-name", "your-password")
|
42
|
-
client.file_download("/tmp/os-release", "os-release")
|
43
|
-
|
44
31
|
Attributes:
|
45
|
-
|
46
|
-
- Optimized for TCP-based communication to provide better performance for large file transfers.
|
32
|
+
Inherits all attributes from `AppMeshClient`, including TLS secure connections and JWT-based authentication.
|
47
33
|
|
48
34
|
Methods:
|
49
|
-
-
|
50
|
-
-
|
35
|
+
- download_file()
|
36
|
+
- upload_file()
|
51
37
|
- Inherits all other methods from `AppMeshClient`, providing a consistent interface for managing applications within App Mesh.
|
38
|
+
|
39
|
+
Example:
|
40
|
+
>>> from appmesh import AppMeshClientTCP
|
41
|
+
>>> client = AppMeshClientTCP()
|
42
|
+
>>> client.login("your-name", "your-password")
|
43
|
+
>>> client.download_file("/tmp/os-release", "os-release")
|
52
44
|
"""
|
53
45
|
|
54
|
-
|
46
|
+
# TLS-optimized chunk size, leaves room for TLS overhead within the 16 KB limit
|
47
|
+
TCP_BLOCK_SIZE = 16 * 1024 - 128
|
55
48
|
ENCODING_UTF8 = "utf-8"
|
56
49
|
HTTP_USER_AGENT_TCP = "appmesh/python/tcp"
|
57
50
|
HTTP_HEADER_KEY_X_SEND_FILE_SOCKET = "X-Send-File-Socket"
|
@@ -59,32 +52,27 @@ class AppMeshClientTCP(AppMeshClient):
|
|
59
52
|
|
60
53
|
def __init__(
|
61
54
|
self,
|
62
|
-
rest_ssl_verify=
|
63
|
-
rest_ssl_client_cert=None,
|
64
|
-
jwt_token=None,
|
65
|
-
tcp_address=("127.0.0.1", 6059),
|
55
|
+
rest_ssl_verify: Union[bool, str] = AppMeshClient.DEFAULT_SSL_CA_CERT_PATH,
|
56
|
+
rest_ssl_client_cert: Optional[Union[str, Tuple[str, str]]] = None,
|
57
|
+
jwt_token: Optional[str] = None,
|
58
|
+
tcp_address: Tuple[str, int] = ("127.0.0.1", 6059),
|
66
59
|
):
|
67
60
|
"""Construct an App Mesh client TCP object to communicate securely with an App Mesh server over TLS.
|
68
61
|
|
69
62
|
Args:
|
70
|
-
rest_ssl_verify
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
jwt_token (str, optional): JWT token for authentication. Used in methods requiring login and user authorization.
|
85
|
-
|
86
|
-
tcp_address (Tuple[str, int], optional): Address and port for establishing a TCP connection to the server.
|
87
|
-
Defaults to `("127.0.0.1", 6059)`.
|
63
|
+
rest_ssl_verify: SSL certificate verification behavior. Can be True, False, or a path to CA bundle.
|
64
|
+
- True: Use system CA certificates (e.g., /etc/ssl/certs/ on Linux)
|
65
|
+
- False: Disable verification (insecure)
|
66
|
+
- str: Path to custom CA bundle or directory
|
67
|
+
ssl_client_cert: SSL client certificate:
|
68
|
+
- str: Path to single PEM with cert+key
|
69
|
+
- tuple: (cert_path, key_path)
|
70
|
+
jwt_token: Pre-configured JWT Token for authenticating requests.
|
71
|
+
tcp_address: Server address as (host, port) tuple, defaults to ("127.0.0.1", 6059).
|
72
|
+
|
73
|
+
Note:
|
74
|
+
TCP connections require an explicit full-chain CA specification for certificate validation,
|
75
|
+
unlike HTTP, which can retrieve intermediate certificates automatically.
|
88
76
|
"""
|
89
77
|
self.tcp_transport = TCPTransport(address=tcp_address, ssl_verify=rest_ssl_verify, ssl_client_cert=rest_ssl_client_cert)
|
90
78
|
super().__init__(rest_ssl_verify=rest_ssl_verify, rest_ssl_client_cert=rest_ssl_client_cert, jwt_token=jwt_token)
|
@@ -102,93 +90,159 @@ class AppMeshClientTCP(AppMeshClient):
|
|
102
90
|
self.close()
|
103
91
|
except Exception:
|
104
92
|
pass # Never raise in __del__
|
105
|
-
super().__del__()
|
106
93
|
|
107
|
-
def
|
94
|
+
def _covert_bytes(self, body) -> bytes:
|
95
|
+
"""Prepare request body for transmission."""
|
96
|
+
if body is None:
|
97
|
+
return b""
|
98
|
+
|
99
|
+
if isinstance(body, (bytes, bytearray, memoryview)):
|
100
|
+
return body
|
101
|
+
|
102
|
+
if isinstance(body, str):
|
103
|
+
return body.encode(self.ENCODING_UTF8)
|
104
|
+
|
105
|
+
if isinstance(body, (dict, list)):
|
106
|
+
return json.dumps(body).encode(self.ENCODING_UTF8)
|
107
|
+
|
108
|
+
raise TypeError(f"Unsupported body type: {type(body)}")
|
109
|
+
|
110
|
+
def _request_http(self, method: AppMeshClient.Method, path: str, query: Optional[dict] = None, header: Optional[dict] = None, body=None) -> requests.Response:
|
108
111
|
"""Send HTTP request over TCP transport.
|
109
112
|
|
110
113
|
Args:
|
111
|
-
method
|
112
|
-
path
|
113
|
-
query
|
114
|
-
header
|
114
|
+
method: HTTP method.
|
115
|
+
path: URI path.
|
116
|
+
query: Query parameters.
|
117
|
+
header: HTTP headers.
|
115
118
|
body: Request body.
|
116
119
|
|
117
120
|
Returns:
|
118
|
-
|
121
|
+
Simulated HTTP response.
|
119
122
|
"""
|
123
|
+
|
124
|
+
# Check for unsupported features
|
125
|
+
if super().forward_to:
|
126
|
+
raise RuntimeError("Forward request is not supported in TCP mode")
|
127
|
+
|
120
128
|
if not self.tcp_transport.connected():
|
121
129
|
self.tcp_transport.connect()
|
122
130
|
|
131
|
+
# Prepare request message (ensure no fields are assigned None!)
|
123
132
|
appmesh_request = RequestMessage()
|
124
|
-
token = self._get_access_token()
|
125
|
-
if token:
|
126
|
-
appmesh_request.headers[self.HTTP_HEADER_KEY_AUTH] = token
|
127
|
-
if super().forward_to and len(super().forward_to) > 0:
|
128
|
-
raise Exception("Not support forward request in TCP mode")
|
129
|
-
appmesh_request.headers[self.HTTP_HEADER_KEY_USER_AGENT] = self.HTTP_USER_AGENT_TCP
|
130
133
|
appmesh_request.uuid = str(uuid.uuid1())
|
131
134
|
appmesh_request.http_method = method.value
|
132
135
|
appmesh_request.request_uri = path
|
133
136
|
appmesh_request.client_addr = socket.gethostname()
|
137
|
+
appmesh_request.headers[self.HTTP_HEADER_KEY_USER_AGENT] = self.HTTP_USER_AGENT_TCP
|
134
138
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
appmesh_request.body = bytes(body, self.ENCODING_UTF8)
|
140
|
-
elif isinstance(body, bytes):
|
141
|
-
appmesh_request.body = body
|
142
|
-
else:
|
143
|
-
raise Exception(f"UnSupported body type: {type(body)}")
|
139
|
+
# Add authentication token
|
140
|
+
token = self._get_access_token()
|
141
|
+
if token:
|
142
|
+
appmesh_request.headers[self.HTTP_HEADER_KEY_AUTH] = token
|
144
143
|
|
144
|
+
# Add custom headers
|
145
145
|
if header:
|
146
|
-
|
147
|
-
|
146
|
+
appmesh_request.headers.update(header)
|
147
|
+
|
148
|
+
# Add query parameters
|
148
149
|
if query:
|
149
|
-
|
150
|
-
|
150
|
+
appmesh_request.query.update(query)
|
151
|
+
|
152
|
+
# Prepare body
|
153
|
+
body_bytes = self._covert_bytes(body)
|
154
|
+
if body_bytes:
|
155
|
+
appmesh_request.body = body_bytes
|
151
156
|
|
157
|
+
# Send request
|
152
158
|
data = appmesh_request.serialize()
|
153
159
|
self.tcp_transport.send_message(data)
|
154
160
|
|
161
|
+
# Receive response
|
155
162
|
resp_data = self.tcp_transport.receive_message()
|
156
163
|
if not resp_data: # Covers None and empty bytes
|
157
164
|
self.tcp_transport.close()
|
158
|
-
raise
|
165
|
+
raise ConnectionError("Socket connection broken")
|
159
166
|
|
167
|
+
# Parse response
|
160
168
|
appmesh_resp = ResponseMessage().deserialize(resp_data)
|
161
169
|
response = requests.Response()
|
162
170
|
response.status_code = appmesh_resp.http_status
|
163
|
-
# response.encoding = self.ENCODING_UTF8 # only need when charset not in appmesh_resp.body_msg_type
|
164
|
-
response._content = appmesh_resp.body if isinstance(appmesh_resp.body, bytes) else str(appmesh_resp.body).encode(self.ENCODING_UTF8)
|
165
171
|
response.headers = appmesh_resp.headers
|
172
|
+
|
173
|
+
# Set response content
|
174
|
+
# response.encoding = self.ENCODING_UTF8 # only need when charset not in appmesh_resp.body_msg_type
|
175
|
+
if isinstance(appmesh_resp.body, bytes):
|
176
|
+
response._content = appmesh_resp.body
|
177
|
+
else:
|
178
|
+
response._content = str(appmesh_resp.body).encode(self.ENCODING_UTF8)
|
179
|
+
|
180
|
+
# Set content type
|
166
181
|
if appmesh_resp.body_msg_type:
|
167
182
|
response.headers["Content-Type"] = appmesh_resp.body_msg_type
|
168
183
|
|
169
184
|
return AppMeshClient.EncodingResponse(response)
|
170
185
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
186
|
+
def _apply_file_attributes(self, local_file: str, headers: dict) -> None:
|
187
|
+
"""Apply file attributes from headers to local file."""
|
188
|
+
if sys.platform == "win32":
|
189
|
+
return
|
190
|
+
|
191
|
+
# Apply file mode
|
192
|
+
if "X-File-Mode" in headers:
|
193
|
+
try:
|
194
|
+
os.chmod(local_file, int(headers["X-File-Mode"]))
|
195
|
+
except (ValueError, OSError) as e:
|
196
|
+
self._logger.warning("Failed to set file mode: %s", e)
|
197
|
+
|
198
|
+
# Apply file ownership
|
199
|
+
if "X-File-User" in headers and "X-File-Group" in headers:
|
200
|
+
try:
|
201
|
+
file_uid = int(headers["X-File-User"])
|
202
|
+
file_gid = int(headers["X-File-Group"])
|
203
|
+
os.chown(local_file, uid=file_uid, gid=file_gid)
|
204
|
+
except (ValueError, PermissionError, OSError) as e:
|
205
|
+
if isinstance(e, PermissionError):
|
206
|
+
print(f"Warning: Unable to change owner/group of {local_file}. " "Operation requires elevated privileges.")
|
207
|
+
else:
|
208
|
+
self._logger.warning("Failed to set file ownership: %s", e)
|
209
|
+
|
210
|
+
def _get_file_attributes(self, local_file: str) -> dict:
|
211
|
+
"""Get file attributes as header dictionary."""
|
212
|
+
if sys.platform == "win32":
|
213
|
+
return {}
|
214
|
+
|
215
|
+
try:
|
216
|
+
file_stat = os.stat(local_file)
|
217
|
+
return {
|
218
|
+
"X-File-Mode": str(file_stat.st_mode & 0o777),
|
219
|
+
"X-File-User": str(file_stat.st_uid),
|
220
|
+
"X-File-Group": str(file_stat.st_gid),
|
221
|
+
}
|
222
|
+
except OSError as e:
|
223
|
+
self._logger.warning("Failed to get file attributes: %s", e)
|
224
|
+
return {}
|
225
|
+
|
226
|
+
def download_file(self, remote_file: str, local_file: str, preserve_permissions: bool = True) -> None:
|
175
227
|
"""Copy a remote file to local, preserving file attributes if requested.
|
176
228
|
|
177
229
|
Args:
|
178
|
-
remote_file
|
179
|
-
local_file
|
180
|
-
|
230
|
+
remote_file: Remote file path.
|
231
|
+
local_file: Local destination path.
|
232
|
+
preserve_permissions: Apply remote file permissions/ownership locally.
|
181
233
|
"""
|
182
234
|
header = {
|
183
235
|
AppMeshClient.HTTP_HEADER_KEY_X_FILE_PATH: remote_file,
|
184
236
|
self.HTTP_HEADER_KEY_X_RECV_FILE_SOCKET: "true",
|
185
237
|
}
|
238
|
+
|
186
239
|
resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/file/download", header=header)
|
187
240
|
resp.raise_for_status()
|
188
241
|
|
189
242
|
if self.HTTP_HEADER_KEY_X_RECV_FILE_SOCKET not in resp.headers:
|
190
|
-
raise ValueError(f"Server did not respond with socket transfer option: {self.HTTP_HEADER_KEY_X_RECV_FILE_SOCKET}")
|
243
|
+
raise ValueError(f"Server did not respond with socket transfer option: " f"{self.HTTP_HEADER_KEY_X_RECV_FILE_SOCKET}")
|
191
244
|
|
245
|
+
# Download file chunks
|
192
246
|
with open(local_file, "wb") as fp:
|
193
247
|
while True:
|
194
248
|
chunk_data = self.tcp_transport.receive_message()
|
@@ -196,50 +250,43 @@ class AppMeshClientTCP(AppMeshClient):
|
|
196
250
|
break
|
197
251
|
fp.write(chunk_data)
|
198
252
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
file_gid = int(resp.headers["X-File-Group"])
|
205
|
-
try:
|
206
|
-
os.chown(path=local_file, uid=file_uid, gid=file_gid)
|
207
|
-
except PermissionError:
|
208
|
-
print(f"Warning: Unable to change owner/group of {local_file}. Operation requires elevated privileges.")
|
209
|
-
|
210
|
-
def upload_file(self, local_file: str, remote_file: str, apply_file_attributes: bool = True) -> None:
|
253
|
+
# Apply file attributes if requested
|
254
|
+
if preserve_permissions:
|
255
|
+
self._apply_file_attributes(local_file, resp.headers)
|
256
|
+
|
257
|
+
def upload_file(self, local_file: str, remote_file: str, preserve_permissions: bool = True) -> None:
|
211
258
|
"""Upload a local file to remote server, preserving file attributes if requested.
|
212
259
|
|
213
260
|
Args:
|
214
|
-
local_file
|
215
|
-
remote_file
|
216
|
-
|
261
|
+
local_file: Local file path.
|
262
|
+
remote_file: Remote destination path.
|
263
|
+
preserve_permissions: Upload file permissions/ownership metadata.
|
217
264
|
"""
|
218
265
|
if not os.path.exists(local_file):
|
219
266
|
raise FileNotFoundError(f"Local file not found: {local_file}")
|
220
267
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
268
|
+
# Prepare headers
|
269
|
+
header = {
|
270
|
+
AppMeshClient.HTTP_HEADER_KEY_X_FILE_PATH: remote_file,
|
271
|
+
"Content-Type": "text/plain",
|
272
|
+
self.HTTP_HEADER_KEY_X_SEND_FILE_SOCKET: "true",
|
273
|
+
}
|
227
274
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
header["X-File-User"] = str(file_stat.st_uid)
|
232
|
-
header["X-File-Group"] = str(file_stat.st_gid)
|
275
|
+
# Add file attributes if requested
|
276
|
+
if preserve_permissions:
|
277
|
+
header.update(self._get_file_attributes(local_file))
|
233
278
|
|
234
|
-
|
235
|
-
|
279
|
+
# Initiate upload
|
280
|
+
resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/file/upload", header=header)
|
281
|
+
resp.raise_for_status()
|
236
282
|
|
237
|
-
|
238
|
-
|
283
|
+
if self.HTTP_HEADER_KEY_X_SEND_FILE_SOCKET not in resp.headers:
|
284
|
+
raise ValueError(f"Server did not respond with socket transfer option: " f"{self.HTTP_HEADER_KEY_X_SEND_FILE_SOCKET}")
|
239
285
|
|
240
|
-
|
286
|
+
# Upload file chunks
|
287
|
+
with open(local_file, "rb") as fp:
|
241
288
|
while True:
|
242
|
-
chunk_data = fp.read(
|
289
|
+
chunk_data = fp.read(self.TCP_BLOCK_SIZE)
|
243
290
|
if not chunk_data:
|
244
291
|
self.tcp_transport.send_message([]) # EOF signal
|
245
292
|
break
|
appmesh/server_http.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# server_http.py
|
2
2
|
# pylint: disable=line-too-long,broad-exception-raised,broad-exception-caught,import-outside-toplevel,protected-access
|
3
3
|
|
4
|
+
"""HTTP server SDK implementation for App Mesh."""
|
5
|
+
|
4
6
|
# Standard library imports
|
5
7
|
import abc
|
6
8
|
import logging
|
@@ -16,8 +18,7 @@ logger = logging.getLogger(__name__)
|
|
16
18
|
|
17
19
|
|
18
20
|
class AppMeshServer(metaclass=abc.ABCMeta):
|
19
|
-
"""
|
20
|
-
Server SDK for App Mesh application interacting with the local App Mesh REST service over HTTPS.
|
21
|
+
"""Server SDK for App Mesh application interacting with the local App Mesh REST service over HTTPS.
|
21
22
|
|
22
23
|
Build-in runtime environment variables required:
|
23
24
|
- APP_MESH_PROCESS_KEY
|
@@ -34,18 +35,13 @@ class AppMeshServer(metaclass=abc.ABCMeta):
|
|
34
35
|
context.task_return(result)
|
35
36
|
"""
|
36
37
|
|
38
|
+
_RETRY_DELAY_SECONDS = 0.1
|
39
|
+
|
37
40
|
def __init__(
|
38
41
|
self,
|
39
42
|
rest_url: str = "https://127.0.0.1:6060",
|
40
|
-
rest_ssl_verify=
|
41
|
-
rest_ssl_client_cert=
|
42
|
-
(
|
43
|
-
AppMeshClient.DEFAULT_SSL_CLIENT_CERT_PATH,
|
44
|
-
AppMeshClient.DEFAULT_SSL_CLIENT_KEY_PATH,
|
45
|
-
)
|
46
|
-
if os.path.exists(AppMeshClient.DEFAULT_SSL_CLIENT_CERT_PATH)
|
47
|
-
else None
|
48
|
-
),
|
43
|
+
rest_ssl_verify: Union[bool, str] = AppMeshClient.DEFAULT_SSL_CA_CERT_PATH,
|
44
|
+
rest_ssl_client_cert: Optional[Union[str, Tuple[str, str]]] = None,
|
49
45
|
rest_timeout: Tuple[float, float] = (60, 300),
|
50
46
|
*,
|
51
47
|
logger_: Optional[logging.Logger] = None,
|
@@ -63,6 +59,7 @@ class AppMeshServer(metaclass=abc.ABCMeta):
|
|
63
59
|
"""Read and validate required runtime environment variables."""
|
64
60
|
process_key = os.getenv("APP_MESH_PROCESS_KEY")
|
65
61
|
app_name = os.getenv("APP_MESH_APPLICATION_NAME")
|
62
|
+
|
66
63
|
if not process_key:
|
67
64
|
raise Exception("Missing environment variable: APP_MESH_PROCESS_KEY. This must be set by App Mesh service.")
|
68
65
|
if not app_name:
|
@@ -75,43 +72,43 @@ class AppMeshServer(metaclass=abc.ABCMeta):
|
|
75
72
|
Used by App Mesh application process to obtain the payload from App Mesh service
|
76
73
|
that a client pushed to it.
|
77
74
|
|
78
|
-
|
79
75
|
Returns:
|
80
|
-
|
76
|
+
The payload provided by the client as returned by the service.
|
81
77
|
"""
|
82
78
|
pkey, app_name = self._get_runtime_env()
|
83
79
|
path = f"/appmesh/app/{app_name}/task"
|
80
|
+
query_params = {"process_key": pkey}
|
84
81
|
|
85
82
|
while True:
|
86
83
|
resp = self._client._request_http(
|
87
84
|
AppMeshClient.Method.GET,
|
88
85
|
path=path,
|
89
|
-
query=
|
86
|
+
query=query_params,
|
90
87
|
)
|
91
88
|
|
92
|
-
if resp.status_code
|
93
|
-
|
94
|
-
time.sleep(0.1)
|
95
|
-
continue
|
89
|
+
if resp.status_code == HTTPStatus.OK:
|
90
|
+
return resp.content
|
96
91
|
|
97
|
-
|
92
|
+
self._logger.warning("task_fetch failed with status %d: %s, retrying...", resp.status_code, resp.text)
|
93
|
+
time.sleep(self._RETRY_DELAY_SECONDS)
|
98
94
|
|
99
95
|
def task_return(self, result: Union[str, bytes]) -> None:
|
100
96
|
"""Return the result of a server-side invocation back to the original client.
|
101
97
|
|
102
|
-
Used by App Mesh application process to
|
103
|
-
after
|
98
|
+
Used by App Mesh application process to post the `result` to App Mesh service
|
99
|
+
after processing payload data so the invoking client can retrieve it.
|
104
100
|
|
105
101
|
Args:
|
106
|
-
result
|
102
|
+
result: Result payload to be delivered back to the client.
|
107
103
|
"""
|
108
104
|
pkey, app_name = self._get_runtime_env()
|
109
105
|
path = f"/appmesh/app/{app_name}/task"
|
106
|
+
query_params = {"process_key": pkey}
|
110
107
|
|
111
108
|
resp = self._client._request_http(
|
112
109
|
AppMeshClient.Method.PUT,
|
113
110
|
path=path,
|
114
|
-
query=
|
111
|
+
query=query_params,
|
115
112
|
body=result,
|
116
113
|
)
|
117
114
|
|
appmesh/server_tcp.py
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
|
4
4
|
# Standard library imports
|
5
5
|
import logging
|
6
|
-
import
|
7
|
-
from typing import Optional, Tuple
|
6
|
+
from typing import Optional, Tuple, Union
|
8
7
|
|
9
8
|
# Local imports
|
10
9
|
from .client_http import AppMeshClient
|
@@ -15,14 +14,12 @@ logger = logging.getLogger(__name__)
|
|
15
14
|
|
16
15
|
|
17
16
|
class AppMeshServerTCP(AppMeshServer):
|
18
|
-
"""
|
19
|
-
Server SDK for interacting with the local App Mesh service over TCP (TLS).
|
20
|
-
"""
|
17
|
+
"""Server SDK for interacting with the local App Mesh service over TCP (TLS)."""
|
21
18
|
|
22
19
|
def __init__(
|
23
20
|
self,
|
24
|
-
rest_ssl_verify=
|
25
|
-
rest_ssl_client_cert=None,
|
21
|
+
rest_ssl_verify: Union[bool, str] = AppMeshClient.DEFAULT_SSL_CA_CERT_PATH,
|
22
|
+
rest_ssl_client_cert: Optional[Union[str, Tuple[str, str]]] = None,
|
26
23
|
tcp_address: Tuple[str, int] = ("127.0.0.1", 6059),
|
27
24
|
*,
|
28
25
|
logger_: Optional[logging.Logger] = None,
|
@@ -34,6 +31,5 @@ class AppMeshServerTCP(AppMeshServer):
|
|
34
31
|
"""
|
35
32
|
# Deliberately avoid calling super().__init__ to inject a TCP client while keeping the same public API.
|
36
33
|
object.__init__(self)
|
37
|
-
# super().__init__(rest_ssl_verify=rest_ssl_verify, rest_ssl_client_cert=rest_ssl_client_cert)
|
38
34
|
self._client = AppMeshClientTCP(rest_ssl_verify=rest_ssl_verify, rest_ssl_client_cert=rest_ssl_client_cert, tcp_address=tcp_address)
|
39
35
|
self._logger = logger_ or logger
|
appmesh/tcp_transport.py
CHANGED
@@ -29,12 +29,10 @@ class TCPTransport:
|
|
29
29
|
|
30
30
|
Args:
|
31
31
|
address: Server address as (host, port) tuple.
|
32
|
-
|
33
32
|
ssl_verify: SSL server verification mode:
|
34
33
|
- True: Use system CA certificates
|
35
34
|
- False: Disable verification (insecure)
|
36
35
|
- str: Path to custom CA bundle or directory
|
37
|
-
|
38
36
|
ssl_client_cert: SSL client certificate:
|
39
37
|
- str: Path to PEM file with cert and key
|
40
38
|
- tuple: (cert_path, key_path)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
appmesh/__init__.py,sha256=on6GmTTwo6mrRbw_XUuf8sZdl5zBYsGT4CSf8l__NnI,2488
|
2
|
+
appmesh/app.py,sha256=bJyv_uOSMj5esMgkFWuvpMPS5ayFTBJLVll2Tvw8xB4,11213
|
3
|
+
appmesh/app_output.py,sha256=s6eqevFxETTVXSPTJX6JyGNpHHILv4ZyM7YWvlkuqQs,741
|
4
|
+
appmesh/app_run.py,sha256=m3ihaacx84o1rl2Oc3EbnppW8D-PTxdehftbWRe8rPk,1732
|
5
|
+
appmesh/appmesh_client.py,sha256=ywB2222PtJUffdfdxZcBfdhZs1KYyc7JvzMxwuK2qyI,378
|
6
|
+
appmesh/client_http.py,sha256=shkpXDEMtxExIgbeLUUknLJjkAYMCmL7rIK_kc1xgXs,48821
|
7
|
+
appmesh/client_http_oauth.py,sha256=zES-f6AnG6dUo754zd-HM6Pvu4vp_64vTKT61npY6HE,5934
|
8
|
+
appmesh/client_tcp.py,sha256=K3IneOSl8xiOIC9z4jHK_4Mhq2n8eeUDASvXJQiRjfQ,11817
|
9
|
+
appmesh/server_http.py,sha256=g2NYREF-f-vnSFVntAJDc0H43v_kNEqS7M4y7Q_DpEY,4193
|
10
|
+
appmesh/server_tcp.py,sha256=GXEVDmYwM19ZUKkRXm8eEzBep9rE1vzV-PwaTlROpFU,1364
|
11
|
+
appmesh/tcp_messages.py,sha256=E0cKWUta7NjuLoTGk-Z9CvbdZyakwG7hO8st_07E5L4,1991
|
12
|
+
appmesh/tcp_transport.py,sha256=nkml2hqSkyeJrGDKGAYjWDgOnSyYMEImVT1PQ6jeudk,8163
|
13
|
+
appmesh-1.6.15.dist-info/METADATA,sha256=dity7yE2WHJTKe3Hph5FLM1N2aKnVjQ9wHIHwO9UR_o,11814
|
14
|
+
appmesh-1.6.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
15
|
+
appmesh-1.6.15.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
16
|
+
appmesh-1.6.15.dist-info/RECORD,,
|
appmesh-1.6.13.dist-info/RECORD
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
appmesh/__init__.py,sha256=on6GmTTwo6mrRbw_XUuf8sZdl5zBYsGT4CSf8l__NnI,2488
|
2
|
-
appmesh/app.py,sha256=5kzQCvGH3LRRUTHsI2_MKEPD3M2qs8kvTxLhbNUqit4,10601
|
3
|
-
appmesh/app_output.py,sha256=s6eqevFxETTVXSPTJX6JyGNpHHILv4ZyM7YWvlkuqQs,741
|
4
|
-
appmesh/app_run.py,sha256=m3ihaacx84o1rl2Oc3EbnppW8D-PTxdehftbWRe8rPk,1732
|
5
|
-
appmesh/appmesh_client.py,sha256=ywB2222PtJUffdfdxZcBfdhZs1KYyc7JvzMxwuK2qyI,378
|
6
|
-
appmesh/client_http.py,sha256=FXCldfTZVU_5RSuSknlH1K2UiC6gOeotj-4NDQzdEhY,60752
|
7
|
-
appmesh/client_http_oauth.py,sha256=1d51o0JX_xtB8d2bEuM7_XJHcwMnhcjkbIq7GE1Zxm8,6120
|
8
|
-
appmesh/client_tcp.py,sha256=RX3T3OG4iOAju8ZPOnTjI_y97Y23_kWoNDjmKjtrBeU,11524
|
9
|
-
appmesh/server_http.py,sha256=wfyiIa2zC-uJR2ZNTGMjYWheqAfSRl0aAv5b_GYcwpE,4343
|
10
|
-
appmesh/server_tcp.py,sha256=J65kmN7DJftyW1LlF--S3keQ6VGmqXb778E79I1R0_k,1488
|
11
|
-
appmesh/tcp_messages.py,sha256=E0cKWUta7NjuLoTGk-Z9CvbdZyakwG7hO8st_07E5L4,1991
|
12
|
-
appmesh/tcp_transport.py,sha256=oUpcBXOaJhG5Hs6yqt9UG8_eENu0cEdNZIyC87LqI7Q,8165
|
13
|
-
appmesh-1.6.13.dist-info/METADATA,sha256=BJJB6M94Sz2yytdr9WRxCf56q1-LCzQ-2zQAfP5_1eU,11814
|
14
|
-
appmesh-1.6.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
15
|
-
appmesh-1.6.13.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
16
|
-
appmesh-1.6.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|