appmesh 1.3.3__py3-none-any.whl → 1.3.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.
appmesh/appmesh_client.py CHANGED
@@ -25,14 +25,14 @@ DEFAULT_TOKEN_EXPIRE_SECONDS = "P1W" # default 7 day(s)
25
25
  DEFAULT_RUN_APP_TIMEOUT_SECONDS = "P2D" # 2 days
26
26
  DEFAULT_RUN_APP_LIFECYCLE_SECONDS = "P2DT12H" # 2.5 days
27
27
 
28
+ DEFAULT_SSL_CA_PEM_FILE = "/opt/appmesh/ssl/ca.pem"
29
+ DEFAULT_SSL_CLIENT_PEM_FILE = "/opt/appmesh/ssl/client.pem"
30
+ DEFAULT_SSL_CLIENT_PEM_KEY_FILE = "/opt/appmesh/ssl/client-key.pem"
31
+
28
32
  REST_TEXT_MESSAGE_JSON_KEY = "message"
29
33
  MESSAGE_ENCODING_UTF8 = "utf-8"
30
34
  TCP_MESSAGE_HEADER_LENGTH = 4
31
35
 
32
- _SSL_CA_PEM_FILE = "/opt/appmesh/ssl/ca.pem"
33
- _SSL_CLIENT_PEM_FILE = "/opt/appmesh/ssl/client.pem"
34
- _SSL_CLIENT_PEM_KEY_FILE = "/opt/appmesh/ssl/client-key.pem"
35
-
36
36
  HTTP_USER_AGENT = "appmesh/python"
37
37
  HTTP_USER_AGENT_TCP = "appmesh/python/tcp"
38
38
  HTTP_HEADER_KEY_USER_AGENT = "User-Agent"
@@ -437,8 +437,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
437
437
  def __init__(
438
438
  self,
439
439
  rest_url: str = "https://127.0.0.1:6060",
440
- rest_ssl_verify=_SSL_CA_PEM_FILE if os.path.exists(_SSL_CA_PEM_FILE) else False,
441
- rest_ssl_client_cert=(_SSL_CLIENT_PEM_FILE, _SSL_CLIENT_PEM_KEY_FILE) if os.path.exists(_SSL_CLIENT_PEM_FILE) else None,
440
+ rest_ssl_verify=DEFAULT_SSL_CA_PEM_FILE if os.path.exists(DEFAULT_SSL_CA_PEM_FILE) else False,
441
+ rest_ssl_client_cert=(DEFAULT_SSL_CLIENT_PEM_FILE, DEFAULT_SSL_CLIENT_PEM_KEY_FILE) if os.path.exists(DEFAULT_SSL_CLIENT_PEM_FILE) else None,
442
442
  rest_timeout=(60, 300),
443
443
  jwt_token=None,
444
444
  ):
@@ -1221,24 +1221,20 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1221
1221
  ########################################
1222
1222
  # File management
1223
1223
  ########################################
1224
- def file_download(self, file_path: str, local_file: str, apply_file_attributes: bool = True) -> bool:
1224
+ def file_download(self, file_path: str, local_file: str, apply_file_attributes: bool = True) -> None:
1225
1225
  """Copy a remote file to local. Optionally, the local file will have the same permission as the remote file.
1226
1226
 
1227
1227
  Args:
1228
1228
  file_path (str): the remote file path.
1229
1229
  local_file (str): the local file path to be downloaded.
1230
1230
  apply_file_attributes (bool): whether to apply file attributes (permissions, owner, group) to the local file.
1231
-
1232
- Returns:
1233
- bool: success or failure.
1234
1231
  """
1235
1232
  resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/file/download", header={"File-Path": file_path})
1236
- if resp.status_code != HTTPStatus.OK:
1237
- raise Exception(resp.text)
1233
+ resp.raise_for_status()
1238
1234
 
1239
1235
  # Write the file content locally
1240
1236
  with open(local_file, "wb") as fp:
1241
- for chunk in resp.iter_content(chunk_size=512):
1237
+ for chunk in resp.iter_content(chunk_size=8192): # 8 KB
1242
1238
  if chunk:
1243
1239
  fp.write(chunk)
1244
1240
 
@@ -1251,11 +1247,10 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1251
1247
  file_gid = int(resp.headers["File-Group"])
1252
1248
  try:
1253
1249
  os.chown(path=local_file, uid=file_uid, gid=file_gid)
1254
- except Exception as ex:
1255
- print(ex)
1256
- return resp.status_code == HTTPStatus.OK
1250
+ except PermissionError:
1251
+ print(f"Warning: Unable to change owner/group of {local_file}. Operation requires elevated privileges.")
1257
1252
 
1258
- def file_upload(self, local_file: str, file_path: str, apply_file_attributes: bool = True) -> bool:
1253
+ def file_upload(self, local_file: str, file_path: str, apply_file_attributes: bool = True) -> None:
1259
1254
  """Upload a local file to the remote server. Optionally, the remote file will have the same permission as the local file.
1260
1255
 
1261
1256
  Dependency:
@@ -1266,10 +1261,10 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1266
1261
  local_file (str): the local file path.
1267
1262
  file_path (str): the target remote file to be uploaded.
1268
1263
  apply_file_attributes (bool): whether to upload file attributes (permissions, owner, group) along with the file.
1269
-
1270
- Returns:
1271
- bool: success or failure.
1272
1264
  """
1265
+ if not os.path.exists(local_file):
1266
+ raise FileNotFoundError(f"Local file not found: {local_file}")
1267
+
1273
1268
  from requests_toolbelt import MultipartEncoder
1274
1269
 
1275
1270
  with open(file=local_file, mode="rb") as fp:
@@ -1291,9 +1286,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1291
1286
  header=header,
1292
1287
  body=encoder,
1293
1288
  )
1294
- if resp.status_code != HTTPStatus.OK:
1295
- raise Exception(resp.text)
1296
- return True
1289
+ resp.raise_for_status()
1297
1290
 
1298
1291
  ########################################
1299
1292
  # Application run
@@ -1450,11 +1443,11 @@ class AppMeshClientTCP(AppMeshClient):
1450
1443
  """
1451
1444
  Client SDK for interacting with the App Mesh service over TCP, with enhanced support for large file transfers.
1452
1445
 
1453
- The `AppMeshClientTCP` class extends the functionality of `AppMeshClient` by offering a TCP-based communication layer
1454
- for the App Mesh REST API. It overrides the file download and upload methods to support large file transfers with
1446
+ The `AppMeshClientTCP` class extends the functionality of `AppMeshClient` by offering a TCP-based communication layer
1447
+ for the App Mesh REST API. It overrides the file download and upload methods to support large file transfers with
1455
1448
  improved performance, leveraging TCP for lower latency and higher throughput compared to HTTP.
1456
1449
 
1457
- This client is suitable for applications requiring efficient data transfers and high-throughput operations within the
1450
+ This client is suitable for applications requiring efficient data transfers and high-throughput operations within the
1458
1451
  App Mesh ecosystem, while maintaining compatibility with all other attributes and methods from `AppMeshClient`.
1459
1452
 
1460
1453
  Dependency:
@@ -1482,7 +1475,7 @@ class AppMeshClientTCP(AppMeshClient):
1482
1475
 
1483
1476
  def __init__(
1484
1477
  self,
1485
- rest_ssl_verify=_SSL_CA_PEM_FILE if os.path.exists(_SSL_CA_PEM_FILE) else False,
1478
+ rest_ssl_verify=DEFAULT_SSL_CA_PEM_FILE if os.path.exists(DEFAULT_SSL_CA_PEM_FILE) else False,
1486
1479
  rest_ssl_client_cert=None,
1487
1480
  jwt_token=None,
1488
1481
  tcp_address=("localhost", 6059),
@@ -1664,31 +1657,34 @@ class AppMeshClientTCP(AppMeshClient):
1664
1657
  ########################################
1665
1658
  # File management
1666
1659
  ########################################
1667
- def file_download(self, file_path: str, local_file: str) -> bool:
1660
+ def file_download(self, file_path: str, local_file: str, apply_file_attributes: bool = True) -> None:
1668
1661
  """Copy a remote file to local, the local file will have the same permission as the remote file
1669
1662
 
1670
1663
  Args:
1671
1664
  file_path (str): the remote file path.
1672
1665
  local_file (str): the local file path to be downloaded.
1673
-
1674
- Returns:
1675
- bool: success or failure.
1666
+ apply_file_attributes (bool): whether to apply file attributes (permissions, owner, group) to the local file.
1676
1667
  """
1677
- header = {}
1678
- header["File-Path"] = file_path
1668
+ header = {"File-Path": file_path}
1679
1669
  header[HTTP_HEADER_KEY_X_RECV_FILE_SOCKET] = "true"
1680
1670
  resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/file/download", header=header)
1681
- if resp.status_code == HTTPStatus.OK and HTTP_HEADER_KEY_X_RECV_FILE_SOCKET in resp.headers:
1682
- with open(local_file, "wb") as fp:
1683
- chunk_data = bytes()
1671
+
1672
+ resp.raise_for_status()
1673
+ if HTTP_HEADER_KEY_X_RECV_FILE_SOCKET not in resp.headers:
1674
+ raise ValueError(f"Server did not respond with socket transfer option: {HTTP_HEADER_KEY_X_RECV_FILE_SOCKET}")
1675
+
1676
+ with open(local_file, "wb") as fp:
1677
+ chunk_data = bytes()
1678
+ chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), byteorder="big", signed=False)
1679
+ while chunk_size > 0:
1680
+ chunk_data = self.__recvall(chunk_size)
1681
+ if chunk_data is None or len(chunk_data) == 0:
1682
+ self.__close_socket()
1683
+ raise Exception("socket connection broken")
1684
+ fp.write(chunk_data)
1684
1685
  chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), byteorder="big", signed=False)
1685
- while chunk_size > 0:
1686
- chunk_data = self.__recvall(chunk_size)
1687
- if chunk_data is None or len(chunk_data) == 0:
1688
- self.__close_socket()
1689
- raise Exception("socket connection broken")
1690
- fp.write(chunk_data)
1691
- chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), byteorder="big", signed=False)
1686
+
1687
+ if apply_file_attributes:
1692
1688
  if "File-Mode" in resp.headers:
1693
1689
  os.chmod(path=local_file, mode=int(resp.headers["File-Mode"]))
1694
1690
  if "File-User" in resp.headers and "File-Group" in resp.headers:
@@ -1696,12 +1692,10 @@ class AppMeshClientTCP(AppMeshClient):
1696
1692
  file_gid = int(resp.headers["File-Group"])
1697
1693
  try:
1698
1694
  os.chown(path=local_file, uid=file_uid, gid=file_gid)
1699
- except Exception as ex:
1700
- print(ex)
1701
- return True
1702
- return False
1695
+ except PermissionError:
1696
+ print(f"Warning: Unable to change owner/group of {local_file}. Operation requires elevated privileges.")
1703
1697
 
1704
- def file_upload(self, local_file: str, file_path: str):
1698
+ def file_upload(self, local_file: str, file_path: str, apply_file_attributes: bool = True) -> None:
1705
1699
  """Upload a local file to the remote server, the remote file will have the same permission as the local file
1706
1700
 
1707
1701
  Dependency:
@@ -1711,29 +1705,35 @@ class AppMeshClientTCP(AppMeshClient):
1711
1705
  Args:
1712
1706
  local_file (str): the local file path.
1713
1707
  file_path (str): the target remote file to be uploaded.
1714
-
1715
- Returns:
1716
- bool: success or failure.
1717
- str: text message.
1708
+ apply_file_attributes (bool): whether to upload file attributes (permissions, owner, group) along with the file.
1718
1709
  """
1710
+ if not os.path.exists(local_file):
1711
+ raise FileNotFoundError(f"Local file not found: {local_file}")
1712
+
1719
1713
  with open(file=local_file, mode="rb") as fp:
1720
- file_stat = os.stat(local_file)
1721
- header = {}
1722
- header["File-Path"] = file_path
1723
- header["File-Mode"] = str(file_stat.st_mode)
1724
- header["File-User"] = str(file_stat.st_uid)
1725
- header["File-Group"] = str(file_stat.st_gid)
1726
- header["Content-Type"] = "text/plain"
1714
+ header = {"File-Path": file_path, "Content-Type": "text/plain"}
1727
1715
  header[HTTP_HEADER_KEY_X_SEND_FILE_SOCKET] = "true"
1716
+
1717
+ if apply_file_attributes:
1718
+ file_stat = os.stat(local_file)
1719
+ header["File-Mode"] = str(file_stat.st_mode)
1720
+ header["File-User"] = str(file_stat.st_uid)
1721
+ header["File-Group"] = str(file_stat.st_gid)
1722
+
1728
1723
  # https://stackoverflow.com/questions/22567306/python-requests-file-upload
1729
1724
  resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/file/upload", header=header)
1730
- if resp.status_code == HTTPStatus.OK and HTTP_HEADER_KEY_X_SEND_FILE_SOCKET in resp.headers:
1731
- chunk_size = 8 * 1024 # (8 KB in bytes), 131072 bytes (128 KB) is default max ssl buffer size
1725
+
1726
+ resp.raise_for_status()
1727
+ if HTTP_HEADER_KEY_X_SEND_FILE_SOCKET not in resp.headers:
1728
+ raise ValueError(f"Server did not respond with socket transfer option: {HTTP_HEADER_KEY_X_SEND_FILE_SOCKET}")
1729
+
1730
+ # TLS-optimized chunk size (slightly less than maximum TLS record size)
1731
+ # leaves some room for TLS overhead (like headers) within the 16 KB limit.
1732
+ chunk_size = 16 * 1024 - 512 # target to 16KB
1733
+ while True:
1732
1734
  chunk_data = fp.read(chunk_size)
1733
- while chunk_data:
1734
- self.__socket_client.sendall(len(chunk_data).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
1735
- self.__socket_client.sendall(chunk_data)
1736
- chunk_data = fp.read(chunk_size)
1737
- self.__socket_client.sendall(int(0).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
1738
- return True, ""
1739
- return False, resp.json()[REST_TEXT_MESSAGE_JSON_KEY]
1735
+ if not chunk_data:
1736
+ self.__socket_client.sendall((0).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
1737
+ break
1738
+ self.__socket_client.sendall(len(chunk_data).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
1739
+ self.__socket_client.sendall(chunk_data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: appmesh
3
- Version: 1.3.3
3
+ Version: 1.3.4
4
4
  Summary: Client SDK for App Mesh
5
5
  Home-page: https://github.com/laoshanxi/app-mesh
6
6
  Author: laoshanxi
@@ -0,0 +1,6 @@
1
+ appmesh/__init__.py,sha256=xRdXeFHEieRauuJZElbEBASgXG0ZzU1a5_0isAhM7Gw,11
2
+ appmesh/appmesh_client.py,sha256=6lnfsR6SAhF66jWBPIVPbC43LPhyAL3amBHxSx30Cu4,68327
3
+ appmesh-1.3.4.dist-info/METADATA,sha256=TZjYqpu2P33ZcN7ue8uTAMobwavbud7_zr9Eo2si7NY,11191
4
+ appmesh-1.3.4.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
5
+ appmesh-1.3.4.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
6
+ appmesh-1.3.4.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- appmesh/__init__.py,sha256=xRdXeFHEieRauuJZElbEBASgXG0ZzU1a5_0isAhM7Gw,11
2
- appmesh/appmesh_client.py,sha256=Hsp4at6YCLcAoz8eRx928amyCTqN4ZAIFnVHxEbzDrI,67720
3
- appmesh-1.3.3.dist-info/METADATA,sha256=73_wYNYMLoHLoew35YGTd2bGKWhfScEObKhr07yyHx0,11191
4
- appmesh-1.3.3.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
5
- appmesh-1.3.3.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
6
- appmesh-1.3.3.dist-info/RECORD,,