sycommon-python-lib 0.2.1b8__tar.gz → 0.2.1b10__tar.gz

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.
Files changed (257) hide show
  1. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/PKG-INFO +1 -1
  2. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/pyproject.toml +1 -1
  3. sycommon_python_lib-0.2.1b10/src/sycommon/auth/__init__.py +46 -0
  4. sycommon_python_lib-0.2.1b10/src/sycommon/auth/wecom_ldap_service.py +490 -0
  5. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/token_usage_db_service.py +5 -5
  6. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/token_usage_mysql_service.py +123 -157
  7. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
  8. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon_python_lib.egg-info/SOURCES.txt +1 -0
  9. sycommon_python_lib-0.2.1b8/src/sycommon/auth/__init__.py +0 -36
  10. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/README.md +0 -0
  11. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/setup.cfg +0 -0
  12. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/__init__.py +0 -0
  13. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/cli.py +0 -0
  14. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/core/__init__.py +0 -0
  15. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/core/console.py +0 -0
  16. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/core/models.py +0 -0
  17. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/core/project.py +0 -0
  18. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/core/utils.py +0 -0
  19. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/__init__.py +0 -0
  20. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/__pycache__/__init__.cpython-311.pyc +0 -0
  21. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/README.md.tpl +0 -0
  22. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/__init__.py +0 -0
  23. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/agent/__init__.py.tpl +0 -0
  24. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/agent/main_agent.py.tpl +0 -0
  25. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/agent/nodes/__init__.py.tpl +0 -0
  26. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/agent/nodes/example_node.py.tpl +0 -0
  27. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/agent/states/__init__.py.tpl +0 -0
  28. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/agent/states/agent_state.py.tpl +0 -0
  29. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/api/__init__.py.tpl +0 -0
  30. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/api/query.py.tpl +0 -0
  31. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/api/sse/__init__.py.tpl +0 -0
  32. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/api/sse/agent.py.tpl +0 -0
  33. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/app.py.tpl +0 -0
  34. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/client/__init__.py.tpl +0 -0
  35. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/db/__init__.py.tpl +0 -0
  36. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/db/model/__init__.py.tpl +0 -0
  37. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/db/model/entity.py.tpl +0 -0
  38. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/db/service.py.tpl +0 -0
  39. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/model/__init__.py.tpl +0 -0
  40. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/model/parse.py.tpl +0 -0
  41. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/tools/__init__.py.tpl +0 -0
  42. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/agent/tools/mq.py.tpl +0 -0
  43. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/.env.tpl +0 -0
  44. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/.gitignore.tpl +0 -0
  45. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/Dockerfile.tpl +0 -0
  46. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/README.md.tpl +0 -0
  47. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/__init__.py +0 -0
  48. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/app.py.tpl +0 -0
  49. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/app.yaml.tpl +0 -0
  50. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/client/FileServiceClient.py.tpl +0 -0
  51. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/client/__init__.py.tpl +0 -0
  52. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/model/__init__.py.tpl +0 -0
  53. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/model/file_info.py.tpl +0 -0
  54. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/base/requirements.txt.tpl +0 -0
  55. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/README.md.tpl +0 -0
  56. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/__init__.py +0 -0
  57. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/api/__init__.py.tpl +0 -0
  58. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/api/echo.py.tpl +0 -0
  59. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/api/sse/__init__.py.tpl +0 -0
  60. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/api/sse/echo.py.tpl +0 -0
  61. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/app.py.tpl +0 -0
  62. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/client/__init__.py.tpl +0 -0
  63. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/model/__init__.py.tpl +0 -0
  64. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/tools/__init__.py.tpl +0 -0
  65. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/command/templates/web/tools/mq.py.tpl +0 -0
  66. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/__init__.py +0 -0
  67. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/__main__.py +0 -0
  68. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/agents/__init__.py +0 -0
  69. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/agents/factory.py +0 -0
  70. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/agents/prompts.py +0 -0
  71. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/__init__.py +0 -0
  72. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/browser.py +0 -0
  73. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/__init__.py +0 -0
  74. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/console.py +0 -0
  75. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/dom.py +0 -0
  76. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/network.py +0 -0
  77. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/page_errors.py +0 -0
  78. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/performance.py +0 -0
  79. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/capabilities/screenshot.py +0 -0
  80. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/client.py +0 -0
  81. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/protocol.py +0 -0
  82. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cdp/repl.py +0 -0
  83. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/cli.py +0 -0
  84. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/__init__.py +0 -0
  85. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/cdp_cmd.py +0 -0
  86. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/chat_cmd.py +0 -0
  87. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/create_cmd.py +0 -0
  88. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/evaluate_cmd.py +0 -0
  89. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/init_cmd.py +0 -0
  90. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/memory_cmd.py +0 -0
  91. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/resume_cmd.py +0 -0
  92. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/rollback_cmd.py +0 -0
  93. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/commands/run_cmd.py +0 -0
  94. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/__init__.py +0 -0
  95. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/backend.py +0 -0
  96. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/config.py +0 -0
  97. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/display.py +0 -0
  98. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/git_integration.py +0 -0
  99. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/llm.py +0 -0
  100. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/core/state.py +0 -0
  101. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/evaluate/__init__.py +0 -0
  102. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/evaluate/api_evaluator.py +0 -0
  103. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/memory/__init__.py +0 -0
  104. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/memory/compressor.py +0 -0
  105. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/memory/full.py +0 -0
  106. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/memory/hot.py +0 -0
  107. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/memory/manager.py +0 -0
  108. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/memory/warm.py +0 -0
  109. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/mode/__init__.py +0 -0
  110. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/mode/create.py +0 -0
  111. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/mode/optimize.py +0 -0
  112. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/models/__init__.py +0 -0
  113. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/models/config_models.py +0 -0
  114. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/__init__.py +0 -0
  115. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/convergence.py +0 -0
  116. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/diagnosis.py +0 -0
  117. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/engine.py +0 -0
  118. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/environment.py +0 -0
  119. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/experience.py +0 -0
  120. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/harness_prompts.py +0 -0
  121. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/history.py +0 -0
  122. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/pre_validation.py +0 -0
  123. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/reward.py +0 -0
  124. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/strategy_bandit.py +0 -0
  125. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/strategy_generator.py +0 -0
  126. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/rl/strategy_prompts.py +0 -0
  127. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycli/skills/__init__.py +0 -0
  128. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/__init__.py +0 -0
  129. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/__init__.py +0 -0
  130. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/agent_manager.py +0 -0
  131. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/chat_events.py +0 -0
  132. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/deep_agent.py +0 -0
  133. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/multi_agent_team.py +0 -0
  134. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/sandbox/__init__.py +0 -0
  135. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/sandbox/file_ops.py +0 -0
  136. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/sandbox/http_sandbox_backend.py +0 -0
  137. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/sandbox/sandbox_pool.py +0 -0
  138. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/sandbox/sandbox_recovery.py +0 -0
  139. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/agent/sandbox/session.py +0 -0
  140. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/auth/ldap_service.py +0 -0
  141. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/Config.py +0 -0
  142. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/DatabaseConfig.py +0 -0
  143. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/ElasticsearchConfig.py +0 -0
  144. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/EmbeddingConfig.py +0 -0
  145. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/LLMConfig.py +0 -0
  146. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/LangfuseConfig.py +0 -0
  147. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/MQConfig.py +0 -0
  148. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/RedisConfig.py +0 -0
  149. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/RerankerConfig.py +0 -0
  150. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/SentryConfig.py +0 -0
  151. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/XxlJobConfig.py +0 -0
  152. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/config/__init__.py +0 -0
  153. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/async_base_db_service.py +0 -0
  154. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/async_database_service.py +0 -0
  155. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/base_db_service.py +0 -0
  156. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/database_service.py +0 -0
  157. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/elasticsearch_service.py +0 -0
  158. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/database/redis_service.py +0 -0
  159. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/health/__init__.py +0 -0
  160. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/health/health_check.py +0 -0
  161. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/health/metrics.py +0 -0
  162. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/health/ping.py +0 -0
  163. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/heartbeat_process/__init__.py +0 -0
  164. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/heartbeat_process/heartbeat_config.py +0 -0
  165. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/heartbeat_process/heartbeat_process_manager.py +0 -0
  166. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/heartbeat_process/heartbeat_process_worker.py +0 -0
  167. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/__init__.py +0 -0
  168. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/embedding.py +0 -0
  169. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/get_llm.py +0 -0
  170. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/llm_logger.py +0 -0
  171. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/llm_tokens.py +0 -0
  172. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/llm_with_token_tracking.py +0 -0
  173. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/native_with_fallback_runnable.py +0 -0
  174. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/output_fixing_runnable.py +0 -0
  175. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/struct_token.py +0 -0
  176. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/sy_langfuse.py +0 -0
  177. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/token_usage_es_service.py +0 -0
  178. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/llm/usage_token.py +0 -0
  179. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/__init__.py +0 -0
  180. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/async_sql_logger.py +0 -0
  181. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/kafka_log.py +0 -0
  182. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/logger_levels.py +0 -0
  183. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/logger_wrapper.py +0 -0
  184. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/process_logger.py +0 -0
  185. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/logging/sql_logger.py +0 -0
  186. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/__init__.py +0 -0
  187. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/background_execution.py +0 -0
  188. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/context.py +0 -0
  189. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/cors.py +0 -0
  190. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/docs.py +0 -0
  191. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/exception.py +0 -0
  192. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/middleware.py +0 -0
  193. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/monitor_memory.py +0 -0
  194. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/mq.py +0 -0
  195. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/sandbox.py +0 -0
  196. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/timeout.py +0 -0
  197. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/token_tracking.py +0 -0
  198. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/middleware/traceid.py +0 -0
  199. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/__init__.py +0 -0
  200. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/base_http.py +0 -0
  201. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/log.py +0 -0
  202. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/mqlistener_config.py +0 -0
  203. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/mqmsg_model.py +0 -0
  204. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/mqsend_config.py +0 -0
  205. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/sandbox.py +0 -0
  206. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/sso_user.py +0 -0
  207. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/token_usage.py +0 -0
  208. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/token_usage_mysql.py +0 -0
  209. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/models/xxljob_handler_config.py +0 -0
  210. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/notice/__init__.py +0 -0
  211. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/notice/uvicorn_monitor.py +0 -0
  212. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/process_pool_consumer.py +0 -0
  213. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_client.py +0 -0
  214. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_pool.py +0 -0
  215. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_service.py +0 -0
  216. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_service_client_manager.py +0 -0
  217. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_service_connection_monitor.py +0 -0
  218. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_service_consumer_manager.py +0 -0
  219. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_service_core.py +0 -0
  220. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/rabbitmq/rabbitmq_service_producer_manager.py +0 -0
  221. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/sentry/__init__.py +0 -0
  222. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/sentry/sy_sentry.py +0 -0
  223. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/services.py +0 -0
  224. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/sse/__init__.py +0 -0
  225. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/sse/event.py +0 -0
  226. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/sse/sse.py +0 -0
  227. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/__init__.py +0 -0
  228. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/example.py +0 -0
  229. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/example2.py +0 -0
  230. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/feign.py +0 -0
  231. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/feign_client.py +0 -0
  232. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/nacos_client_base.py +0 -0
  233. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/nacos_config_manager.py +0 -0
  234. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/nacos_heartbeat_manager.py +0 -0
  235. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/nacos_service.py +0 -0
  236. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/nacos_service_discovery.py +0 -0
  237. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/nacos_service_registration.py +0 -0
  238. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/synacos/param.py +0 -0
  239. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tests/deep_agent_server.py +0 -0
  240. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tests/test_deep_agent.py +0 -0
  241. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tests/test_email.py +0 -0
  242. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tests/test_mq.py +0 -0
  243. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/__init__.py +0 -0
  244. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/async_utils.py +0 -0
  245. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/docs.py +0 -0
  246. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/env.py +0 -0
  247. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/merge_headers.py +0 -0
  248. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/snowflake.py +0 -0
  249. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/syemail.py +0 -0
  250. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/tools/timing.py +0 -0
  251. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/xxljob/__init__.py +0 -0
  252. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon/xxljob/xxljob_service.py +0 -0
  253. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  254. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon_python_lib.egg-info/entry_points.txt +0 -0
  255. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
  256. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/src/sycommon_python_lib.egg-info/top_level.txt +0 -0
  257. {sycommon_python_lib-0.2.1b8 → sycommon_python_lib-0.2.1b10}/tests/test_sycli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.2.1b8
3
+ Version: 0.2.1b10
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.2.1b8"
3
+ version = "0.2.1b10"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -0,0 +1,46 @@
1
+ """
2
+ 认证模块
3
+
4
+ 提供 LDAP 域账号登录认证、企微-LDAP 用户关联功能。
5
+
6
+ LDAP 认证示例::
7
+
8
+ from sycommon.auth import LDAPAuthService, LDAPConfig
9
+
10
+ config = LDAPConfig.from_config()
11
+ auth_service = LDAPAuthService(config)
12
+ result = await auth_service.authenticate("username", "password")
13
+
14
+ 企微-LDAP 关联示例::
15
+
16
+ from sycommon.auth import WeComLDAPService
17
+
18
+ service = WeComLDAPService()
19
+ user = await service.get_user_info("0633")
20
+ if user.matched and user.ldap_user:
21
+ print(user.ldap_user.email)
22
+ """
23
+
24
+ from sycommon.auth.ldap_service import (
25
+ LDAPConfig,
26
+ LDAPAuthService,
27
+ LDAPUser,
28
+ LDAPAuthResult,
29
+ )
30
+ from sycommon.auth.wecom_ldap_service import (
31
+ WeComConfig,
32
+ WeComLDAPService,
33
+ WeComLDAPUser,
34
+ LDAPFullUser,
35
+ )
36
+
37
+ __all__ = [
38
+ "LDAPConfig",
39
+ "LDAPAuthService",
40
+ "LDAPUser",
41
+ "LDAPAuthResult",
42
+ "WeComConfig",
43
+ "WeComLDAPService",
44
+ "WeComLDAPUser",
45
+ "LDAPFullUser",
46
+ ]
@@ -0,0 +1,490 @@
1
+ """
2
+ 企微-LDAP 用户关联服务
3
+
4
+ 通过企微 userid 关联 LDAP 域账号,获取邮箱、部门、职位等完整信息。
5
+
6
+ 关联策略:中文名优先 + 英文名兜底,匹配率约 95.8%。
7
+
8
+ 使用示例::
9
+
10
+ from sycommon.auth import WeComLDAPService
11
+
12
+ service = WeComLDAPService()
13
+ user = await service.get_user_info("0633")
14
+ if user.matched and user.ldap_user:
15
+ print(user.ldap_user.email)
16
+ """
17
+
18
+ import asyncio
19
+ import logging
20
+ import time
21
+ from collections import defaultdict
22
+ from typing import Dict, List, Optional
23
+
24
+ import aiohttp
25
+ from pydantic import BaseModel
26
+
27
+ from sycommon.config.Config import SingletonMeta
28
+ from sycommon.logging.kafka_log import SYLogger
29
+
30
+
31
+ # ─── 模型定义 ───
32
+
33
+
34
+ class WeComConfig(BaseModel):
35
+ """企微通讯录同步配置"""
36
+
37
+ corpid: str
38
+ corpsecret: str
39
+
40
+ @classmethod
41
+ def from_config(cls) -> "WeComConfig":
42
+ """从 Config 加载企微配置
43
+
44
+ 配置路径: config['llm']['WeCom']
45
+ """
46
+ from sycommon.config.Config import Config
47
+
48
+ wecom_config = Config().config.get("llm", {}).get("WeCom", {})
49
+ if not wecom_config:
50
+ raise ValueError("企微配置不存在,请在 llm.WeCom 下配置 corpid 和 corpsecret")
51
+
52
+ corpid = wecom_config.get("corpid", "")
53
+ corpsecret = wecom_config.get("corpsecret", "")
54
+ if not corpid or not corpsecret:
55
+ raise ValueError("企微配置不完整,需要 corpid 和 corpsecret")
56
+
57
+ return cls(corpid=corpid, corpsecret=corpsecret)
58
+
59
+
60
+ class LDAPFullUser(BaseModel):
61
+ """LDAP 域账号完整用户信息"""
62
+
63
+ username: str # sAMAccountName 域账号
64
+ display_name: Optional[str] = None # 中文名
65
+ email: Optional[str] = None # 邮箱
66
+ department: Optional[str] = None # 部门
67
+ title: Optional[str] = None # 职位
68
+ phone: Optional[str] = None # 电话
69
+ dn: Optional[str] = None # DN 路径
70
+ ou_chain: List[str] = [] # OU 层级路径
71
+
72
+
73
+ class WeComLDAPUser(BaseModel):
74
+ """企微-LDAP 关联用户(最终返回结果)"""
75
+
76
+ wecom_userid: str # 企微 userid
77
+ wecom_name: str # 企微中文名
78
+ wecom_english_name: Optional[str] = None # 企微英文名
79
+ wecom_departments: List[str] = [] # 企微部门列表
80
+ wecom_position: Optional[str] = None # 企微职位
81
+ matched: bool = False # 是否匹配到 LDAP
82
+ match_method: Optional[str] = None # 匹配方式: chinese_name / english_name
83
+ ldap_user: Optional[LDAPFullUser] = None # LDAP 完整信息
84
+
85
+
86
+ # ─── 内部缓存结构 ───
87
+
88
+
89
+ class _LDAPIndex:
90
+ """LDAP 用户索引(按 cn 和 sAMAccountName 前缀建索引)"""
91
+
92
+ def __init__(self):
93
+ # cn(中文名) -> LDAPFullUser
94
+ self.by_cn: Dict[str, LDAPFullUser] = {}
95
+ # sAMAccountName 前缀(小写) -> [cn]
96
+ self.by_sam_prefix: Dict[str, List[str]] = defaultdict(list)
97
+
98
+ def build(self, users: List[dict]):
99
+ """从 LDAP 查询结果构建索引"""
100
+ self.by_cn.clear()
101
+ self.by_sam_prefix.clear()
102
+
103
+ for u in users:
104
+ cn = u.get("cn", "").strip()
105
+ sam = u.get("sAMAccountName", "").strip()
106
+ if not cn or not sam:
107
+ continue
108
+
109
+ dn = u.get("distinguishedName", "")
110
+ dn_parts = dn.split(",")
111
+ ou_chain = [
112
+ p.split("=", 1)[1] for p in dn_parts if p.startswith("OU=")
113
+ ]
114
+
115
+ ldap_user = LDAPFullUser(
116
+ username=sam,
117
+ display_name=cn,
118
+ email=u.get("mail", "") or None,
119
+ department=u.get("department", "") or None,
120
+ title=u.get("title", "") or None,
121
+ phone=u.get("telephoneNumber", "") or None,
122
+ dn=dn or None,
123
+ ou_chain=ou_chain,
124
+ )
125
+ self.by_cn[cn] = ldap_user
126
+
127
+ # sAMAccountName 如 "sussie.xia" -> 前缀 "sussie"
128
+ prefix = sam.split(".")[0].lower()
129
+ self.by_sam_prefix[prefix].append(cn)
130
+
131
+ def lookup(self, chinese_name: str, english_name: str = "") -> tuple:
132
+ """查找匹配的 LDAP 用户
133
+
134
+ Args:
135
+ chinese_name: 中文名
136
+ english_name: 英文名(来自企微 extattr)
137
+
138
+ Returns:
139
+ (LDAPFullUser | None, match_method | None)
140
+ """
141
+ # 第一优先级:中文名直接匹配
142
+ if chinese_name in self.by_cn:
143
+ return self.by_cn[chinese_name], "chinese_name"
144
+
145
+ # 兜底:英文名前缀匹配
146
+ if english_name:
147
+ prefix = english_name.lower().split()[0]
148
+ candidates = self.by_sam_prefix.get(prefix, [])
149
+ if len(candidates) == 1:
150
+ # 唯一匹配,直接返回
151
+ return self.by_cn[candidates[0]], "english_name"
152
+ elif len(candidates) > 1:
153
+ # 重名,无法确定,不匹配
154
+ pass
155
+
156
+ return None, None
157
+
158
+
159
+ # ─── 服务类 ───
160
+
161
+
162
+ class WeComLDAPService(metaclass=SingletonMeta):
163
+ """企微-LDAP 用户关联服务
164
+
165
+ 通过企微 userid 查询关联的 LDAP 域账号完整信息。
166
+ 内置 access_token 缓存和 LDAP 用户索引缓存。
167
+ """
168
+
169
+ def __init__(self):
170
+ self._wecom_config: Optional[WeComConfig] = None
171
+ self._ldap_config = None # LDAPConfig
172
+ self._access_token: Optional[str] = None
173
+ self._token_expires_at: float = 0
174
+ self._ldap_index: Optional[_LDAPIndex] = None
175
+ self._ldap_index_expires_at: float = 0
176
+ self._ldap_index_ttl: int = 3600 # LDAP 索引缓存 1 小时
177
+ # 企微部门 ID -> 名称 缓存
178
+ self._dept_map: Dict[int, str] = {}
179
+
180
+ def _ensure_configs(self):
181
+ """延迟加载配置"""
182
+ if self._wecom_config is None:
183
+ self._wecom_config = WeComConfig.from_config()
184
+ if self._ldap_config is None:
185
+ from sycommon.auth.ldap_service import LDAPConfig
186
+
187
+ self._ldap_config = LDAPConfig.from_config()
188
+
189
+ # ─── 企微 API ───
190
+
191
+ async def _get_access_token(self) -> str:
192
+ """获取企微 access_token(带缓存)"""
193
+ if self._access_token and time.time() < self._token_expires_at:
194
+ return self._access_token
195
+
196
+ self._ensure_configs()
197
+ url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
198
+ params = {
199
+ "corpid": self._wecom_config.corpid,
200
+ "corpsecret": self._wecom_config.corpsecret,
201
+ }
202
+
203
+ async with aiohttp.ClientSession() as session:
204
+ async with session.get(url, params=params) as resp:
205
+ data = await resp.json()
206
+
207
+ if data.get("errcode") != 0:
208
+ raise RuntimeError(f"获取企微 access_token 失败: {data}")
209
+
210
+ self._access_token = data["access_token"]
211
+ # 提前 300 秒过期,避免边界情况
212
+ self._token_expires_at = time.time() + data.get("expires_in", 7200) - 300
213
+ logging.info("[WeComLDAP] access_token 已刷新")
214
+ return self._access_token
215
+
216
+ async def _wecom_get(self, path: str, params: dict = None) -> dict:
217
+ """封装企微 GET 请求"""
218
+ token = await self._get_access_token()
219
+ url = f"https://qyapi.weixin.qq.com{path}"
220
+ if params is None:
221
+ params = {}
222
+ params["access_token"] = token
223
+
224
+ async with aiohttp.ClientSession() as session:
225
+ async with session.get(url, params=params) as resp:
226
+ return await resp.json()
227
+
228
+ async def _get_wecom_user(self, userid: str) -> Optional[dict]:
229
+ """获取单个企微用户详情"""
230
+ data = await self._wecom_get(
231
+ "/cgi-bin/user/get", {"userid": userid}
232
+ )
233
+ if data.get("errcode") != 0:
234
+ SYLogger.warning(f"[WeComLDAP] 获取企微用户 {userid} 失败: {data}")
235
+ return None
236
+ return data
237
+
238
+ async def _get_all_wecom_users(self) -> List[dict]:
239
+ """获取全量企微用户"""
240
+ data = await self._wecom_get(
241
+ "/cgi-bin/user/list",
242
+ {"department_id": 1, "fetch_child": 1},
243
+ )
244
+ if data.get("errcode") != 0:
245
+ SYLogger.error(f"[WeComLDAP] 获取企微用户列表失败: {data}")
246
+ return []
247
+ return data.get("userlist", [])
248
+
249
+ async def _get_dept_map(self) -> Dict[int, str]:
250
+ """获取部门 ID -> 名称映射"""
251
+ if self._dept_map:
252
+ return self._dept_map
253
+
254
+ data = await self._wecom_get("/cgi-bin/department/list")
255
+ if data.get("errcode") != 0:
256
+ return {}
257
+
258
+ self._dept_map = {d["id"]: d["name"] for d in data.get("department", [])}
259
+ return self._dept_map
260
+
261
+ # ─── LDAP 查询 ───
262
+
263
+ def _load_ldap_index_sync(self) -> _LDAPIndex:
264
+ """同步加载 LDAP 用户索引"""
265
+ import ldap3
266
+
267
+ self._ensure_configs()
268
+ config = self._ldap_config
269
+
270
+ bind_user = f"{config.username}@{config.default_dc}"
271
+ raw_users = []
272
+
273
+ for url in config.urls:
274
+ try:
275
+ server = ldap3.Server(
276
+ url.rstrip("/"),
277
+ get_info=ldap3.ALL,
278
+ connect_timeout=5,
279
+ )
280
+ conn = ldap3.Connection(
281
+ server,
282
+ user=bind_user,
283
+ password=config.password,
284
+ auto_bind=True,
285
+ receive_timeout=30,
286
+ )
287
+
288
+ # 搜索盛业(大陆)和盛业(香港)两个 OU
289
+ for ou_base in [
290
+ f"OU=盛业(大陆),{config.base}",
291
+ f"OU=盛业(香港),{config.base}",
292
+ ]:
293
+ conn.search(
294
+ search_base=ou_base,
295
+ search_filter="(objectClass=user)",
296
+ search_scope=ldap3.SUBTREE,
297
+ attributes=[
298
+ "cn",
299
+ "sAMAccountName",
300
+ "mail",
301
+ "department",
302
+ "title",
303
+ "telephoneNumber",
304
+ "distinguishedName",
305
+ ],
306
+ size_limit=0,
307
+ )
308
+
309
+ for entry in conn.entries:
310
+ cn = str(entry.cn).strip() if entry.cn else ""
311
+ sam = (
312
+ str(entry.sAMAccountName).strip()
313
+ if entry.sAMAccountName
314
+ else ""
315
+ )
316
+ if not cn or not sam or sam.startswith("$"):
317
+ continue
318
+
319
+ raw_users.append(
320
+ {
321
+ "cn": cn,
322
+ "sAMAccountName": sam,
323
+ "mail": str(entry.mail).strip()
324
+ if entry.mail
325
+ else "",
326
+ "department": str(entry.department).strip()
327
+ if entry.department
328
+ else "",
329
+ "title": str(entry.title).strip()
330
+ if entry.title
331
+ else "",
332
+ "telephoneNumber": str(
333
+ entry.telephoneNumber
334
+ ).strip()
335
+ if entry.telephoneNumber
336
+ else "",
337
+ "distinguishedName": str(
338
+ entry.distinguishedName
339
+ ).strip()
340
+ if entry.distinguishedName
341
+ else "",
342
+ }
343
+ )
344
+
345
+ conn.unbind()
346
+ break # 第一个可用的 LDAP 服务器成功即停止
347
+
348
+ except Exception as e:
349
+ SYLogger.warning(f"[WeComLDAP] LDAP 连接 {url} 失败: {e}")
350
+ continue
351
+
352
+ index = _LDAPIndex()
353
+ index.build(raw_users)
354
+ logging.info(f"[WeComLDAP] LDAP 索引构建完成,共 {len(raw_users)} 人")
355
+ return index
356
+
357
+ async def _get_ldap_index(self) -> _LDAPIndex:
358
+ """获取 LDAP 索引(带缓存)"""
359
+ if (
360
+ self._ldap_index
361
+ and time.time() < self._ldap_index_expires_at
362
+ ):
363
+ return self._ldap_index
364
+
365
+ loop = asyncio.get_event_loop()
366
+ self._ldap_index = await loop.run_in_executor(
367
+ None, self._load_ldap_index_sync
368
+ )
369
+ self._ldap_index_expires_at = time.time() + self._ldap_index_ttl
370
+ return self._ldap_index
371
+
372
+ # ─── 辅助方法 ───
373
+
374
+ @staticmethod
375
+ def _parse_wecom_english_name(user_data: dict) -> str:
376
+ """从企微用户数据中提取英文名"""
377
+ for attr in user_data.get("extattr", {}).get("attrs", []):
378
+ if attr.get("name") == "英文名":
379
+ return attr.get("value", "")
380
+ return ""
381
+
382
+ async def _build_wecom_ldap_user(
383
+ self, user_data: dict, ldap_index: _LDAPIndex
384
+ ) -> WeComLDAPUser:
385
+ """将企微用户数据与 LDAP 信息合并"""
386
+ dept_map = await self._get_dept_map()
387
+ dept_ids = user_data.get("department", [])
388
+ dept_names = [dept_map.get(did, str(did)) for did in dept_ids]
389
+ english_name = self._parse_wecom_english_name(user_data)
390
+ chinese_name = user_data.get("name", "")
391
+
392
+ ldap_user, match_method = ldap_index.lookup(chinese_name, english_name)
393
+
394
+ return WeComLDAPUser(
395
+ wecom_userid=user_data.get("userid", ""),
396
+ wecom_name=chinese_name,
397
+ wecom_english_name=english_name or None,
398
+ wecom_departments=dept_names,
399
+ wecom_position=user_data.get("position") or None,
400
+ matched=ldap_user is not None,
401
+ match_method=match_method,
402
+ ldap_user=ldap_user,
403
+ )
404
+
405
+ # ─── 公开接口 ───
406
+
407
+ async def get_user_info(self, wecom_userid: str) -> WeComLDAPUser:
408
+ """通过企微 userid 获取关联的 LDAP 完整用户信息
409
+
410
+ Args:
411
+ wecom_userid: 企微用户ID(如 "0633", "SZ0888")
412
+
413
+ Returns:
414
+ WeComLDAPUser: 合并后的用户信息,包含 LDAP 域账号详情
415
+ """
416
+ # 1. 从企微获取用户信息
417
+ user_data = await self._get_wecom_user(wecom_userid)
418
+ if not user_data:
419
+ return WeComLDAPUser(wecom_userid=wecom_userid, wecom_name="")
420
+
421
+ # 2. 获取 LDAP 索引
422
+ ldap_index = await self._get_ldap_index()
423
+
424
+ # 3. 合并返回
425
+ return await self._build_wecom_ldap_user(user_data, ldap_index)
426
+
427
+ async def get_all_users(self) -> List[WeComLDAPUser]:
428
+ """获取全量企微用户并关联 LDAP 信息
429
+
430
+ Returns:
431
+ 所有企微用户的关联结果列表
432
+ """
433
+ # 1. 并行获取企微用户列表和 LDAP 索引
434
+ wecom_users, ldap_index = await asyncio.gather(
435
+ self._get_all_wecom_users(),
436
+ self._get_ldap_index(),
437
+ )
438
+
439
+ # 2. 逐个匹配
440
+ results = []
441
+ for u in wecom_users:
442
+ result = await self._build_wecom_ldap_user(u, ldap_index)
443
+ results.append(result)
444
+
445
+ matched = sum(1 for r in results if r.matched)
446
+ logging.info(
447
+ f"[WeComLDAP] 全量匹配完成: {matched}/{len(results)} 已关联"
448
+ )
449
+ return results
450
+
451
+ async def refresh_cache(self):
452
+ """手动刷新缓存(access_token + LDAP 索引 + 部门映射)"""
453
+ self._access_token = None
454
+ self._token_expires_at = 0
455
+ self._ldap_index = None
456
+ self._ldap_index_expires_at = 0
457
+ self._dept_map = {}
458
+
459
+ await self._get_access_token()
460
+ await self._get_ldap_index()
461
+ await self._get_dept_map()
462
+ logging.info("[WeComLDAP] 缓存已刷新")
463
+
464
+ async def get_user_email(self, wecom_userid: str) -> Optional[str]:
465
+ """快捷方法:通过企微 userid 获取邮箱
466
+
467
+ Args:
468
+ wecom_userid: 企微用户ID
469
+
470
+ Returns:
471
+ 邮箱地址,未匹配返回 None
472
+ """
473
+ user = await self.get_user_info(wecom_userid)
474
+ if user.matched and user.ldap_user:
475
+ return user.ldap_user.email
476
+ return None
477
+
478
+ async def get_user_domain_account(self, wecom_userid: str) -> Optional[str]:
479
+ """快捷方法:通过企微 userid 获取域账号名
480
+
481
+ Args:
482
+ wecom_userid: 企微用户ID
483
+
484
+ Returns:
485
+ 域账号名(sAMAccountName),未匹配返回 None
486
+ """
487
+ user = await self.get_user_info(wecom_userid)
488
+ if user.matched and user.ldap_user:
489
+ return user.ldap_user.username
490
+ return None
@@ -153,13 +153,13 @@ class TokenUsageDBConnector(metaclass=SingletonMeta):
153
153
  safe_url = f'mysql+aiomysql://{self.db_user}:***@{self.db_host}:{self.db_port}/{self.db_name}'
154
154
  SYLogger.info(f"TokenUsageDBService Database URL: {safe_url}")
155
155
 
156
- # 创建异步引擎
156
+ # 创建异步引擎(Token 记录连接池较小,增加连接超时防止慢 MySQL 拖垮主服务)
157
157
  self.engine = create_async_engine(
158
158
  self.db_url,
159
- connect_args=params,
160
- pool_size=5, # Token 记录连接池较小
161
- max_overflow=10,
162
- pool_timeout=30,
159
+ connect_args={**params, "connect_timeout": 3},
160
+ pool_size=2,
161
+ max_overflow=3,
162
+ pool_timeout=5,
163
163
  pool_recycle=3600,
164
164
  pool_pre_ping=True,
165
165
  echo=False,