341 lines
13 KiB
Python
341 lines
13 KiB
Python
"""GVS-DSDK — GVS Distributed SDK
|
||
|
||
GVS 分布式服务间通信 SDK,作为子服务器(如 ATestCServer)和主服务器(gvsds)
|
||
之间的统一通信桥梁。
|
||
|
||
设计原则:
|
||
1. 薄封装:直接包装 gvsds.apps.msync 原生层
|
||
2. 纯转发:方法签名 1:1 对应原生层
|
||
3. PascalCase:全部公开 API 使用 PascalCase
|
||
4. 协议兼容:完全兼容 gvsds/apps/msync 现有协议
|
||
5. 惰性加载:仅在访问属性时才 import 原生层(避免 Django 未初始化时报错)
|
||
|
||
包结构:
|
||
gvsdsdk/
|
||
├── auth/ # ELT 用户认证模块
|
||
│ ├── elt_auth.py # ELT 认证后端
|
||
│ ├── cookie.py # Cookie 管理
|
||
│ ├── crypto.py # 密码哈希 + AES 加密
|
||
│ ├── middleware.py # ELTAuthMiddleware + CurrentRoleMiddleware
|
||
│ ├── permissions.py # RBAC/ABAC 权限
|
||
│ └── managers.py # UserManager + RoleManager
|
||
├── msync/ # MSYNC 服务间通信
|
||
├── commission/ # 分佣引擎
|
||
│ ├── models.py # 分佣数据模型
|
||
│ ├── manager.py # CommissionEngine 编排器
|
||
│ └── strategies/ # 分账策略
|
||
├── payment/ # 支付网关
|
||
│ ├── models.py # 支付数据模型
|
||
│ ├── manager.py # PaymentManager 编排器
|
||
│ └── gateways/ # 支付渠道适配器
|
||
├── order/ # 订单模板与订单
|
||
│ └── models.py # 订单数据模型
|
||
├── models.py # SAAS 核心数据模型
|
||
├── model_base.py # QModel
|
||
├── model_utils.py # UUIDObj
|
||
└── fluent.py # FluentQuery ORM 查询层
|
||
|
||
使用示例:
|
||
from gvsdsdk import ServiceRegistry, OGMManager, TransactionManager
|
||
from gvsdsdk.auth import ELTAuthentication, PermissionVerifier
|
||
from gvsdsdk.commission import CommissionEngine
|
||
from gvsdsdk.payment import PaymentManager
|
||
print(gvsdsdk.__version__) # '1.0.0'
|
||
"""
|
||
|
||
import os as _os
|
||
import sys as _sys
|
||
import platform as _platform
|
||
from typing import Optional, Tuple
|
||
|
||
|
||
# === 版本定义(单一来源) ===
|
||
|
||
#: 主版本号
|
||
VERSION_MAJOR = 1
|
||
#: 次版本号
|
||
VERSION_MINOR = 0
|
||
#: 补丁版本号
|
||
VERSION_PATCH = 0
|
||
#: 预发布标签(如 'a1', 'b2', 'rc1')
|
||
VERSION_PRERELEASE = ''
|
||
|
||
#: 完整版本字符串(PEP 440 兼容)
|
||
__version__ = f'{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_PATCH}{VERSION_PRERELEASE}'
|
||
|
||
|
||
# === 包元数据 ===
|
||
|
||
#: 物理安装路径(pkg.__file__ 所在目录)
|
||
_PKG_DIR = _os.path.dirname(_os.path.abspath(__file__))
|
||
|
||
|
||
def get_version() -> str:
|
||
"""返回 SDK 版本字符串"""
|
||
return __version__
|
||
|
||
|
||
def get_version_info() -> dict:
|
||
"""返回详细版本信息字典
|
||
|
||
Returns:
|
||
包含 version, location, python_version, platform 等字段
|
||
"""
|
||
return {
|
||
'Version': __version__,
|
||
'Major': VERSION_MAJOR,
|
||
'Minor': VERSION_MINOR,
|
||
'Patch': VERSION_PATCH,
|
||
'Prerelease': VERSION_PRERELEASE,
|
||
'Location': _PKG_DIR,
|
||
'Python': _sys.version.split()[0],
|
||
'Platform': _platform.platform(),
|
||
'Machine': _platform.machine(),
|
||
}
|
||
|
||
|
||
def check_min_version(min_version: str) -> Tuple[bool, str]:
|
||
"""检查当前版本是否 >= 给定最低版本
|
||
|
||
Args:
|
||
min_version: 形如 '1.0.0' 的最低版本字符串
|
||
|
||
Returns:
|
||
(is_ok, message) 元组
|
||
"""
|
||
def parse(v: str):
|
||
parts = v.split('.')
|
||
major = int(parts[0]) if len(parts) > 0 else 0
|
||
minor = int(parts[1]) if len(parts) > 1 else 0
|
||
patch_str = parts[2] if len(parts) > 2 else '0'
|
||
digits = ''
|
||
for c in patch_str:
|
||
if c.isdigit():
|
||
digits += c
|
||
else:
|
||
break
|
||
patch = int(digits) if digits else 0
|
||
return (major, minor, patch)
|
||
|
||
current = parse(__version__)
|
||
required = parse(min_version)
|
||
|
||
if current >= required:
|
||
return True, f'OK: SDK {__version__} >= {min_version}'
|
||
return False, f'FAIL: SDK {__version__} < {min_version} (required)'
|
||
|
||
|
||
# === 惰性加载(PEP 562)===
|
||
|
||
def _load_msync():
|
||
from gvsdsdk import msync as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_auth():
|
||
from gvsdsdk import auth as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_commission():
|
||
from gvsdsdk import commission as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_payment():
|
||
from gvsdsdk import payment as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_order():
|
||
from gvsdsdk import order as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_models():
|
||
from gvsdsdk import models as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_fluent():
|
||
from gvsdsdk import fluent as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_model_base():
|
||
from gvsdsdk import model_base as _mod
|
||
return _mod
|
||
|
||
|
||
def _load_model_utils():
|
||
from gvsdsdk import model_utils as _mod
|
||
return _mod
|
||
|
||
|
||
_LAZY_SYMBOLS = {
|
||
# ── MSYNC 服务间通信 ──────────────────────────────────
|
||
'SignPayload': ('msync', 'SignPayload'),
|
||
'VerifySignature': ('msync', 'VerifySignature'),
|
||
'GenerateChallenge': ('msync', 'GenerateChallenge'),
|
||
'BuildAuthPayload': ('msync', 'BuildAuthPayload'),
|
||
'SignAuthPayload': ('msync', 'SignAuthPayload'),
|
||
'VerifyAuthPayload': ('msync', 'VerifyAuthPayload'),
|
||
'ServiceTokenEncoder': ('msync', 'ServiceTokenEncoder'),
|
||
'AuthenticateService': ('msync', 'AuthenticateService'),
|
||
'RefreshServiceToken': ('msync', 'RefreshServiceToken'),
|
||
'ValidateAccessToken': ('msync', 'ValidateAccessToken'),
|
||
'IssueServiceToken': ('msync', 'IssueServiceToken'),
|
||
'ServiceRegistry': ('msync', 'ServiceRegistry'),
|
||
'RegistryError': ('msync', 'RegistryError'),
|
||
'OGMManager': ('msync', 'OGMManager'),
|
||
'OGMError': ('msync', 'OGMError'),
|
||
'TransactionManager': ('msync', 'TransactionManager'),
|
||
'TransactionError': ('msync', 'TransactionError'),
|
||
'StepExecutionError': ('msync', 'StepExecutionError'),
|
||
'LocalTransactionManager': ('msync', 'LocalTransactionManager'),
|
||
'StepHandler': ('msync', 'StepHandler'),
|
||
'local_tx': ('msync', 'local_tx'),
|
||
'ServiceClient': ('msync', 'ServiceClient'),
|
||
'ServiceClientError': ('msync', 'ServiceClientError'),
|
||
|
||
# ── ELT 用户认证 ──────────────────────────────────────
|
||
'ELTAuthentication': ('auth', 'ELTAuthentication'),
|
||
'ELT_COOKIE_NAME': ('auth', 'ELT_COOKIE_NAME'),
|
||
'ELT_COOKIE_DOMAIN': ('auth', 'ELT_COOKIE_DOMAIN'),
|
||
'ELT_COOKIE_MAX_AGE': ('auth', 'ELT_COOKIE_MAX_AGE'),
|
||
'SetELTCookie': ('auth', 'SetELTCookie'),
|
||
'DeleteELTCookie': ('auth', 'DeleteELTCookie'),
|
||
'HashPassword': ('auth', 'HashPassword'),
|
||
'VerifyPassword': ('auth', 'VerifyPassword'),
|
||
'SymmetricEncrypt': ('auth', 'SymmetricEncrypt'),
|
||
'SymmetricDecrypt': ('auth', 'SymmetricDecrypt'),
|
||
'FileSHA1': ('auth', 'FileSHA1'),
|
||
'FileSHA256': ('auth', 'FileSHA256'),
|
||
'BytesSHA1': ('auth', 'BytesSHA1'),
|
||
'BytesSHA256': ('auth', 'BytesSHA256'),
|
||
'ELTAuthMiddleware': ('auth', 'ELTAuthMiddleware'),
|
||
'CurrentRoleMiddleware': ('auth', 'CurrentRoleMiddleware'),
|
||
'IsAdminUser': ('auth', 'IsAdminUser'),
|
||
'IsCompanyMember': ('auth', 'IsCompanyMember'),
|
||
'CompanyScopedMixin': ('auth', 'CompanyScopedMixin'),
|
||
'PermissionVerifier': ('auth', 'PermissionVerifier'),
|
||
'RoleManager': ('auth', 'RoleManager'),
|
||
'ShopManager': ('auth', 'ShopManager'),
|
||
'PositionManager': ('auth', 'PositionManager'),
|
||
|
||
# ── 分佣引擎 ──────────────────────────────────────────
|
||
'CommissionEngine': ('commission', 'CommissionEngine'),
|
||
'CommissionError': ('commission', 'CommissionError'),
|
||
'CommissionEvent': ('commission', 'CommissionEvent'),
|
||
'RateTable': ('commission', 'RateTable'),
|
||
'RateEntry': ('commission', 'RateEntry'),
|
||
'CommissionRule': ('commission', 'CommissionRule'),
|
||
'CommissionRecord': ('commission', 'CommissionRecord'),
|
||
'PreSettlement': ('commission', 'PreSettlement'),
|
||
'CreateStrategy': ('commission', 'CreateStrategy'),
|
||
'PercentageStrategy': ('commission', 'PercentageStrategy'),
|
||
'FixedStrategy': ('commission', 'FixedStrategy'),
|
||
'TieredStrategy': ('commission', 'TieredStrategy'),
|
||
'RemainderStrategy': ('commission', 'RemainderStrategy'),
|
||
'WithdrawalFeeStrategy': ('commission', 'WithdrawalFeeStrategy'),
|
||
|
||
# ── 支付网关 ──────────────────────────────────────────
|
||
'PaymentManager': ('payment', 'PaymentManager'),
|
||
'PaymentError': ('payment', 'PaymentError'),
|
||
'PaymentGatewayConfig': ('payment', 'PaymentGatewayConfig'),
|
||
'PaymentTransaction': ('payment', 'PaymentTransaction'),
|
||
'EncryptField': ('payment', 'EncryptField'),
|
||
'PaymentCredentials': ('payment', 'PaymentCredentials'),
|
||
'PaymentRequest': ('payment', 'PaymentRequest'),
|
||
'PaymentResponse': ('payment', 'PaymentResponse'),
|
||
'RefundRequest': ('payment', 'RefundRequest'),
|
||
'RefundResponse': ('payment', 'RefundResponse'),
|
||
'TransferRequest': ('payment', 'TransferRequest'),
|
||
'TransferResponse': ('payment', 'TransferResponse'),
|
||
'QueryResponse': ('payment', 'QueryResponse'),
|
||
'AbstractPaymentGateway': ('payment', 'AbstractPaymentGateway'),
|
||
'GatewayRegistry': ('payment', 'GatewayRegistry'),
|
||
'payment_registry': ('payment', 'payment_registry'),
|
||
'WechatPaymentGateway': ('payment', 'WechatPaymentGateway'),
|
||
'AlipayPaymentGateway': ('payment', 'AlipayPaymentGateway'),
|
||
'BankPaymentGateway': ('payment', 'BankPaymentGateway'),
|
||
|
||
# ── 订单模板与订单 ────────────────────────────────────
|
||
'OrderTemplate': ('order', 'OrderTemplate'),
|
||
'OrderTemplateItem': ('order', 'OrderTemplateItem'),
|
||
'OrderLevel': ('order', 'OrderLevel'),
|
||
'Order': ('order', 'Order'),
|
||
'OrderItem': ('order', 'OrderItem'),
|
||
|
||
# ── 数据模型 ──────────────────────────────────────────
|
||
'User': ('models', 'User'),
|
||
'Role': ('models', 'Role'),
|
||
'Permission': ('models', 'Permission'),
|
||
'UserRole': ('models', 'UserRole'),
|
||
'UUIDField': ('models', 'UUIDField'),
|
||
'UserManager': ('models', 'UserManager'),
|
||
'EphemeralToken': ('models', 'EphemeralToken'),
|
||
'User2FA': ('models', 'User2FA'),
|
||
'UserPending2FA': ('models', 'UserPending2FA'),
|
||
'UserAvatar': ('models', 'UserAvatar'),
|
||
'UserLoginLog': ('models', 'UserLoginLog'),
|
||
'AccountActivation': ('models', 'AccountActivation'),
|
||
'RolePermission': ('models', 'RolePermission'),
|
||
'UserABAC': ('models', 'UserABAC'),
|
||
'Password': ('models', 'Password'),
|
||
'Shop': ('models', 'Shop'),
|
||
'RoleShop': ('models', 'RoleShop'),
|
||
'Position': ('models', 'Position'),
|
||
'PositionTemplate': ('models', 'PositionTemplate'),
|
||
'PositionTemplatePermission': ('models', 'PositionTemplatePermission'),
|
||
'UserDept': ('models', 'UserDept'),
|
||
'FixedBinaryField': ('models', 'FixedBinaryField'),
|
||
'QModel': ('model_base', 'QModel'),
|
||
'QModelBase': ('model_base', 'QModelBase'),
|
||
|
||
# ── ORM 查询层 ────────────────────────────────────────
|
||
'FluentQuery': ('fluent', 'FluentQuery'),
|
||
'Session': ('fluent', 'Session'),
|
||
'db': ('fluent', 'db'),
|
||
'func': ('fluent', 'func'),
|
||
'FQ': ('fluent', 'FQ'),
|
||
'FieldExpression': ('model_base', 'FieldExpression'),
|
||
|
||
# ── 工具 ──────────────────────────────────────────────
|
||
'UUIDObj': ('model_utils', 'UUIDObj'),
|
||
}
|
||
|
||
_LOADERS = {
|
||
'msync': _load_msync,
|
||
'auth': _load_auth,
|
||
'commission': _load_commission,
|
||
'payment': _load_payment,
|
||
'order': _load_order,
|
||
'models': _load_models,
|
||
'fluent': _load_fluent,
|
||
'model_base': _load_model_base,
|
||
'model_utils': _load_model_utils,
|
||
}
|
||
|
||
|
||
def __getattr__(name):
|
||
"""惰性加载——仅在被访问时才 import 真正的模块"""
|
||
if name in _LAZY_SYMBOLS:
|
||
module_name, attr = _LAZY_SYMBOLS[name]
|
||
mod = _LOADERS[module_name]()
|
||
value = getattr(mod, attr)
|
||
globals()[name] = value
|
||
return value
|
||
raise AttributeError(f"module 'gvsdsdk' has no attribute {name!r}")
|
||
|
||
|
||
__all__ = list(_LAZY_SYMBOLS.keys()) + [
|
||
'get_version',
|
||
'get_version_info',
|
||
'check_min_version',
|
||
'__version__',
|
||
'VERSION_MAJOR',
|
||
'VERSION_MINOR',
|
||
'VERSION_PATCH',
|
||
]
|