appmesh 1.6.9__py3-none-any.whl → 1.6.11__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 CHANGED
@@ -11,6 +11,7 @@ Example:
11
11
 
12
12
  import sys
13
13
  from types import ModuleType
14
+ from typing import TYPE_CHECKING
14
15
 
15
16
  __all__ = ["App", "AppMeshClient", "AppMeshClientTCP", "AppMeshClientOAuth", "AppMeshServer", "AppMeshServerTCP"]
16
17
 
@@ -24,6 +25,17 @@ _LAZY_IMPORTS = {
24
25
  }
25
26
 
26
27
 
28
+ if TYPE_CHECKING:
29
+ # Provide explicit imports for static analyzers and type checkers
30
+ # These imports are only executed during type checking and won't affect runtime.
31
+ from .app import App # noqa: F401
32
+ from .client_http import AppMeshClient # noqa: F401
33
+ from .client_tcp import AppMeshClientTCP # noqa: F401
34
+ from .client_http_oauth import AppMeshClientOAuth # noqa: F401
35
+ from .server_http import AppMeshServer # noqa: F401
36
+ from .server_tcp import AppMeshServerTCP # noqa: F401
37
+
38
+
27
39
  def _lazy_import(name):
28
40
  """Helper function for lazy importing."""
29
41
  if name in _LAZY_IMPORTS:
appmesh/app_output.py CHANGED
@@ -1,11 +1,11 @@
1
1
  # app_output.py
2
+ # pylint: disable=line-too-long
2
3
  """Application output information"""
3
4
 
5
+ # Standard library imports
4
6
  from http import HTTPStatus
5
7
  from typing import Optional
6
8
 
7
- # pylint: disable=line-too-long
8
-
9
9
 
10
10
  class AppOutput(object):
11
11
  """
appmesh/client_http.py CHANGED
@@ -1,7 +1,10 @@
1
1
  # client_http.py
2
2
  # pylint: disable=broad-exception-raised,line-too-long,broad-exception-caught,too-many-lines,import-outside-toplevel
3
+
4
+ # Standard library imports
3
5
  import abc
4
6
  import base64
7
+ import http.cookiejar as cookiejar
5
8
  import json
6
9
  import locale
7
10
  import logging
@@ -9,19 +12,21 @@ import os
9
12
  import sys
10
13
  import threading
11
14
  import time
12
- import requests
13
- import http.cookiejar as cookiejar
14
15
  from datetime import datetime
15
16
  from enum import Enum, unique
16
17
  from http import HTTPStatus
17
- import threading
18
18
  from typing import Optional, Tuple, Union
19
19
  from urllib import parse
20
+
21
+ # Third-party imports
20
22
  import aniso8601
21
23
  import jwt
24
+ import requests
25
+
26
+ # Local imports
22
27
  from .app import App
23
- from .app_run import AppRun
24
28
  from .app_output import AppOutput
29
+ from .app_run import AppRun
25
30
 
26
31
 
27
32
  class AppMeshClient(metaclass=abc.ABCMeta):
@@ -129,6 +134,10 @@ class AppMeshClient(metaclass=abc.ABCMeta):
129
134
  HTTP_HEADER_KEY_USER_AGENT = "User-Agent"
130
135
  HTTP_HEADER_KEY_X_TARGET_HOST = "X-Target-Host"
131
136
  HTTP_HEADER_KEY_X_FILE_PATH = "X-File-Path"
137
+ HTTP_HEADER_JWT_set_cookie = "X-Set-Cookie"
138
+ HTTP_HEADER_NAME_CSRF_TOKEN = "X-CSRF-Token"
139
+ COOKIE_TOKEN = "appmesh_auth_token"
140
+ COOKIE_CSRF_TOKEN = "appmesh_csrf_token"
132
141
 
133
142
  @unique
134
143
  class Method(Enum):
@@ -216,7 +225,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
216
225
  rest_timeout (tuple, optional): HTTP connection timeouts for API requests, as `(connect_timeout, read_timeout)`.
217
226
  The default is `(60, 300)`, where `60` seconds is the maximum time to establish a connection and `300` seconds for the maximum read duration.
218
227
 
219
- rest_cookie_file (str, optional): Path to a file for storing session cookies. If provided, cookies will be saved to and loaded from this file to maintain session state across client instances.
228
+ rest_cookie_file (str, optional): Path to a file for storing session cookies.
229
+ If provided, cookies will be saved to and loaded from this file to maintain session state across client instances instead of keep jwt_token.
220
230
 
221
231
  jwt_token (str, optional): JWT token for API authentication, used in headers to authorize requests where required.
222
232
  auto_refresh_token (bool, optional): Enable automatic token refresh before expiration.
@@ -231,25 +241,16 @@ class AppMeshClient(metaclass=abc.ABCMeta):
231
241
  self.rest_timeout = rest_timeout
232
242
  self._forward_to = None
233
243
 
234
- # Session and cookie management
235
- self._lock = threading.Lock()
236
- self.session = requests.Session()
237
- self.cookie_file = rest_cookie_file
238
- if self.cookie_file:
239
- self.session.cookies = cookiejar.MozillaCookieJar(self.cookie_file)
240
- if os.path.exists(self.cookie_file):
241
- self.session.cookies.load(ignore_discard=True, ignore_expires=True)
242
- else:
243
- os.makedirs(os.path.dirname(self.cookie_file), exist_ok=True)
244
- self.session.cookies.save(ignore_discard=True, ignore_expires=True)
245
- if os.name == "posix":
246
- os.chmod(self.cookie_file, 0o600) # User read/write only
247
-
248
244
  # Token auto-refresh
249
245
  self._token_refresh_timer = None
250
246
  self._auto_refresh_token = auto_refresh_token
251
247
  self.jwt_token = jwt_token # Set property last after all dependencies are initialized to setup refresh timer
252
248
 
249
+ # Session and cookie management
250
+ self._lock = threading.Lock()
251
+ self.session = requests.Session()
252
+ self.cookie_file = self._load_cookies(rest_cookie_file)
253
+
253
254
  @staticmethod
254
255
  def _ensure_logging_configured():
255
256
  """Ensure logging is configured. If no handlers are configured, add a default console handler."""
@@ -259,6 +260,45 @@ class AppMeshClient(metaclass=abc.ABCMeta):
259
260
  def _get_access_token(self) -> str:
260
261
  return self.jwt_token
261
262
 
263
+ def _load_cookies(self, cookie_file: Optional[str]) -> str:
264
+ """Load cookies from the cookie file and return the file path ."""
265
+ if not cookie_file:
266
+ return ""
267
+
268
+ self.session.cookies = cookiejar.MozillaCookieJar(cookie_file)
269
+ if os.path.exists(cookie_file):
270
+ self.session.cookies.load(ignore_discard=True, ignore_expires=True)
271
+ self.jwt_token = self._get_cookie_value(self.session.cookies, self.COOKIE_TOKEN)
272
+ else:
273
+ os.makedirs(os.path.dirname(cookie_file), exist_ok=True)
274
+ self.session.cookies.save(ignore_discard=True, ignore_expires=True)
275
+ if os.name == "posix":
276
+ os.chmod(cookie_file, 0o600) # User read/write only
277
+ return cookie_file
278
+
279
+ @staticmethod
280
+ def _get_cookie_value(cookies, name, check_expiry=True) -> Optional[str]:
281
+ """Get cookie value by name, checking expiry if requested."""
282
+ # If it's a RequestsCookieJar, use .get() but check expiry manually if requested
283
+ if hasattr(cookies, "get") and not isinstance(cookies, list):
284
+ cookie = cookies.get(name)
285
+ if cookie is None:
286
+ return None
287
+ if check_expiry and getattr(cookie, "expires", None):
288
+ if cookie.expires < time.time():
289
+ return None # expired
290
+ return cookie.value if hasattr(cookie, "value") else cookie
291
+
292
+ # Otherwise, assume it's a MozillaCookieJar — iterate manually
293
+ for c in cookies:
294
+ if c.name == name:
295
+ if check_expiry and getattr(c, "expires", None):
296
+ if c.expires < time.time():
297
+ return None # expired
298
+ return c.value
299
+
300
+ return None
301
+
262
302
  def _check_and_refresh_token(self):
263
303
  """Check and refresh token if needed, then schedule next check.
264
304
 
@@ -407,6 +447,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
407
447
  - Refresh tokens before expiration
408
448
  - Validate token format before setting
409
449
  """
450
+ if self._jwt_token == token:
451
+ return # No change
410
452
  self._jwt_token = token
411
453
 
412
454
  # handle refresh
@@ -418,7 +460,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
418
460
 
419
461
  # handle session
420
462
  with self._lock:
421
- if self.cookie_file:
463
+ if hasattr(self, "cookie_file") and self.cookie_file:
422
464
  self.session.cookies.save(ignore_discard=True, ignore_expires=True)
423
465
 
424
466
  @property
@@ -499,6 +541,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
499
541
  self.HTTP_HEADER_KEY_AUTH: "Basic " + base64.b64encode(f"{user_name}:{user_pwd}".encode()).decode(),
500
542
  "X-Expire-Seconds": str(self._parse_duration(timeout_seconds)),
501
543
  **({"X-Audience": audience} if audience else {}),
544
+ **({self.HTTP_HEADER_JWT_set_cookie: "true"} if self.cookie_file else {}),
502
545
  # **({"X-Totp-Code": totp_code} if totp_code else {}),
503
546
  },
504
547
  )
@@ -539,6 +582,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
539
582
  "totp_challenge": challenge,
540
583
  "expire_seconds": self._parse_duration(timeout),
541
584
  },
585
+ header={self.HTTP_HEADER_JWT_set_cookie: "true"} if self.cookie_file else {},
542
586
  )
543
587
  if resp.status_code == HTTPStatus.OK and "access_token" in resp.json():
544
588
  self.jwt_token = resp.json()["access_token"]
@@ -1422,9 +1466,13 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1422
1466
 
1423
1467
  # Prepare headers
1424
1468
  header = {} if header is None else header
1425
- token = self._get_access_token()
1426
- if token:
1427
- header[self.HTTP_HEADER_KEY_AUTH] = f"Bearer {token}"
1469
+
1470
+ # JWT or Cookie token
1471
+ if self.cookie_file and self._get_cookie_value(self.session.cookies, self.COOKIE_CSRF_TOKEN):
1472
+ header[self.HTTP_HEADER_NAME_CSRF_TOKEN] = self._get_cookie_value(self.session.cookies, self.COOKIE_CSRF_TOKEN)
1473
+ elif self._get_access_token():
1474
+ header[self.HTTP_HEADER_KEY_AUTH] = f"Bearer {self._get_access_token()}"
1475
+
1428
1476
  if self.forward_to and len(self.forward_to) > 0:
1429
1477
  if ":" in self.forward_to:
1430
1478
  header[self.HTTP_HEADER_KEY_X_TARGET_HOST] = self.forward_to
appmesh/client_tcp.py CHANGED
@@ -1,15 +1,20 @@
1
1
  # client_tcp.py
2
2
  # pylint: disable=line-too-long,broad-exception-raised,broad-exception-caught,import-outside-toplevel,protected-access
3
3
 
4
+ # Standard library imports
4
5
  import json
5
6
  import os
6
- import sys
7
7
  import socket
8
+ import sys
8
9
  import uuid
10
+
11
+ # Third-party imports
9
12
  import requests
13
+
14
+ # Local imports
10
15
  from .client_http import AppMeshClient
11
- from .tcp_transport import TCPTransport
12
16
  from .tcp_messages import RequestMessage, ResponseMessage
17
+ from .tcp_transport import TCPTransport
13
18
 
14
19
 
15
20
  class AppMeshClientTCP(AppMeshClient):
appmesh/server_http.py CHANGED
@@ -1,12 +1,15 @@
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
+ # Standard library imports
4
5
  import abc
5
6
  import logging
6
7
  import os
7
8
  import time
8
- from typing import Optional, Tuple, Union
9
9
  from http import HTTPStatus
10
+ from typing import Optional, Tuple, Union
11
+
12
+ # Local imports
10
13
  from .client_http import AppMeshClient
11
14
 
12
15
  logger = logging.getLogger(__name__)
appmesh/server_tcp.py CHANGED
@@ -1,9 +1,12 @@
1
1
  # server_tcp.py
2
2
  # pylint: disable=line-too-long,broad-exception-raised,broad-exception-caught,import-outside-toplevel,protected-access
3
3
 
4
- import os
4
+ # Standard library imports
5
5
  import logging
6
+ import os
6
7
  from typing import Optional, Tuple
8
+
9
+ # Local imports
7
10
  from .client_http import AppMeshClient
8
11
  from .client_tcp import AppMeshClientTCP
9
12
  from .server_http import AppMeshServer
appmesh/tcp_messages.py CHANGED
@@ -1,6 +1,9 @@
1
1
  # tcp_messages.py
2
2
 
3
+ # Standard library imports
3
4
  from typing import get_type_hints
5
+
6
+ # Third-party imports
4
7
  import msgpack
5
8
 
6
9
 
appmesh/tcp_transport.py CHANGED
@@ -1,5 +1,6 @@
1
1
  # tcp_transport.py
2
2
 
3
+ # Standard library imports
3
4
  import os
4
5
  import socket
5
6
  import ssl
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: appmesh
3
- Version: 1.6.9
3
+ Version: 1.6.11
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,16 @@
1
+ appmesh/__init__.py,sha256=uJ5LOadwZW2nOXkSuPOy2S3WH9Bx0BUn5wUvPBeFzoc,2217
2
+ appmesh/app.py,sha256=crD4DRFZJuHtZMfSsz7C-EwvjPmGZbFXYXvA_wCdvdI,10734
3
+ appmesh/app_output.py,sha256=N8BihWhuUgPUyqZabZMKhQylk8nTHXKk6kMIdidEkGM,1061
4
+ appmesh/app_run.py,sha256=aYq852a29OThIi32Xtx5s0sTXZ97T0lHD5WXH8yfPoc,2018
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=YB_AiMOSzN9j8oSrF0V9gD184Ugbsff-ZnezExwmvtk,1928
12
+ appmesh/tcp_transport.py,sha256=FCfTBHb9FLwMUIxZejOuH_NocHQFGaNDge57IUTJvgs,8973
13
+ appmesh-1.6.11.dist-info/METADATA,sha256=gHUSXnQdxvG61jPEUWcJBSJlrmR_PIHZ_qyyaYwTuIc,11764
14
+ appmesh-1.6.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ appmesh-1.6.11.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
+ appmesh-1.6.11.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- appmesh/__init__.py,sha256=TY1y5B5cE57uhraEzCFOZRWuo9SY1R-fYNRan8hCZOM,1670
2
- appmesh/app.py,sha256=crD4DRFZJuHtZMfSsz7C-EwvjPmGZbFXYXvA_wCdvdI,10734
3
- appmesh/app_output.py,sha256=vfn322AyixblI8DbXds08h6L_ybObiaRSifsA1-Xcoo,1035
4
- appmesh/app_run.py,sha256=aYq852a29OThIi32Xtx5s0sTXZ97T0lHD5WXH8yfPoc,2018
5
- appmesh/appmesh_client.py,sha256=ywB2222PtJUffdfdxZcBfdhZs1KYyc7JvzMxwuK2qyI,378
6
- appmesh/client_http.py,sha256=OiYM4CXn21S4e_jx71X5_31krLes6UuHHueEYk6UIu4,58690
7
- appmesh/client_http_oauth.py,sha256=1d51o0JX_xtB8d2bEuM7_XJHcwMnhcjkbIq7GE1Zxm8,6120
8
- appmesh/client_tcp.py,sha256=aq6UUzytZA4ibE9WQMMWdo1uW8sHETEhJjsbM6IYSno,11457
9
- appmesh/server_http.py,sha256=rBIYO9rbR-r3x1Jcry440Sp--IM-OWKRaOhNpGdkxh8,4299
10
- appmesh/server_tcp.py,sha256=-CU5tw97WJmDcUNsNPWqpdZ0wxRzRD6kUP3XyNZUTHc,1444
11
- appmesh/tcp_messages.py,sha256=H9S_iCy0IuufY2v50_SUgRvcyQmJsySG65tBe_xb3Ko,1878
12
- appmesh/tcp_transport.py,sha256=0hRSp5fpL9wKB05JIyIRIuyBC8w1IdokryhMDHqtN4M,8946
13
- appmesh-1.6.9.dist-info/METADATA,sha256=aT2BPT5BM_5FkkFKhR-h_NBWMQMeVBP3-Wo2QwA-j6Y,11763
14
- appmesh-1.6.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- appmesh-1.6.9.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
- appmesh-1.6.9.dist-info/RECORD,,