py_wisharetec_toolkit 3.0.2__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.
- py_wisharetec_toolkit/__init__.py +11 -0
- py_wisharetec_toolkit/py.typed +0 -0
- py_wisharetec_toolkit/shanshu/__init__.py +18 -0
- py_wisharetec_toolkit/shanshu/auth.py +143 -0
- py_wisharetec_toolkit/shanshu/client.py +2218 -0
- py_wisharetec_toolkit/shanshu/models.py +1276 -0
- py_wisharetec_toolkit-3.0.2.dist-info/METADATA +313 -0
- py_wisharetec_toolkit-3.0.2.dist-info/RECORD +10 -0
- py_wisharetec_toolkit-3.0.2.dist-info/WHEEL +5 -0
- py_wisharetec_toolkit-3.0.2.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: UTF-8 -*-
|
|
3
|
+
|
|
4
|
+
"""shanshu 子包。
|
|
5
|
+
|
|
6
|
+
可供他人通过 `from py_wisharetec_toolkit import shanshu` 或
|
|
7
|
+
`from py_wisharetec_toolkit.shanshu import client, models, auth` 导入。
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__version__ = "3.0.2"
|
|
11
|
+
__all__ = ["client", "models", "auth"]
|
|
12
|
+
|
|
13
|
+
from . import client # noqa: E402
|
|
14
|
+
from . import models # noqa: E402
|
|
15
|
+
from . import auth # noqa: E402
|
|
16
|
+
|
|
17
|
+
# 将异步客户端类也导出到顶层,方便直接使用
|
|
18
|
+
from .client import AsyncShanshuClient, AsyncShanshuClientConfig # noqa: E402
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: UTF-8 -*-
|
|
3
|
+
|
|
4
|
+
"""Shanshu 登录认证与 Token 缓存。
|
|
5
|
+
|
|
6
|
+
提供基于 httpx 的 ``/api/user/loginInteractive`` 接口调用,
|
|
7
|
+
并支持 memory / diskcache / redis 三种 Token 缓存后端。
|
|
8
|
+
|
|
9
|
+
缓存 key 格式:py_wisharetec_toolkit:shanshu:authorization_token:{account}
|
|
10
|
+
便于缓存不同用户的登录 token。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import threading
|
|
17
|
+
from typing import Any, Protocol, runtime_checkable
|
|
18
|
+
|
|
19
|
+
LOGIN_PATH = "api/user/loginInteractive"
|
|
20
|
+
CACHE_KEY_PREFIX = "py_wisharetec_toolkit:shanshu:authorization_token"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def cache_key(account: str) -> str:
|
|
24
|
+
"""构造 Token 缓存 key。
|
|
25
|
+
|
|
26
|
+
格式:py_wisharetec_toolkit:shanshu:authorization_token:{account}
|
|
27
|
+
"""
|
|
28
|
+
return f"{CACHE_KEY_PREFIX}:{account}"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@runtime_checkable
|
|
32
|
+
class ShanshuTokenCache(Protocol):
|
|
33
|
+
"""Token 缓存协议,key 为 cache_key(account) 生成的字符串。"""
|
|
34
|
+
|
|
35
|
+
def get(self, key: str) -> str | None: ...
|
|
36
|
+
|
|
37
|
+
def set(self, key: str, token: str, ttl: int | None = None) -> None: ...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ShanshuMemoryTokenCache:
|
|
41
|
+
"""进程内内存缓存(默认后端,无需额外依赖,线程安全)。"""
|
|
42
|
+
|
|
43
|
+
def __init__(self) -> None:
|
|
44
|
+
self._tokens: dict[str, str] = {}
|
|
45
|
+
self._lock = threading.Lock()
|
|
46
|
+
|
|
47
|
+
def get(self, key: str) -> str | None:
|
|
48
|
+
with self._lock:
|
|
49
|
+
return self._tokens.get(key)
|
|
50
|
+
|
|
51
|
+
def set(self, key: str, token: str, ttl: int | None = None) -> None:
|
|
52
|
+
with self._lock:
|
|
53
|
+
self._tokens[key] = token
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ShanshuDiskCacheTokenCache:
|
|
57
|
+
"""基于 diskcache 的持久化缓存。
|
|
58
|
+
|
|
59
|
+
需要额外安装:pip install diskcache
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
cache_dir: str = ".runtime/cache/diskcache",
|
|
65
|
+
table: str = "token",
|
|
66
|
+
expire: int | None = None,
|
|
67
|
+
) -> None:
|
|
68
|
+
try:
|
|
69
|
+
import diskcache as dc
|
|
70
|
+
except ImportError as exc: # pragma: no cover
|
|
71
|
+
raise ImportError(
|
|
72
|
+
"使用 ShanshuDiskCacheTokenCache 需要安装 diskcache: pip install diskcache"
|
|
73
|
+
) from exc
|
|
74
|
+
self._cache = dc.Cache(cache_dir, table=table)
|
|
75
|
+
self._expire = expire
|
|
76
|
+
|
|
77
|
+
def get(self, key: str) -> str | None:
|
|
78
|
+
return self._cache.get(key)
|
|
79
|
+
|
|
80
|
+
def set(self, key: str, token: str, ttl: int | None = None) -> None:
|
|
81
|
+
expire = ttl if ttl is not None else self._expire
|
|
82
|
+
self._cache.set(key, token, expire=expire)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class ShanshuRedisTokenCache:
|
|
86
|
+
"""基于 redis 的缓存。
|
|
87
|
+
|
|
88
|
+
需要额外安装:pip install redis
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
host: str = "localhost",
|
|
94
|
+
port: int = 6379,
|
|
95
|
+
db: int = 0,
|
|
96
|
+
password: str | None = None,
|
|
97
|
+
expire: int | None = None,
|
|
98
|
+
**kwargs: Any,
|
|
99
|
+
) -> None:
|
|
100
|
+
try:
|
|
101
|
+
import redis as redis_lib
|
|
102
|
+
except ImportError as exc: # pragma: no cover
|
|
103
|
+
raise ImportError(
|
|
104
|
+
"使用 ShanshuRedisTokenCache 需要安装 redis: pip install redis"
|
|
105
|
+
) from exc
|
|
106
|
+
self._client = redis_lib.Redis(
|
|
107
|
+
host=host,
|
|
108
|
+
port=port,
|
|
109
|
+
db=db,
|
|
110
|
+
password=password,
|
|
111
|
+
**kwargs,
|
|
112
|
+
)
|
|
113
|
+
self._expire = expire
|
|
114
|
+
|
|
115
|
+
def get(self, key: str) -> str | None:
|
|
116
|
+
val = self._client.get(key)
|
|
117
|
+
if val is None:
|
|
118
|
+
return None
|
|
119
|
+
return val.decode() if isinstance(val, bytes) else val
|
|
120
|
+
|
|
121
|
+
def set(self, key: str, token: str, ttl: int | None = None) -> None:
|
|
122
|
+
expire = ttl if ttl is not None else self._expire
|
|
123
|
+
if expire is not None:
|
|
124
|
+
self._client.set(key, token, ex=expire)
|
|
125
|
+
else:
|
|
126
|
+
self._client.set(key, token)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def md5(text: str) -> str:
|
|
130
|
+
"""计算字符串的 MD5 哈希(小写十六进制)。"""
|
|
131
|
+
return hashlib.md5(text.encode("utf-8")).hexdigest()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
__all__ = [
|
|
135
|
+
"LOGIN_PATH",
|
|
136
|
+
"CACHE_KEY_PREFIX",
|
|
137
|
+
"cache_key",
|
|
138
|
+
"ShanshuTokenCache",
|
|
139
|
+
"ShanshuMemoryTokenCache",
|
|
140
|
+
"ShanshuDiskCacheTokenCache",
|
|
141
|
+
"ShanshuRedisTokenCache",
|
|
142
|
+
"md5",
|
|
143
|
+
]
|