Files
GVSDSDK/__init__.py
T
TermiNexus 4d8e6d4225 fix(msync): Saga 增强与已知缺陷全量修复,版本升至 1.1.0
- 自动重试:Execute 内按 CanRetry 内联重试(与手动 RetryStep 共享计数);
  RetryStep 补 select_for_update 行锁
- 步骤数据流:前置步骤 StepResult 合并进后续步骤载荷(不落库,向后兼容)
- 空闲超时:IsTimedOut 改以 UpdateTime 起算,Execute 每步推进刷新计时
- TransactionResult:Execute/Compensate 终态写入步骤汇总快照
- 幂等键:_call_service 携带 Idempotency-Key(事务码:步骤号:重试次数),
  local_tx 侧按 key 内存去重(TTL 300s)
- 修复 RetryCompensate 成功后残留 compensate_error 导致事务误判 FAILED
- 迁移 0001 FK 去除 db_column(列名对齐模型 attname,消除 makemigrations 漂移)
- 新增 gvsdsdk_check_schema 命令:模型与数据库 schema 一致性校验
- 新增 VERSION_MATRIX.md 版本连接状态表;版本 1.0.0 -> 1.1.0
2026-08-10 22:38:48 +08:00

374 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""GVSDS SDK — GVSDS 分布式 SDK
GVSDS 分布式服务间通信 SDK,作为子服务器(如 ATestCServer)和主服务器(gvsds)
之间的统一通信桥梁。实现原生位于 gvsdsdk 内(非封装层),可脱离 gvsds 独立部署。
设计原则:
1. 原生实现:全部逻辑位于 gvsdsdk(含 msync 通信底座),不依赖 gvsds
2. 独立部署:屏蔽 gvsds 包后所有子模块可独立导入运行
3. PascalCase:全部公开 API 使用 PascalCase
4. 惰性加载:仅访问属性时才 import ORM 依赖模块(避免 Django 未初始化时报错)
包结构:
gvsdsdk/
├── auth/ # 用户认证与权限模块
│ ├── crypto.py # 密码哈希 + AES 加密
│ ├── middleware.py # CurrentRoleMiddleware
│ ├── permissions.py # RBAC/ABAC 权限
│ └── managers.py # RoleManager(UserManager 在 models.py)
├── msync/ # MSYNC 服务间通信(完整实现)
│ ├── models.py # 服务节点/令牌/OGM/分布式事务模型
│ ├── registry.py # 服务注册发现
│ ├── ogm.py # OGM 对象全局映射
│ ├── transaction.py # Saga 远程事务编排
│ ├── local_tx.py # 本地事务步骤处理器
│ ├── auth.py # HMAC 签名 + 令牌编解码 + 服务端签发/验证
│ ├── sio.py # Socket.IO 服务端
│ ├── views.py # REST API 视图
│ └── ...
├── commission/ # 分佣引擎
├── payment/ # 支付网关
├── order/ # 订单模板与订单
├── models.py # SAAS 核心数据模型
├── model_base.py # QModel
├── model_utils.py # UUIDObj
├── secrets.py # secrets.ini 配置读取
├── serializer_base.py # PascalCase DRF 序列化器基类
└── fluent.py # FluentQuery ORM 查询层
使用示例:
from gvsdsdk import ServiceRegistry, OGMManager, TransactionManager
from gvsdsdk.auth import PermissionVerifier
from gvsdsdk.commission import CommissionEngine
from gvsdsdk.payment import PaymentManager
print(gvsdsdk.__version__) # '1.1.0'
"""
import os as _os
import sys as _sys
import platform as _platform
from typing import Optional, Tuple
# === 版本定义(单一来源) ===
#: 主版本号
VERSION_MAJOR = 1
#: 次版本号
VERSION_MINOR = 1
#: 补丁版本号
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_stats():
from gvsdsdk import stats 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'),
# ── 用户认证与权限 ────────────────────────────────────
'GetDefaultAvatar': ('auth', 'GetDefaultAvatar'),
'HashPassword': ('auth', 'HashPassword'),
'VerifyPassword': ('auth', 'VerifyPassword'),
'SymmetricEncrypt': ('auth', 'SymmetricEncrypt'),
'SymmetricDecrypt': ('auth', 'SymmetricDecrypt'),
'FileSHA1': ('auth', 'FileSHA1'),
'FileSHA256': ('auth', 'FileSHA256'),
'BytesSHA1': ('auth', 'BytesSHA1'),
'BytesSHA256': ('auth', 'BytesSHA256'),
'CurrentRoleMiddleware': ('auth', 'CurrentRoleMiddleware'),
'IsAdminUser': ('auth', 'IsAdminUser'),
'IsCompanyMember': ('auth', 'IsCompanyMember'),
'CompanyScopedMixin': ('auth', 'CompanyScopedMixin'),
'PermissionVerifier': ('auth', 'PermissionVerifier'),
'RoleManager': ('auth', 'RoleManager'),
'ShopManager': ('auth', 'ShopManager'),
'PositionManager': ('auth', 'PositionManager'),
'AuthManager': ('auth', 'AuthManager'),
'AdminUserManager': ('auth', 'AdminUserManager'),
'TenantManager': ('auth', 'TenantManager'),
'CompanyManager': ('auth', 'CompanyManager'),
'DepartmentManager': ('auth', 'DepartmentManager'),
'MessageManager': ('auth', 'MessageManager'),
'UserService': ('auth', 'UserService'),
# ── 分佣引擎 ──────────────────────────────────────────
'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'),
# ── 统计引擎 ──────────────────────────────────────────
'StatsManager': ('stats', 'StatsManager'),
'StatMetric': ('stats', 'StatMetric'),
'StatDimension': ('stats', 'StatDimension'),
'StatRecord': ('stats', 'StatRecord'),
'StatRanking': ('stats', 'StatRanking'),
'StatConfig': ('stats', 'StatConfig'),
# ── 数据模型 ──────────────────────────────────────────
'User': ('models', 'User'),
'Role': ('models', 'Role'),
'Permission': ('models', 'Permission'),
'UserRole': ('models', 'UserRole'),
'UUIDField': ('models', 'UUIDField'),
'UserManager': ('models', 'UserManager'),
'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'),
'Menu': ('models', 'Menu'),
'WorkOrder': ('models', 'WorkOrder'),
'AuditLog': ('models', 'AuditLog'),
'UserRoleDepartment': ('models', 'UserRoleDepartment'),
'UserRoleWorkgroup': ('models', 'UserRoleWorkgroup'),
'Message': ('models', 'Message'),
'UserIDCard': ('models', 'UserIDCard'),
'PersonalPage': ('models', 'PersonalPage'),
'UserSettings': ('models', 'UserSettings'),
'Tenant': ('models', 'Tenant'),
'Company': ('models', 'Company'),
'Department': ('models', 'Department'),
'CompanyInfo': ('models', 'CompanyInfo'),
'DepartmentSMTM': ('models', 'DepartmentSMTM'),
'Workgroup': ('models', 'Workgroup'),
'SimulatedTrigger': ('models', 'SimulatedTrigger'),
'CashReceiptsPaymentsLedger': ('models', 'CashReceiptsPaymentsLedger'),
'Asset': ('models', 'Asset'),
'Liability': ('models', 'Liability'),
'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,
'stats': _load_stats,
'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',
]