appmesh 1.3.7__py3-none-any.whl → 1.3.8__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/__init__.py +2 -2
- appmesh/appmesh_client.py +6 -1221
- appmesh/http_client.py +1216 -0
- appmesh/{appmesh_client_tcp.py → tcp_client.py} +14 -160
- appmesh/tcp_messages.py +41 -0
- appmesh/tcp_transport.py +160 -0
- {appmesh-1.3.7.dist-info → appmesh-1.3.8.dist-info}/METADATA +1 -1
- appmesh-1.3.8.dist-info/RECORD +13 -0
- {appmesh-1.3.7.dist-info → appmesh-1.3.8.dist-info}/WHEEL +1 -1
- appmesh-1.3.7.dist-info/RECORD +0 -10
- {appmesh-1.3.7.dist-info → appmesh-1.3.8.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# TCP-based App Mesh Client
|
3
2
|
# pylint: disable=line-too-long,broad-exception-raised, ,broad-exception-caught,import-outside-toplevel,protected-access
|
4
3
|
|
5
|
-
# Standard library imports
|
6
4
|
import json
|
7
5
|
import os
|
8
6
|
import socket
|
9
|
-
import ssl
|
10
7
|
import uuid
|
11
|
-
|
12
|
-
# Third-party imports
|
13
8
|
import requests
|
14
|
-
import msgpack
|
15
|
-
|
16
|
-
# Local application-specific imports
|
17
9
|
from .appmesh_client import AppMeshClient
|
10
|
+
from .tcp_transport import TCPTransport
|
11
|
+
from .tcp_messages import RequestMessage, ResponseMessage
|
18
12
|
|
19
13
|
|
20
14
|
class AppMeshClientTCP(AppMeshClient):
|
@@ -52,7 +46,6 @@ class AppMeshClientTCP(AppMeshClient):
|
|
52
46
|
"""
|
53
47
|
|
54
48
|
TCP_BLOCK_SIZE = 16 * 1024 - 128 # TLS-optimized chunk size, leaves some room for TLS overhead (like headers) within the 16 KB limit.
|
55
|
-
TCP_HEADER_LENGTH = 4
|
56
49
|
ENCODING_UTF8 = "utf-8"
|
57
50
|
HTTP_USER_AGENT_TCP = "appmesh/python/tcp"
|
58
51
|
HTTP_HEADER_KEY_X_SEND_FILE_SOCKET = "X-Send-File-Socket"
|
@@ -87,98 +80,9 @@ class AppMeshClientTCP(AppMeshClient):
|
|
87
80
|
tcp_address (Tuple[str, int], optional): Address and port for establishing a TCP connection to the server.
|
88
81
|
Defaults to `("localhost", 6059)`.
|
89
82
|
"""
|
90
|
-
self.tcp_address =
|
91
|
-
self.__socket_client = None
|
83
|
+
self.tcp_transport = TCPTransport(address=tcp_address, ssl_verify=rest_ssl_verify, ssl_client_cert=rest_ssl_client_cert)
|
92
84
|
super().__init__(rest_ssl_verify=rest_ssl_verify, rest_ssl_client_cert=rest_ssl_client_cert, jwt_token=jwt_token)
|
93
85
|
|
94
|
-
def __del__(self) -> None:
|
95
|
-
"""De-construction"""
|
96
|
-
self.__close_socket()
|
97
|
-
|
98
|
-
def __connect_socket(self) -> ssl.SSLSocket:
|
99
|
-
"""Establish tcp connection"""
|
100
|
-
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
101
|
-
# Set minimum TLS version
|
102
|
-
if hasattr(context, "minimum_version"):
|
103
|
-
context.minimum_version = ssl.TLSVersion.TLSv1_2
|
104
|
-
else:
|
105
|
-
context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
|
106
|
-
# Configure SSL verification
|
107
|
-
if not self.ssl_verify:
|
108
|
-
context.verify_mode = ssl.CERT_NONE
|
109
|
-
else:
|
110
|
-
context.verify_mode = ssl.CERT_REQUIRED # Require certificate verification
|
111
|
-
context.load_default_certs() # Load system's default CA certificates
|
112
|
-
if isinstance(self.ssl_verify, str):
|
113
|
-
if os.path.isfile(self.ssl_verify):
|
114
|
-
# Load custom CA certificate file
|
115
|
-
context.load_verify_locations(cafile=self.ssl_verify)
|
116
|
-
elif os.path.isdir(self.ssl_verify):
|
117
|
-
# Load CA certificates from directory
|
118
|
-
context.load_verify_locations(capath=self.ssl_verify)
|
119
|
-
else:
|
120
|
-
raise ValueError(f"ssl_verify path '{self.ssl_verify}' is neither a file nor a directory")
|
121
|
-
|
122
|
-
if self.ssl_client_cert is not None:
|
123
|
-
# Load client-side certificate and private key
|
124
|
-
context.load_cert_chain(certfile=self.ssl_client_cert[0], keyfile=self.ssl_client_cert[1])
|
125
|
-
|
126
|
-
# Create a TCP socket
|
127
|
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
128
|
-
sock.setblocking(True)
|
129
|
-
sock.settimeout(30) # Connection timeout set to 30 seconds
|
130
|
-
# Wrap the socket with SSL/TLS
|
131
|
-
ssl_socket = context.wrap_socket(sock, server_hostname=self.tcp_address[0])
|
132
|
-
# Connect to the server
|
133
|
-
ssl_socket.connect(self.tcp_address)
|
134
|
-
# Disable Nagle's algorithm
|
135
|
-
ssl_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
136
|
-
# After connecting, set separate timeout for recv/send
|
137
|
-
# ssl_socket.settimeout(20) # 20 seconds for recv/send
|
138
|
-
return ssl_socket
|
139
|
-
|
140
|
-
def __close_socket(self) -> None:
|
141
|
-
"""Close socket connection"""
|
142
|
-
if self.__socket_client:
|
143
|
-
try:
|
144
|
-
self.__socket_client.close()
|
145
|
-
except Exception as e:
|
146
|
-
print(f"Error closing socket: {e}")
|
147
|
-
finally:
|
148
|
-
self.__socket_client = None
|
149
|
-
|
150
|
-
def __recvall(self, length: int) -> bytearray:
|
151
|
-
"""socket recv data with fixed length
|
152
|
-
https://stackoverflow.com/questions/64466530/using-a-custom-socket-recvall-function-works-only-if-thread-is-put-to-sleep
|
153
|
-
Args:
|
154
|
-
length (bytes): data length to be received
|
155
|
-
|
156
|
-
Returns:
|
157
|
-
bytearray: Received data
|
158
|
-
|
159
|
-
Raises:
|
160
|
-
EOFError: If connection closes prematurely
|
161
|
-
ValueError: If length is invalid
|
162
|
-
"""
|
163
|
-
if length <= 0:
|
164
|
-
raise ValueError(f"Invalid length: {length}")
|
165
|
-
|
166
|
-
# Pre-allocate buffer of exact size needed
|
167
|
-
buffer = bytearray(length)
|
168
|
-
view = memoryview(buffer)
|
169
|
-
bytes_received = 0
|
170
|
-
|
171
|
-
while bytes_received < length:
|
172
|
-
# Use recv_into to read directly into our buffer
|
173
|
-
chunk_size = self.__socket_client.recv_into(view[bytes_received:], length - bytes_received)
|
174
|
-
|
175
|
-
if chunk_size == 0:
|
176
|
-
raise EOFError("Connection closed by peer")
|
177
|
-
|
178
|
-
bytes_received += chunk_size
|
179
|
-
|
180
|
-
return buffer
|
181
|
-
|
182
86
|
def _request_http(self, method: AppMeshClient.Method, path: str, query: dict = None, header: dict = None, body=None) -> requests.Response:
|
183
87
|
"""TCP API
|
184
88
|
|
@@ -193,10 +97,10 @@ class AppMeshClientTCP(AppMeshClient):
|
|
193
97
|
requests.Response: HTTP response
|
194
98
|
"""
|
195
99
|
|
196
|
-
if self.
|
197
|
-
self.
|
100
|
+
if not self.tcp_transport.connected():
|
101
|
+
self.tcp_transport.connect()
|
198
102
|
|
199
|
-
appmesh_request =
|
103
|
+
appmesh_request = RequestMessage()
|
200
104
|
if super().jwt_token:
|
201
105
|
appmesh_request.headers["Authorization"] = "Bearer " + super().jwt_token
|
202
106
|
if super().forwarding_host and len(super().forwarding_host) > 0:
|
@@ -222,16 +126,13 @@ class AppMeshClientTCP(AppMeshClient):
|
|
222
126
|
for k, v in query.items():
|
223
127
|
appmesh_request.querys[k] = v
|
224
128
|
data = appmesh_request.serialize()
|
225
|
-
self.
|
226
|
-
self.__socket_client.sendall(data)
|
129
|
+
self.tcp_transport.send_message(data)
|
227
130
|
|
228
|
-
|
229
|
-
# https://stackoverflow.com/questions/33913308/socket-module-how-to-send-integer
|
230
|
-
resp_data = self.__recvall(int.from_bytes(self.__recvall(self.TCP_HEADER_LENGTH), byteorder="big", signed=False))
|
131
|
+
resp_data = self.tcp_transport.receive_message()
|
231
132
|
if resp_data is None or len(resp_data) == 0:
|
232
|
-
self.
|
133
|
+
self.tcp_transport.close()
|
233
134
|
raise Exception("socket connection broken")
|
234
|
-
appmesh_resp =
|
135
|
+
appmesh_resp = ResponseMessage().desirialize(resp_data)
|
235
136
|
response = requests.Response()
|
236
137
|
response.status_code = appmesh_resp.http_status
|
237
138
|
response.encoding = self.ENCODING_UTF8
|
@@ -261,15 +162,8 @@ class AppMeshClientTCP(AppMeshClient):
|
|
261
162
|
raise ValueError(f"Server did not respond with socket transfer option: {self.HTTP_HEADER_KEY_X_RECV_FILE_SOCKET}")
|
262
163
|
|
263
164
|
with open(local_file, "wb") as fp:
|
264
|
-
chunk_data
|
265
|
-
chunk_size = int.from_bytes(self.__recvall(self.TCP_HEADER_LENGTH), byteorder="big", signed=False)
|
266
|
-
while chunk_size > 0:
|
267
|
-
chunk_data = self.__recvall(chunk_size)
|
268
|
-
if chunk_data is None or len(chunk_data) == 0:
|
269
|
-
self.__close_socket()
|
270
|
-
raise Exception("socket connection broken")
|
165
|
+
while chunk_data := self.tcp_transport.receive_message():
|
271
166
|
fp.write(chunk_data)
|
272
|
-
chunk_size = int.from_bytes(self.__recvall(self.TCP_HEADER_LENGTH), byteorder="big", signed=False)
|
273
167
|
|
274
168
|
if apply_file_attributes:
|
275
169
|
if "File-Mode" in resp.headers:
|
@@ -307,7 +201,6 @@ class AppMeshClientTCP(AppMeshClient):
|
|
307
201
|
header["File-User"] = str(file_stat.st_uid)
|
308
202
|
header["File-Group"] = str(file_stat.st_gid)
|
309
203
|
|
310
|
-
# https://stackoverflow.com/questions/22567306/python-requests-file-upload
|
311
204
|
resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/file/upload", header=header)
|
312
205
|
|
313
206
|
resp.raise_for_status()
|
@@ -318,45 +211,6 @@ class AppMeshClientTCP(AppMeshClient):
|
|
318
211
|
while True:
|
319
212
|
chunk_data = fp.read(chunk_size)
|
320
213
|
if not chunk_data:
|
321
|
-
self.
|
214
|
+
self.tcp_transport.send_message([])
|
322
215
|
break
|
323
|
-
self.
|
324
|
-
self.__socket_client.sendall(chunk_data)
|
325
|
-
|
326
|
-
|
327
|
-
class RequestMsg:
|
328
|
-
"""HTTP request message"""
|
329
|
-
|
330
|
-
uuid: str = ""
|
331
|
-
request_uri: str = ""
|
332
|
-
http_method: str = ""
|
333
|
-
client_addr: str = ""
|
334
|
-
body: bytes = b""
|
335
|
-
headers: dict = {}
|
336
|
-
querys: dict = {}
|
337
|
-
|
338
|
-
def serialize(self) -> bytes:
|
339
|
-
"""Serialize request message to bytes"""
|
340
|
-
# http://www.cnitblog.com/luckydmz/archive/2019/11/20/91959.html
|
341
|
-
self_dict = vars(self)
|
342
|
-
self_dict["headers"] = self.headers
|
343
|
-
self_dict["querys"] = self.querys
|
344
|
-
return msgpack.dumps(self_dict)
|
345
|
-
|
346
|
-
|
347
|
-
class ResponseMsg:
|
348
|
-
"""HTTP response message"""
|
349
|
-
|
350
|
-
uuid: str = ""
|
351
|
-
request_uri: str = ""
|
352
|
-
http_status: int = 0
|
353
|
-
body_msg_type: str = ""
|
354
|
-
body: str = ""
|
355
|
-
headers: dict = {}
|
356
|
-
|
357
|
-
def desirialize(self, buf: bytes):
|
358
|
-
"""Deserialize response message"""
|
359
|
-
dic = msgpack.unpackb(buf)
|
360
|
-
for k, v in dic.items():
|
361
|
-
setattr(self, k, v)
|
362
|
-
return self
|
216
|
+
self.tcp_transport.send_message(chunk_data)
|
appmesh/tcp_messages.py
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# tcp_messages.py
|
2
|
+
|
3
|
+
import msgpack
|
4
|
+
|
5
|
+
|
6
|
+
class RequestMessage:
|
7
|
+
"""HTTP request message"""
|
8
|
+
|
9
|
+
uuid: str = ""
|
10
|
+
request_uri: str = ""
|
11
|
+
http_method: str = ""
|
12
|
+
client_addr: str = ""
|
13
|
+
body: bytes = b""
|
14
|
+
headers: dict = {}
|
15
|
+
querys: dict = {}
|
16
|
+
|
17
|
+
def serialize(self) -> bytes:
|
18
|
+
"""Serialize request message to bytes"""
|
19
|
+
# http://www.cnitblog.com/luckydmz/archive/2019/11/20/91959.html
|
20
|
+
self_dict = vars(self)
|
21
|
+
self_dict["headers"] = self.headers
|
22
|
+
self_dict["querys"] = self.querys
|
23
|
+
return msgpack.dumps(self_dict)
|
24
|
+
|
25
|
+
|
26
|
+
class ResponseMessage:
|
27
|
+
"""HTTP response message"""
|
28
|
+
|
29
|
+
uuid: str = ""
|
30
|
+
request_uri: str = ""
|
31
|
+
http_status: int = 0
|
32
|
+
body_msg_type: str = ""
|
33
|
+
body: str = ""
|
34
|
+
headers: dict = {}
|
35
|
+
|
36
|
+
def desirialize(self, buf: bytes):
|
37
|
+
"""Deserialize response message"""
|
38
|
+
dic = msgpack.unpackb(buf)
|
39
|
+
for k, v in dic.items():
|
40
|
+
setattr(self, k, v)
|
41
|
+
return self
|
appmesh/tcp_transport.py
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# tcp_transport.py
|
2
|
+
|
3
|
+
import os
|
4
|
+
import socket
|
5
|
+
import ssl
|
6
|
+
from typing import Optional, Tuple, Union
|
7
|
+
|
8
|
+
|
9
|
+
class TCPTransport:
|
10
|
+
"""TCP Transport layer handling socket connections"""
|
11
|
+
|
12
|
+
# Number of bytes used for the message length header
|
13
|
+
# Must match the C++ service implementation which uses uint32_t (4 bytes)
|
14
|
+
# Format: Big-endian unsigned 32-bit integer
|
15
|
+
TCP_HEADER_LENGTH = 4
|
16
|
+
MAX_MESSAGE_SIZE = 300 * 1024 * 1024 # 300 MiB message size limit
|
17
|
+
|
18
|
+
def __init__(self, address: Tuple[str, int], ssl_verify: Union[bool, str], ssl_client_cert: Union[str, Tuple[str, str]]):
|
19
|
+
"""Construct an TCPTransport object to send and recieve TCP data.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
ssl_verify (Union[bool, str], optional): Specifies SSL certificate verification behavior. Can be:
|
23
|
+
- `True`: Uses the system's default CA certificates to verify the server's identity.
|
24
|
+
- `False`: Disables SSL certificate verification (insecure, intended for development).
|
25
|
+
- `str`: Specifies a custom CA bundle or directory for server certificate verification. If a string is provided,
|
26
|
+
it should either be a file path to a custom CA certificate (CA bundle) or a directory path containing multiple
|
27
|
+
certificates (CA directory).
|
28
|
+
|
29
|
+
**Note**: Unlike HTTP requests, TCP connections cannot automatically retrieve intermediate or public CA certificates.
|
30
|
+
When `rest_ssl_verify` is a path, it explicitly identifies a CA issuer to ensure certificate validation.
|
31
|
+
|
32
|
+
ssl_client_cert (Union[str, Tuple[str, str]], optional): Path to the SSL client certificate and key. If a `str`,
|
33
|
+
it should be the path to a PEM file containing both the client certificate and private key. If a `tuple`, it should
|
34
|
+
be a pair of paths: (`cert`, `key`), where `cert` is the client certificate file and `key` is the private key file.
|
35
|
+
|
36
|
+
tcp_address (Tuple[str, int], optional): Address and port for establishing a TCP connection to the server.
|
37
|
+
Defaults to `("localhost", 6059)`.
|
38
|
+
"""
|
39
|
+
self.tcp_address = address
|
40
|
+
self.ssl_verify = ssl_verify
|
41
|
+
self.ssl_client_cert = ssl_client_cert
|
42
|
+
self._socket = None
|
43
|
+
|
44
|
+
def __enter__(self):
|
45
|
+
"""Context manager entry"""
|
46
|
+
if not self.connected():
|
47
|
+
self.connect()
|
48
|
+
return self
|
49
|
+
|
50
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
51
|
+
"""Context manager exit"""
|
52
|
+
self.close()
|
53
|
+
|
54
|
+
def __del__(self) -> None:
|
55
|
+
"""De-construction"""
|
56
|
+
self.close()
|
57
|
+
|
58
|
+
def connect(self) -> None:
|
59
|
+
"""Establish tcp connection"""
|
60
|
+
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
61
|
+
# Set minimum TLS version
|
62
|
+
if hasattr(context, "minimum_version"):
|
63
|
+
context.minimum_version = ssl.TLSVersion.TLSv1_2
|
64
|
+
else:
|
65
|
+
context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
|
66
|
+
# Configure SSL verification
|
67
|
+
if not self.ssl_verify:
|
68
|
+
context.verify_mode = ssl.CERT_NONE
|
69
|
+
else:
|
70
|
+
context.verify_mode = ssl.CERT_REQUIRED # Require certificate verification
|
71
|
+
context.load_default_certs() # Load system's default CA certificates
|
72
|
+
if isinstance(self.ssl_verify, str):
|
73
|
+
if os.path.isfile(self.ssl_verify):
|
74
|
+
# Load custom CA certificate file
|
75
|
+
context.load_verify_locations(cafile=self.ssl_verify)
|
76
|
+
elif os.path.isdir(self.ssl_verify):
|
77
|
+
# Load CA certificates from directory
|
78
|
+
context.load_verify_locations(capath=self.ssl_verify)
|
79
|
+
else:
|
80
|
+
raise ValueError(f"ssl_verify path '{self.ssl_verify}' is neither a file nor a directory")
|
81
|
+
|
82
|
+
if self.ssl_client_cert is not None:
|
83
|
+
# Load client-side certificate and private key
|
84
|
+
context.load_cert_chain(certfile=self.ssl_client_cert[0], keyfile=self.ssl_client_cert[1])
|
85
|
+
|
86
|
+
# Create a TCP socket
|
87
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
88
|
+
sock.setblocking(True)
|
89
|
+
sock.settimeout(30) # Connection timeout set to 30 seconds
|
90
|
+
# Wrap the socket with SSL/TLS
|
91
|
+
ssl_socket = context.wrap_socket(sock, server_hostname=self.tcp_address[0])
|
92
|
+
# Connect to the server
|
93
|
+
ssl_socket.connect(self.tcp_address)
|
94
|
+
# Disable Nagle's algorithm
|
95
|
+
ssl_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
96
|
+
# After connecting, set separate timeout for recv/send
|
97
|
+
# ssl_socket.settimeout(20) # 20 seconds for recv/send
|
98
|
+
self._socket = ssl_socket
|
99
|
+
|
100
|
+
def close(self) -> None:
|
101
|
+
"""Close socket connection"""
|
102
|
+
if self._socket:
|
103
|
+
try:
|
104
|
+
self._socket.close()
|
105
|
+
except Exception as e:
|
106
|
+
print(f"Error closing socket: {e}")
|
107
|
+
finally:
|
108
|
+
self._socket = None
|
109
|
+
|
110
|
+
def connected(self) -> bool:
|
111
|
+
"""Check whether socket is connected"""
|
112
|
+
return self._socket is not None
|
113
|
+
|
114
|
+
def send_message(self, data) -> None:
|
115
|
+
"""Send a message with a prefixed header indicating its length"""
|
116
|
+
length = len(data)
|
117
|
+
self._socket.sendall(length.to_bytes(self.TCP_HEADER_LENGTH, byteorder="big", signed=False))
|
118
|
+
if length > 0:
|
119
|
+
self._socket.sendall(data)
|
120
|
+
|
121
|
+
def receive_message(self) -> Optional[bytearray]:
|
122
|
+
"""Receive a message with a prefixed header indicating its length"""
|
123
|
+
length = int.from_bytes(self._recvall(self.TCP_HEADER_LENGTH), byteorder="big", signed=False)
|
124
|
+
if length > self.MAX_MESSAGE_SIZE:
|
125
|
+
raise ValueError(f"Message size {length} exceeds maximum allowed {self.MAX_MESSAGE_SIZE}")
|
126
|
+
if length > 0:
|
127
|
+
return self._recvall(length)
|
128
|
+
return None
|
129
|
+
|
130
|
+
def _recvall(self, length: int) -> bytearray:
|
131
|
+
"""socket recv data with fixed length
|
132
|
+
https://stackoverflow.com/questions/64466530/using-a-custom-socket-recvall-function-works-only-if-thread-is-put-to-sleep
|
133
|
+
Args:
|
134
|
+
length (int): data length to be received
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
bytearray: Received data
|
138
|
+
|
139
|
+
Raises:
|
140
|
+
EOFError: If connection closes prematurely
|
141
|
+
ValueError: If length is invalid
|
142
|
+
"""
|
143
|
+
if length <= 0:
|
144
|
+
raise ValueError(f"Invalid length: {length}")
|
145
|
+
|
146
|
+
# Pre-allocate buffer of exact size needed
|
147
|
+
buffer = bytearray(length)
|
148
|
+
view = memoryview(buffer)
|
149
|
+
bytes_received = 0
|
150
|
+
|
151
|
+
while bytes_received < length:
|
152
|
+
# Use recv_into to read directly into our buffer
|
153
|
+
chunk_size = self._socket.recv_into(view[bytes_received:], length - bytes_received)
|
154
|
+
|
155
|
+
if chunk_size == 0:
|
156
|
+
raise EOFError("Connection closed by peer")
|
157
|
+
|
158
|
+
bytes_received += chunk_size
|
159
|
+
|
160
|
+
return buffer
|
@@ -0,0 +1,13 @@
|
|
1
|
+
appmesh/__init__.py,sha256=vgiSdMzlzDwgHxBMDoFaKWb77g2nJVciRf4z_ssAlwE,431
|
2
|
+
appmesh/app.py,sha256=trPD1i7PFv7DTuy33Hr8-AC36r3h3XIBejdB3cUU8C8,10438
|
3
|
+
appmesh/app_output.py,sha256=JK_TMKgjvaw4n_ys_vmN5S4MyWVZpmD7NlKz_UyMIM8,1015
|
4
|
+
appmesh/app_run.py,sha256=D4j_SaA16_RtZ2-Ey6X4HIyngvLdfFHgyzYurDT1ATc,1753
|
5
|
+
appmesh/appmesh_client.py,sha256=0ltkqHZUq094gKneYmC0bEZCP0X9kHTp9fccKdWFWP0,339
|
6
|
+
appmesh/http_client.py,sha256=miO52kW8d9s0tGn42SxbOPtVNu9ZL8HDFCoCCMXm_EA,47484
|
7
|
+
appmesh/tcp_client.py,sha256=cbnx_YbBMBbJeR5DY7u5jmlgHcYqbjzffirSiJ-zT1o,10852
|
8
|
+
appmesh/tcp_messages.py,sha256=w1Kehz_aX4X2CYAUsy9mFVJRhxnLQwwc6L58W4YkQqs,969
|
9
|
+
appmesh/tcp_transport.py,sha256=YlKMaE-oaKLmGuBdWIyKz3YH4ZPMgJWHBZYbINtUoYM,6934
|
10
|
+
appmesh-1.3.8.dist-info/METADATA,sha256=GCrx58vUH1DvcQfLWXjG-pVJowoD7ykM6ZehOZVTGMI,11191
|
11
|
+
appmesh-1.3.8.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
12
|
+
appmesh-1.3.8.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
13
|
+
appmesh-1.3.8.dist-info/RECORD,,
|
appmesh-1.3.7.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
appmesh/__init__.py,sha256=2-k6yrZr3TLHZ00YSiFHAYzsccSQ3eWZgoRs1eavZb8,442
|
2
|
-
appmesh/app.py,sha256=trPD1i7PFv7DTuy33Hr8-AC36r3h3XIBejdB3cUU8C8,10438
|
3
|
-
appmesh/app_output.py,sha256=JK_TMKgjvaw4n_ys_vmN5S4MyWVZpmD7NlKz_UyMIM8,1015
|
4
|
-
appmesh/app_run.py,sha256=D4j_SaA16_RtZ2-Ey6X4HIyngvLdfFHgyzYurDT1ATc,1753
|
5
|
-
appmesh/appmesh_client.py,sha256=9zysxEzSL3y2Csm7teLk7l6hknKzzTd-l4kWKeuuOj4,47571
|
6
|
-
appmesh/appmesh_client_tcp.py,sha256=BcPQcJqdPIWqP4vbRKHHEvlkkI83mqNfUse6AUGDbkE,16424
|
7
|
-
appmesh-1.3.7.dist-info/METADATA,sha256=rQoOicSO7Hz9lIocYszWWjpcpf65QzKFeILPyiB_tCA,11191
|
8
|
-
appmesh-1.3.7.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
9
|
-
appmesh-1.3.7.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
10
|
-
appmesh-1.3.7.dist-info/RECORD,,
|
File without changes
|