ccproxy-api 0.1.7__py3-none-any.whl → 0.2.0__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.
- ccproxy/api/__init__.py +1 -15
- ccproxy/api/app.py +434 -219
- ccproxy/api/bootstrap.py +30 -0
- ccproxy/api/decorators.py +85 -0
- ccproxy/api/dependencies.py +144 -168
- ccproxy/api/format_validation.py +54 -0
- ccproxy/api/middleware/cors.py +6 -3
- ccproxy/api/middleware/errors.py +388 -524
- ccproxy/api/middleware/hooks.py +563 -0
- ccproxy/api/middleware/normalize_headers.py +59 -0
- ccproxy/api/middleware/request_id.py +35 -16
- ccproxy/api/middleware/streaming_hooks.py +292 -0
- ccproxy/api/routes/__init__.py +5 -14
- ccproxy/api/routes/health.py +39 -672
- ccproxy/api/routes/plugins.py +277 -0
- ccproxy/auth/__init__.py +2 -19
- ccproxy/auth/bearer.py +25 -15
- ccproxy/auth/dependencies.py +123 -157
- ccproxy/auth/exceptions.py +0 -12
- ccproxy/auth/manager.py +35 -49
- ccproxy/auth/managers/__init__.py +10 -0
- ccproxy/auth/managers/base.py +523 -0
- ccproxy/auth/managers/base_enhanced.py +63 -0
- ccproxy/auth/managers/token_snapshot.py +77 -0
- ccproxy/auth/models/base.py +65 -0
- ccproxy/auth/models/credentials.py +40 -0
- ccproxy/auth/oauth/__init__.py +4 -18
- ccproxy/auth/oauth/base.py +533 -0
- ccproxy/auth/oauth/cli_errors.py +37 -0
- ccproxy/auth/oauth/flows.py +430 -0
- ccproxy/auth/oauth/protocol.py +366 -0
- ccproxy/auth/oauth/registry.py +408 -0
- ccproxy/auth/oauth/router.py +396 -0
- ccproxy/auth/oauth/routes.py +186 -113
- ccproxy/auth/oauth/session.py +151 -0
- ccproxy/auth/oauth/templates.py +342 -0
- ccproxy/auth/storage/__init__.py +2 -5
- ccproxy/auth/storage/base.py +279 -5
- ccproxy/auth/storage/generic.py +134 -0
- ccproxy/cli/__init__.py +1 -2
- ccproxy/cli/_settings_help.py +351 -0
- ccproxy/cli/commands/auth.py +1519 -793
- ccproxy/cli/commands/config/commands.py +209 -276
- ccproxy/cli/commands/plugins.py +669 -0
- ccproxy/cli/commands/serve.py +75 -810
- ccproxy/cli/commands/status.py +254 -0
- ccproxy/cli/decorators.py +83 -0
- ccproxy/cli/helpers.py +22 -60
- ccproxy/cli/main.py +359 -10
- ccproxy/cli/options/claude_options.py +0 -25
- ccproxy/config/__init__.py +7 -11
- ccproxy/config/core.py +227 -0
- ccproxy/config/env_generator.py +232 -0
- ccproxy/config/runtime.py +67 -0
- ccproxy/config/security.py +36 -3
- ccproxy/config/settings.py +382 -441
- ccproxy/config/toml_generator.py +299 -0
- ccproxy/config/utils.py +452 -0
- ccproxy/core/__init__.py +7 -271
- ccproxy/{_version.py → core/_version.py} +16 -3
- ccproxy/core/async_task_manager.py +516 -0
- ccproxy/core/async_utils.py +47 -14
- ccproxy/core/auth/__init__.py +6 -0
- ccproxy/core/constants.py +16 -50
- ccproxy/core/errors.py +53 -0
- ccproxy/core/id_utils.py +20 -0
- ccproxy/core/interfaces.py +16 -123
- ccproxy/core/logging.py +473 -18
- ccproxy/core/plugins/__init__.py +77 -0
- ccproxy/core/plugins/cli_discovery.py +211 -0
- ccproxy/core/plugins/declaration.py +455 -0
- ccproxy/core/plugins/discovery.py +604 -0
- ccproxy/core/plugins/factories.py +967 -0
- ccproxy/core/plugins/hooks/__init__.py +30 -0
- ccproxy/core/plugins/hooks/base.py +58 -0
- ccproxy/core/plugins/hooks/events.py +46 -0
- ccproxy/core/plugins/hooks/implementations/__init__.py +16 -0
- ccproxy/core/plugins/hooks/implementations/formatters/__init__.py +11 -0
- ccproxy/core/plugins/hooks/implementations/formatters/json.py +552 -0
- ccproxy/core/plugins/hooks/implementations/formatters/raw.py +370 -0
- ccproxy/core/plugins/hooks/implementations/http_tracer.py +431 -0
- ccproxy/core/plugins/hooks/layers.py +44 -0
- ccproxy/core/plugins/hooks/manager.py +186 -0
- ccproxy/core/plugins/hooks/registry.py +139 -0
- ccproxy/core/plugins/hooks/thread_manager.py +203 -0
- ccproxy/core/plugins/hooks/types.py +22 -0
- ccproxy/core/plugins/interfaces.py +416 -0
- ccproxy/core/plugins/loader.py +166 -0
- ccproxy/core/plugins/middleware.py +233 -0
- ccproxy/core/plugins/models.py +59 -0
- ccproxy/core/plugins/protocol.py +180 -0
- ccproxy/core/plugins/runtime.py +519 -0
- ccproxy/{observability/context.py → core/request_context.py} +137 -94
- ccproxy/core/status_report.py +211 -0
- ccproxy/core/transformers.py +13 -8
- ccproxy/data/claude_headers_fallback.json +540 -19
- ccproxy/data/codex_headers_fallback.json +114 -7
- ccproxy/http/__init__.py +30 -0
- ccproxy/http/base.py +95 -0
- ccproxy/http/client.py +323 -0
- ccproxy/http/hooks.py +642 -0
- ccproxy/http/pool.py +279 -0
- ccproxy/llms/formatters/__init__.py +7 -0
- ccproxy/llms/formatters/anthropic_to_openai/__init__.py +55 -0
- ccproxy/llms/formatters/anthropic_to_openai/errors.py +65 -0
- ccproxy/llms/formatters/anthropic_to_openai/requests.py +356 -0
- ccproxy/llms/formatters/anthropic_to_openai/responses.py +153 -0
- ccproxy/llms/formatters/anthropic_to_openai/streams.py +1546 -0
- ccproxy/llms/formatters/base.py +140 -0
- ccproxy/llms/formatters/base_model.py +33 -0
- ccproxy/llms/formatters/common/__init__.py +51 -0
- ccproxy/llms/formatters/common/identifiers.py +48 -0
- ccproxy/llms/formatters/common/streams.py +254 -0
- ccproxy/llms/formatters/common/thinking.py +74 -0
- ccproxy/llms/formatters/common/usage.py +135 -0
- ccproxy/llms/formatters/constants.py +55 -0
- ccproxy/llms/formatters/context.py +116 -0
- ccproxy/llms/formatters/mapping.py +33 -0
- ccproxy/llms/formatters/openai_to_anthropic/__init__.py +55 -0
- ccproxy/llms/formatters/openai_to_anthropic/_helpers.py +141 -0
- ccproxy/llms/formatters/openai_to_anthropic/errors.py +53 -0
- ccproxy/llms/formatters/openai_to_anthropic/requests.py +674 -0
- ccproxy/llms/formatters/openai_to_anthropic/responses.py +285 -0
- ccproxy/llms/formatters/openai_to_anthropic/streams.py +530 -0
- ccproxy/llms/formatters/openai_to_openai/__init__.py +53 -0
- ccproxy/llms/formatters/openai_to_openai/_helpers.py +325 -0
- ccproxy/llms/formatters/openai_to_openai/errors.py +6 -0
- ccproxy/llms/formatters/openai_to_openai/requests.py +388 -0
- ccproxy/llms/formatters/openai_to_openai/responses.py +594 -0
- ccproxy/llms/formatters/openai_to_openai/streams.py +1832 -0
- ccproxy/llms/formatters/utils.py +306 -0
- ccproxy/llms/models/__init__.py +9 -0
- ccproxy/llms/models/anthropic.py +619 -0
- ccproxy/llms/models/openai.py +844 -0
- ccproxy/llms/streaming/__init__.py +26 -0
- ccproxy/llms/streaming/accumulators.py +1074 -0
- ccproxy/llms/streaming/formatters.py +251 -0
- ccproxy/{adapters/openai/streaming.py → llms/streaming/processors.py} +193 -240
- ccproxy/models/__init__.py +8 -159
- ccproxy/models/detection.py +92 -193
- ccproxy/models/provider.py +75 -0
- ccproxy/plugins/access_log/README.md +32 -0
- ccproxy/plugins/access_log/__init__.py +20 -0
- ccproxy/plugins/access_log/config.py +33 -0
- ccproxy/plugins/access_log/formatter.py +126 -0
- ccproxy/plugins/access_log/hook.py +763 -0
- ccproxy/plugins/access_log/logger.py +254 -0
- ccproxy/plugins/access_log/plugin.py +137 -0
- ccproxy/plugins/access_log/writer.py +109 -0
- ccproxy/plugins/analytics/README.md +24 -0
- ccproxy/plugins/analytics/__init__.py +1 -0
- ccproxy/plugins/analytics/config.py +5 -0
- ccproxy/plugins/analytics/ingest.py +85 -0
- ccproxy/plugins/analytics/models.py +97 -0
- ccproxy/plugins/analytics/plugin.py +121 -0
- ccproxy/plugins/analytics/routes.py +163 -0
- ccproxy/plugins/analytics/service.py +284 -0
- ccproxy/plugins/claude_api/README.md +29 -0
- ccproxy/plugins/claude_api/__init__.py +10 -0
- ccproxy/plugins/claude_api/adapter.py +829 -0
- ccproxy/plugins/claude_api/config.py +52 -0
- ccproxy/plugins/claude_api/detection_service.py +461 -0
- ccproxy/plugins/claude_api/health.py +175 -0
- ccproxy/plugins/claude_api/hooks.py +284 -0
- ccproxy/plugins/claude_api/models.py +256 -0
- ccproxy/plugins/claude_api/plugin.py +298 -0
- ccproxy/plugins/claude_api/routes.py +118 -0
- ccproxy/plugins/claude_api/streaming_metrics.py +68 -0
- ccproxy/plugins/claude_api/tasks.py +84 -0
- ccproxy/plugins/claude_sdk/README.md +35 -0
- ccproxy/plugins/claude_sdk/__init__.py +80 -0
- ccproxy/plugins/claude_sdk/adapter.py +749 -0
- ccproxy/plugins/claude_sdk/auth.py +57 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/client.py +63 -39
- ccproxy/plugins/claude_sdk/config.py +210 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/converter.py +6 -6
- ccproxy/plugins/claude_sdk/detection_service.py +163 -0
- ccproxy/{services/claude_sdk_service.py → plugins/claude_sdk/handler.py} +123 -304
- ccproxy/plugins/claude_sdk/health.py +113 -0
- ccproxy/plugins/claude_sdk/hooks.py +115 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/manager.py +42 -32
- ccproxy/{claude_sdk → plugins/claude_sdk}/message_queue.py +8 -8
- ccproxy/{models/claude_sdk.py → plugins/claude_sdk/models.py} +64 -16
- ccproxy/plugins/claude_sdk/options.py +154 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/parser.py +23 -5
- ccproxy/plugins/claude_sdk/plugin.py +269 -0
- ccproxy/plugins/claude_sdk/routes.py +104 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/session_client.py +124 -12
- ccproxy/plugins/claude_sdk/session_pool.py +700 -0
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_handle.py +48 -43
- ccproxy/{claude_sdk → plugins/claude_sdk}/stream_worker.py +22 -18
- ccproxy/{claude_sdk → plugins/claude_sdk}/streaming.py +50 -16
- ccproxy/plugins/claude_sdk/tasks.py +97 -0
- ccproxy/plugins/claude_shared/README.md +18 -0
- ccproxy/plugins/claude_shared/__init__.py +12 -0
- ccproxy/plugins/claude_shared/model_defaults.py +171 -0
- ccproxy/plugins/codex/README.md +35 -0
- ccproxy/plugins/codex/__init__.py +6 -0
- ccproxy/plugins/codex/adapter.py +635 -0
- ccproxy/{config/codex.py → plugins/codex/config.py} +78 -12
- ccproxy/plugins/codex/detection_service.py +544 -0
- ccproxy/plugins/codex/health.py +162 -0
- ccproxy/plugins/codex/hooks.py +263 -0
- ccproxy/plugins/codex/model_defaults.py +39 -0
- ccproxy/plugins/codex/models.py +263 -0
- ccproxy/plugins/codex/plugin.py +275 -0
- ccproxy/plugins/codex/routes.py +129 -0
- ccproxy/plugins/codex/streaming_metrics.py +324 -0
- ccproxy/plugins/codex/tasks.py +106 -0
- ccproxy/plugins/codex/utils/__init__.py +1 -0
- ccproxy/plugins/codex/utils/sse_parser.py +106 -0
- ccproxy/plugins/command_replay/README.md +34 -0
- ccproxy/plugins/command_replay/__init__.py +17 -0
- ccproxy/plugins/command_replay/config.py +133 -0
- ccproxy/plugins/command_replay/formatter.py +432 -0
- ccproxy/plugins/command_replay/hook.py +294 -0
- ccproxy/plugins/command_replay/plugin.py +161 -0
- ccproxy/plugins/copilot/README.md +39 -0
- ccproxy/plugins/copilot/__init__.py +11 -0
- ccproxy/plugins/copilot/adapter.py +465 -0
- ccproxy/plugins/copilot/config.py +155 -0
- ccproxy/plugins/copilot/data/copilot_fallback.json +41 -0
- ccproxy/plugins/copilot/detection_service.py +255 -0
- ccproxy/plugins/copilot/manager.py +275 -0
- ccproxy/plugins/copilot/model_defaults.py +284 -0
- ccproxy/plugins/copilot/models.py +148 -0
- ccproxy/plugins/copilot/oauth/__init__.py +16 -0
- ccproxy/plugins/copilot/oauth/client.py +494 -0
- ccproxy/plugins/copilot/oauth/models.py +385 -0
- ccproxy/plugins/copilot/oauth/provider.py +602 -0
- ccproxy/plugins/copilot/oauth/storage.py +170 -0
- ccproxy/plugins/copilot/plugin.py +360 -0
- ccproxy/plugins/copilot/routes.py +294 -0
- ccproxy/plugins/credential_balancer/README.md +124 -0
- ccproxy/plugins/credential_balancer/__init__.py +6 -0
- ccproxy/plugins/credential_balancer/config.py +270 -0
- ccproxy/plugins/credential_balancer/factory.py +415 -0
- ccproxy/plugins/credential_balancer/hook.py +51 -0
- ccproxy/plugins/credential_balancer/manager.py +587 -0
- ccproxy/plugins/credential_balancer/plugin.py +146 -0
- ccproxy/plugins/dashboard/README.md +25 -0
- ccproxy/plugins/dashboard/__init__.py +1 -0
- ccproxy/plugins/dashboard/config.py +8 -0
- ccproxy/plugins/dashboard/plugin.py +71 -0
- ccproxy/plugins/dashboard/routes.py +67 -0
- ccproxy/plugins/docker/README.md +32 -0
- ccproxy/{docker → plugins/docker}/__init__.py +3 -0
- ccproxy/{docker → plugins/docker}/adapter.py +108 -10
- ccproxy/plugins/docker/config.py +82 -0
- ccproxy/{docker → plugins/docker}/docker_path.py +4 -3
- ccproxy/{docker → plugins/docker}/middleware.py +2 -2
- ccproxy/plugins/docker/plugin.py +198 -0
- ccproxy/{docker → plugins/docker}/stream_process.py +3 -3
- ccproxy/plugins/duckdb_storage/README.md +26 -0
- ccproxy/plugins/duckdb_storage/__init__.py +1 -0
- ccproxy/plugins/duckdb_storage/config.py +22 -0
- ccproxy/plugins/duckdb_storage/plugin.py +128 -0
- ccproxy/plugins/duckdb_storage/routes.py +51 -0
- ccproxy/plugins/duckdb_storage/storage.py +633 -0
- ccproxy/plugins/max_tokens/README.md +38 -0
- ccproxy/plugins/max_tokens/__init__.py +12 -0
- ccproxy/plugins/max_tokens/adapter.py +235 -0
- ccproxy/plugins/max_tokens/config.py +86 -0
- ccproxy/plugins/max_tokens/models.py +53 -0
- ccproxy/plugins/max_tokens/plugin.py +200 -0
- ccproxy/plugins/max_tokens/service.py +271 -0
- ccproxy/plugins/max_tokens/token_limits.json +54 -0
- ccproxy/plugins/metrics/README.md +35 -0
- ccproxy/plugins/metrics/__init__.py +10 -0
- ccproxy/{observability/metrics.py → plugins/metrics/collector.py} +20 -153
- ccproxy/plugins/metrics/config.py +85 -0
- ccproxy/plugins/metrics/grafana/dashboards/ccproxy-dashboard.json +1720 -0
- ccproxy/plugins/metrics/hook.py +403 -0
- ccproxy/plugins/metrics/plugin.py +268 -0
- ccproxy/{observability → plugins/metrics}/pushgateway.py +57 -59
- ccproxy/plugins/metrics/routes.py +107 -0
- ccproxy/plugins/metrics/tasks.py +117 -0
- ccproxy/plugins/oauth_claude/README.md +35 -0
- ccproxy/plugins/oauth_claude/__init__.py +14 -0
- ccproxy/plugins/oauth_claude/client.py +270 -0
- ccproxy/plugins/oauth_claude/config.py +84 -0
- ccproxy/plugins/oauth_claude/manager.py +482 -0
- ccproxy/plugins/oauth_claude/models.py +266 -0
- ccproxy/plugins/oauth_claude/plugin.py +149 -0
- ccproxy/plugins/oauth_claude/provider.py +571 -0
- ccproxy/plugins/oauth_claude/storage.py +212 -0
- ccproxy/plugins/oauth_codex/README.md +38 -0
- ccproxy/plugins/oauth_codex/__init__.py +14 -0
- ccproxy/plugins/oauth_codex/client.py +224 -0
- ccproxy/plugins/oauth_codex/config.py +95 -0
- ccproxy/plugins/oauth_codex/manager.py +256 -0
- ccproxy/plugins/oauth_codex/models.py +239 -0
- ccproxy/plugins/oauth_codex/plugin.py +146 -0
- ccproxy/plugins/oauth_codex/provider.py +574 -0
- ccproxy/plugins/oauth_codex/storage.py +92 -0
- ccproxy/plugins/permissions/README.md +28 -0
- ccproxy/plugins/permissions/__init__.py +22 -0
- ccproxy/plugins/permissions/config.py +28 -0
- ccproxy/{cli/commands/permission_handler.py → plugins/permissions/handlers/cli.py} +49 -25
- ccproxy/plugins/permissions/handlers/protocol.py +33 -0
- ccproxy/plugins/permissions/handlers/terminal.py +675 -0
- ccproxy/{api/routes → plugins/permissions}/mcp.py +34 -7
- ccproxy/{models/permissions.py → plugins/permissions/models.py} +65 -1
- ccproxy/plugins/permissions/plugin.py +153 -0
- ccproxy/{api/routes/permissions.py → plugins/permissions/routes.py} +20 -16
- ccproxy/{api/services/permission_service.py → plugins/permissions/service.py} +65 -11
- ccproxy/{api → plugins/permissions}/ui/permission_handler_protocol.py +1 -1
- ccproxy/{api → plugins/permissions}/ui/terminal_permission_handler.py +66 -10
- ccproxy/plugins/pricing/README.md +34 -0
- ccproxy/plugins/pricing/__init__.py +6 -0
- ccproxy/{pricing → plugins/pricing}/cache.py +7 -6
- ccproxy/{config/pricing.py → plugins/pricing/config.py} +32 -6
- ccproxy/plugins/pricing/exceptions.py +35 -0
- ccproxy/plugins/pricing/loader.py +440 -0
- ccproxy/{pricing → plugins/pricing}/models.py +13 -23
- ccproxy/plugins/pricing/plugin.py +169 -0
- ccproxy/plugins/pricing/service.py +191 -0
- ccproxy/plugins/pricing/tasks.py +300 -0
- ccproxy/{pricing → plugins/pricing}/updater.py +86 -72
- ccproxy/plugins/pricing/utils.py +99 -0
- ccproxy/plugins/request_tracer/README.md +40 -0
- ccproxy/plugins/request_tracer/__init__.py +7 -0
- ccproxy/plugins/request_tracer/config.py +120 -0
- ccproxy/plugins/request_tracer/hook.py +415 -0
- ccproxy/plugins/request_tracer/plugin.py +255 -0
- ccproxy/scheduler/__init__.py +2 -14
- ccproxy/scheduler/core.py +26 -41
- ccproxy/scheduler/manager.py +61 -105
- ccproxy/scheduler/registry.py +6 -32
- ccproxy/scheduler/tasks.py +268 -276
- ccproxy/services/__init__.py +0 -1
- ccproxy/services/adapters/__init__.py +11 -0
- ccproxy/services/adapters/base.py +123 -0
- ccproxy/services/adapters/chain_composer.py +88 -0
- ccproxy/services/adapters/chain_validation.py +44 -0
- ccproxy/services/adapters/chat_accumulator.py +200 -0
- ccproxy/services/adapters/delta_utils.py +142 -0
- ccproxy/services/adapters/format_adapter.py +136 -0
- ccproxy/services/adapters/format_context.py +11 -0
- ccproxy/services/adapters/format_registry.py +158 -0
- ccproxy/services/adapters/http_adapter.py +1045 -0
- ccproxy/services/adapters/mock_adapter.py +118 -0
- ccproxy/services/adapters/protocols.py +35 -0
- ccproxy/services/adapters/simple_converters.py +571 -0
- ccproxy/services/auth_registry.py +180 -0
- ccproxy/services/cache/__init__.py +6 -0
- ccproxy/services/cache/response_cache.py +261 -0
- ccproxy/services/cli_detection.py +437 -0
- ccproxy/services/config/__init__.py +6 -0
- ccproxy/services/config/proxy_configuration.py +111 -0
- ccproxy/services/container.py +256 -0
- ccproxy/services/factories.py +380 -0
- ccproxy/services/handler_config.py +76 -0
- ccproxy/services/interfaces.py +298 -0
- ccproxy/services/mocking/__init__.py +6 -0
- ccproxy/services/mocking/mock_handler.py +291 -0
- ccproxy/services/tracing/__init__.py +7 -0
- ccproxy/services/tracing/interfaces.py +61 -0
- ccproxy/services/tracing/null_tracer.py +57 -0
- ccproxy/streaming/__init__.py +23 -0
- ccproxy/streaming/buffer.py +1056 -0
- ccproxy/streaming/deferred.py +897 -0
- ccproxy/streaming/handler.py +117 -0
- ccproxy/streaming/interfaces.py +77 -0
- ccproxy/streaming/simple_adapter.py +39 -0
- ccproxy/streaming/sse.py +109 -0
- ccproxy/streaming/sse_parser.py +127 -0
- ccproxy/templates/__init__.py +6 -0
- ccproxy/templates/plugin_scaffold.py +695 -0
- ccproxy/testing/endpoints/__init__.py +33 -0
- ccproxy/testing/endpoints/cli.py +215 -0
- ccproxy/testing/endpoints/config.py +874 -0
- ccproxy/testing/endpoints/console.py +57 -0
- ccproxy/testing/endpoints/models.py +100 -0
- ccproxy/testing/endpoints/runner.py +1903 -0
- ccproxy/testing/endpoints/tools.py +308 -0
- ccproxy/testing/mock_responses.py +70 -1
- ccproxy/testing/response_handlers.py +20 -0
- ccproxy/utils/__init__.py +0 -6
- ccproxy/utils/binary_resolver.py +476 -0
- ccproxy/utils/caching.py +327 -0
- ccproxy/utils/cli_logging.py +101 -0
- ccproxy/utils/command_line.py +251 -0
- ccproxy/utils/headers.py +228 -0
- ccproxy/utils/model_mapper.py +120 -0
- ccproxy/utils/startup_helpers.py +68 -446
- ccproxy/utils/version_checker.py +273 -6
- ccproxy_api-0.2.0.dist-info/METADATA +212 -0
- ccproxy_api-0.2.0.dist-info/RECORD +417 -0
- {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0.dist-info}/WHEEL +1 -1
- ccproxy_api-0.2.0.dist-info/entry_points.txt +24 -0
- ccproxy/__init__.py +0 -4
- ccproxy/adapters/__init__.py +0 -11
- ccproxy/adapters/base.py +0 -80
- ccproxy/adapters/codex/__init__.py +0 -11
- ccproxy/adapters/openai/__init__.py +0 -42
- ccproxy/adapters/openai/adapter.py +0 -953
- ccproxy/adapters/openai/models.py +0 -412
- ccproxy/adapters/openai/response_adapter.py +0 -355
- ccproxy/adapters/openai/response_models.py +0 -178
- ccproxy/api/middleware/headers.py +0 -49
- ccproxy/api/middleware/logging.py +0 -180
- ccproxy/api/middleware/request_content_logging.py +0 -297
- ccproxy/api/middleware/server_header.py +0 -58
- ccproxy/api/responses.py +0 -89
- ccproxy/api/routes/claude.py +0 -371
- ccproxy/api/routes/codex.py +0 -1251
- ccproxy/api/routes/metrics.py +0 -1029
- ccproxy/api/routes/proxy.py +0 -211
- ccproxy/api/services/__init__.py +0 -6
- ccproxy/auth/conditional.py +0 -84
- ccproxy/auth/credentials_adapter.py +0 -93
- ccproxy/auth/models.py +0 -118
- ccproxy/auth/oauth/models.py +0 -48
- ccproxy/auth/openai/__init__.py +0 -13
- ccproxy/auth/openai/credentials.py +0 -166
- ccproxy/auth/openai/oauth_client.py +0 -334
- ccproxy/auth/openai/storage.py +0 -184
- ccproxy/auth/storage/json_file.py +0 -158
- ccproxy/auth/storage/keyring.py +0 -189
- ccproxy/claude_sdk/__init__.py +0 -18
- ccproxy/claude_sdk/options.py +0 -194
- ccproxy/claude_sdk/session_pool.py +0 -550
- ccproxy/cli/docker/__init__.py +0 -34
- ccproxy/cli/docker/adapter_factory.py +0 -157
- ccproxy/cli/docker/params.py +0 -274
- ccproxy/config/auth.py +0 -153
- ccproxy/config/claude.py +0 -348
- ccproxy/config/cors.py +0 -79
- ccproxy/config/discovery.py +0 -95
- ccproxy/config/docker_settings.py +0 -264
- ccproxy/config/observability.py +0 -158
- ccproxy/config/reverse_proxy.py +0 -31
- ccproxy/config/scheduler.py +0 -108
- ccproxy/config/server.py +0 -86
- ccproxy/config/validators.py +0 -231
- ccproxy/core/codex_transformers.py +0 -389
- ccproxy/core/http.py +0 -328
- ccproxy/core/http_transformers.py +0 -812
- ccproxy/core/proxy.py +0 -143
- ccproxy/core/validators.py +0 -288
- ccproxy/models/errors.py +0 -42
- ccproxy/models/messages.py +0 -269
- ccproxy/models/requests.py +0 -107
- ccproxy/models/responses.py +0 -270
- ccproxy/models/types.py +0 -102
- ccproxy/observability/__init__.py +0 -51
- ccproxy/observability/access_logger.py +0 -457
- ccproxy/observability/sse_events.py +0 -303
- ccproxy/observability/stats_printer.py +0 -753
- ccproxy/observability/storage/__init__.py +0 -1
- ccproxy/observability/storage/duckdb_simple.py +0 -677
- ccproxy/observability/storage/models.py +0 -70
- ccproxy/observability/streaming_response.py +0 -107
- ccproxy/pricing/__init__.py +0 -19
- ccproxy/pricing/loader.py +0 -251
- ccproxy/services/claude_detection_service.py +0 -243
- ccproxy/services/codex_detection_service.py +0 -252
- ccproxy/services/credentials/__init__.py +0 -55
- ccproxy/services/credentials/config.py +0 -105
- ccproxy/services/credentials/manager.py +0 -561
- ccproxy/services/credentials/oauth_client.py +0 -481
- ccproxy/services/proxy_service.py +0 -1827
- ccproxy/static/.keep +0 -0
- ccproxy/utils/cost_calculator.py +0 -210
- ccproxy/utils/disconnection_monitor.py +0 -83
- ccproxy/utils/model_mapping.py +0 -199
- ccproxy/utils/models_provider.py +0 -150
- ccproxy/utils/simple_request_logger.py +0 -284
- ccproxy/utils/streaming_metrics.py +0 -199
- ccproxy_api-0.1.7.dist-info/METADATA +0 -615
- ccproxy_api-0.1.7.dist-info/RECORD +0 -191
- ccproxy_api-0.1.7.dist-info/entry_points.txt +0 -4
- /ccproxy/{api/middleware/auth.py → auth/models/__init__.py} +0 -0
- /ccproxy/{claude_sdk → plugins/claude_sdk}/exceptions.py +0 -0
- /ccproxy/{docker → plugins/docker}/models.py +0 -0
- /ccproxy/{docker → plugins/docker}/protocol.py +0 -0
- /ccproxy/{docker → plugins/docker}/validators.py +0 -0
- /ccproxy/{auth/oauth/storage.py → plugins/permissions/handlers/__init__.py} +0 -0
- /ccproxy/{api → plugins/permissions}/ui/__init__.py +0 -0
- {ccproxy_api-0.1.7.dist-info → ccproxy_api-0.2.0.dist-info}/licenses/LICENSE +0 -0
ccproxy/scheduler/core.py
CHANGED
|
@@ -11,7 +11,7 @@ from .errors import (
|
|
|
11
11
|
TaskNotFoundError,
|
|
12
12
|
TaskRegistrationError,
|
|
13
13
|
)
|
|
14
|
-
from .registry import TaskRegistry
|
|
14
|
+
from .registry import TaskRegistry
|
|
15
15
|
from .tasks import BaseScheduledTask
|
|
16
16
|
|
|
17
17
|
|
|
@@ -31,9 +31,9 @@ class Scheduler:
|
|
|
31
31
|
|
|
32
32
|
def __init__(
|
|
33
33
|
self,
|
|
34
|
+
task_registry: TaskRegistry,
|
|
34
35
|
max_concurrent_tasks: int = 10,
|
|
35
36
|
graceful_shutdown_timeout: float = 30.0,
|
|
36
|
-
task_registry: TaskRegistry | None = None,
|
|
37
37
|
):
|
|
38
38
|
"""
|
|
39
39
|
Initialize the scheduler.
|
|
@@ -41,11 +41,11 @@ class Scheduler:
|
|
|
41
41
|
Args:
|
|
42
42
|
max_concurrent_tasks: Maximum number of tasks to run concurrently
|
|
43
43
|
graceful_shutdown_timeout: Timeout for graceful shutdown in seconds
|
|
44
|
-
task_registry: Task registry instance (
|
|
44
|
+
task_registry: Task registry instance (required)
|
|
45
45
|
"""
|
|
46
46
|
self.max_concurrent_tasks = max_concurrent_tasks
|
|
47
47
|
self.graceful_shutdown_timeout = graceful_shutdown_timeout
|
|
48
|
-
self.task_registry = task_registry
|
|
48
|
+
self.task_registry = task_registry
|
|
49
49
|
|
|
50
50
|
self._running = False
|
|
51
51
|
self._tasks: dict[str, BaseScheduledTask] = {}
|
|
@@ -63,7 +63,7 @@ class Scheduler:
|
|
|
63
63
|
logger.debug(
|
|
64
64
|
"scheduler_starting",
|
|
65
65
|
max_concurrent_tasks=self.max_concurrent_tasks,
|
|
66
|
-
registered_tasks=self.task_registry.
|
|
66
|
+
registered_tasks=self.task_registry.list(),
|
|
67
67
|
)
|
|
68
68
|
|
|
69
69
|
try:
|
|
@@ -81,6 +81,7 @@ class Scheduler:
|
|
|
81
81
|
"scheduler_start_failed",
|
|
82
82
|
error=str(e),
|
|
83
83
|
error_type=type(e).__name__,
|
|
84
|
+
exc_info=e,
|
|
84
85
|
)
|
|
85
86
|
raise SchedulerError(f"Failed to start scheduler: {e}") from e
|
|
86
87
|
|
|
@@ -90,7 +91,7 @@ class Scheduler:
|
|
|
90
91
|
return
|
|
91
92
|
|
|
92
93
|
self._running = False
|
|
93
|
-
logger.
|
|
94
|
+
logger.debug("scheduler_stopping", active_tasks=len(self._tasks))
|
|
94
95
|
|
|
95
96
|
# Stop all tasks
|
|
96
97
|
stop_tasks = []
|
|
@@ -106,7 +107,7 @@ class Scheduler:
|
|
|
106
107
|
asyncio.gather(*stop_tasks, return_exceptions=True),
|
|
107
108
|
timeout=self.graceful_shutdown_timeout,
|
|
108
109
|
)
|
|
109
|
-
logger.
|
|
110
|
+
logger.debug("scheduler_stopped_gracefully")
|
|
110
111
|
except TimeoutError:
|
|
111
112
|
logger.warning(
|
|
112
113
|
"scheduler_shutdown_timeout",
|
|
@@ -123,6 +124,7 @@ class Scheduler:
|
|
|
123
124
|
"scheduler_shutdown_error",
|
|
124
125
|
error=str(e),
|
|
125
126
|
error_type=type(e).__name__,
|
|
127
|
+
exc_info=e,
|
|
126
128
|
)
|
|
127
129
|
raise SchedulerShutdownError(
|
|
128
130
|
f"Error during scheduler shutdown: {e}"
|
|
@@ -152,7 +154,7 @@ class Scheduler:
|
|
|
152
154
|
if task_name in self._tasks:
|
|
153
155
|
raise SchedulerError(f"Task '{task_name}' already exists")
|
|
154
156
|
|
|
155
|
-
if not self.task_registry.
|
|
157
|
+
if not self.task_registry.has(task_type):
|
|
156
158
|
raise TaskRegistrationError(f"Task type '{task_type}' is not registered")
|
|
157
159
|
|
|
158
160
|
try:
|
|
@@ -160,6 +162,18 @@ class Scheduler:
|
|
|
160
162
|
task_class = self.task_registry.get(task_type)
|
|
161
163
|
task_instance = task_class(name=task_name, **task_kwargs)
|
|
162
164
|
|
|
165
|
+
interval_value = task_kwargs.get("interval_seconds")
|
|
166
|
+
if interval_value is not None:
|
|
167
|
+
try:
|
|
168
|
+
task_instance.interval_seconds = max(1.0, float(interval_value))
|
|
169
|
+
except (TypeError, ValueError):
|
|
170
|
+
logger.warning(
|
|
171
|
+
"task_interval_invalid",
|
|
172
|
+
task_name=task_name,
|
|
173
|
+
task_type=task_type,
|
|
174
|
+
interval_value=interval_value,
|
|
175
|
+
)
|
|
176
|
+
|
|
163
177
|
# Add to our tasks dict
|
|
164
178
|
self._tasks[task_name] = task_instance
|
|
165
179
|
|
|
@@ -191,6 +205,7 @@ class Scheduler:
|
|
|
191
205
|
task_type=task_type,
|
|
192
206
|
error=str(e),
|
|
193
207
|
error_type=type(e).__name__,
|
|
208
|
+
exc_info=e,
|
|
194
209
|
)
|
|
195
210
|
raise SchedulerError(f"Failed to add task '{task_name}': {e}") from e
|
|
196
211
|
|
|
@@ -222,6 +237,7 @@ class Scheduler:
|
|
|
222
237
|
task_name=task_name,
|
|
223
238
|
error=str(e),
|
|
224
239
|
error_type=type(e).__name__,
|
|
240
|
+
exc_info=e,
|
|
225
241
|
)
|
|
226
242
|
raise SchedulerError(f"Failed to remove task '{task_name}': {e}") from e
|
|
227
243
|
|
|
@@ -287,7 +303,7 @@ class Scheduler:
|
|
|
287
303
|
"graceful_shutdown_timeout": self.graceful_shutdown_timeout,
|
|
288
304
|
"task_names": list(self._tasks.keys()),
|
|
289
305
|
"running_task_names": running_tasks,
|
|
290
|
-
"registered_task_types": self.task_registry.
|
|
306
|
+
"registered_task_types": self.task_registry.list(),
|
|
291
307
|
}
|
|
292
308
|
|
|
293
309
|
@property
|
|
@@ -301,35 +317,4 @@ class Scheduler:
|
|
|
301
317
|
return len(self._tasks)
|
|
302
318
|
|
|
303
319
|
|
|
304
|
-
# Global scheduler
|
|
305
|
-
_global_scheduler: Scheduler | None = None
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
async def get_scheduler() -> Scheduler:
|
|
309
|
-
"""
|
|
310
|
-
Get or create the global scheduler instance.
|
|
311
|
-
|
|
312
|
-
Returns:
|
|
313
|
-
Global Scheduler instance
|
|
314
|
-
"""
|
|
315
|
-
global _global_scheduler
|
|
316
|
-
|
|
317
|
-
if _global_scheduler is None:
|
|
318
|
-
_global_scheduler = Scheduler()
|
|
319
|
-
|
|
320
|
-
return _global_scheduler
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
async def start_scheduler() -> None:
|
|
324
|
-
"""Start the global scheduler."""
|
|
325
|
-
scheduler = await get_scheduler()
|
|
326
|
-
await scheduler.start()
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
async def stop_scheduler() -> None:
|
|
330
|
-
"""Stop the global scheduler."""
|
|
331
|
-
global _global_scheduler
|
|
332
|
-
|
|
333
|
-
if _global_scheduler:
|
|
334
|
-
await _global_scheduler.stop()
|
|
335
|
-
_global_scheduler = None
|
|
320
|
+
# Global scheduler helpers omitted.
|
ccproxy/scheduler/manager.py
CHANGED
|
@@ -3,16 +3,12 @@
|
|
|
3
3
|
import structlog
|
|
4
4
|
|
|
5
5
|
from ccproxy.config.settings import Settings
|
|
6
|
+
from ccproxy.services.container import ServiceContainer
|
|
6
7
|
|
|
7
8
|
from .core import Scheduler
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
|
|
11
|
-
PricingCacheUpdateTask,
|
|
12
|
-
PushgatewayTask,
|
|
13
|
-
StatsPrintingTask,
|
|
14
|
-
VersionUpdateCheckTask,
|
|
15
|
-
)
|
|
9
|
+
from .errors import SchedulerError, TaskRegistrationError
|
|
10
|
+
from .registry import TaskRegistry
|
|
11
|
+
from .tasks import PoolStatsTask, VersionUpdateCheckTask
|
|
16
12
|
|
|
17
13
|
|
|
18
14
|
logger = structlog.get_logger(__name__)
|
|
@@ -29,11 +25,11 @@ async def setup_scheduler_tasks(scheduler: Scheduler, settings: Settings) -> Non
|
|
|
29
25
|
scheduler_config = settings.scheduler
|
|
30
26
|
|
|
31
27
|
if not scheduler_config.enabled:
|
|
32
|
-
logger.
|
|
28
|
+
logger.debug("scheduler_disabled")
|
|
33
29
|
return
|
|
34
30
|
|
|
35
31
|
# Log network features status
|
|
36
|
-
logger.
|
|
32
|
+
logger.debug(
|
|
37
33
|
"network_features_status",
|
|
38
34
|
pricing_updates_enabled=scheduler_config.pricing_update_enabled,
|
|
39
35
|
version_check_enabled=scheduler_config.version_check_enabled,
|
|
@@ -45,71 +41,21 @@ async def setup_scheduler_tasks(scheduler: Scheduler, settings: Settings) -> Non
|
|
|
45
41
|
),
|
|
46
42
|
)
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
max_backoff_seconds=scheduler_config.pushgateway_max_backoff_seconds,
|
|
57
|
-
)
|
|
58
|
-
logger.info(
|
|
59
|
-
"pushgateway_task_added",
|
|
60
|
-
interval_seconds=scheduler_config.pushgateway_interval_seconds,
|
|
61
|
-
)
|
|
62
|
-
except Exception as e:
|
|
63
|
-
logger.error(
|
|
64
|
-
"pushgateway_task_add_failed",
|
|
65
|
-
error=str(e),
|
|
66
|
-
error_type=type(e).__name__,
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
# Add stats printing task if enabled
|
|
70
|
-
if scheduler_config.stats_printing_enabled:
|
|
71
|
-
try:
|
|
72
|
-
await scheduler.add_task(
|
|
73
|
-
task_name="stats_printing",
|
|
74
|
-
task_type="stats_printing",
|
|
75
|
-
interval_seconds=scheduler_config.stats_printing_interval_seconds,
|
|
76
|
-
enabled=True,
|
|
77
|
-
)
|
|
78
|
-
logger.info(
|
|
79
|
-
"stats_printing_task_added",
|
|
80
|
-
interval_seconds=scheduler_config.stats_printing_interval_seconds,
|
|
81
|
-
)
|
|
82
|
-
except Exception as e:
|
|
83
|
-
logger.error(
|
|
84
|
-
"stats_printing_task_add_failed",
|
|
85
|
-
error=str(e),
|
|
86
|
-
error_type=type(e).__name__,
|
|
87
|
-
)
|
|
44
|
+
if (
|
|
45
|
+
hasattr(scheduler_config, "stats_printing_enabled")
|
|
46
|
+
and scheduler_config.stats_printing_enabled
|
|
47
|
+
):
|
|
48
|
+
logger.debug(
|
|
49
|
+
"stats_printing_task_skipped",
|
|
50
|
+
message="Stats printing is handled by plugin",
|
|
51
|
+
)
|
|
88
52
|
|
|
89
|
-
# Add pricing cache update task if enabled
|
|
90
53
|
if scheduler_config.pricing_update_enabled:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
task_name="pricing_cache_update",
|
|
97
|
-
task_type="pricing_cache_update",
|
|
98
|
-
interval_seconds=interval_seconds,
|
|
99
|
-
enabled=True,
|
|
100
|
-
force_refresh_on_startup=scheduler_config.pricing_force_refresh_on_startup,
|
|
101
|
-
)
|
|
102
|
-
logger.debug(
|
|
103
|
-
"pricing_update_task_added",
|
|
104
|
-
interval_hours=scheduler_config.pricing_update_interval_hours,
|
|
105
|
-
force_refresh_on_startup=scheduler_config.pricing_force_refresh_on_startup,
|
|
106
|
-
)
|
|
107
|
-
except Exception as e:
|
|
108
|
-
logger.error(
|
|
109
|
-
"pricing_update_task_add_failed",
|
|
110
|
-
error=str(e),
|
|
111
|
-
error_type=type(e).__name__,
|
|
112
|
-
)
|
|
54
|
+
logger.debug(
|
|
55
|
+
"pricing_update_task_handled_by_plugin",
|
|
56
|
+
message="Pricing updates managed by plugin",
|
|
57
|
+
interval_hours=scheduler_config.pricing_update_interval_hours,
|
|
58
|
+
)
|
|
113
59
|
|
|
114
60
|
# Add version update check task if enabled
|
|
115
61
|
if scheduler_config.version_check_enabled:
|
|
@@ -129,43 +75,36 @@ async def setup_scheduler_tasks(scheduler: Scheduler, settings: Settings) -> Non
|
|
|
129
75
|
interval_hours=scheduler_config.version_check_interval_hours,
|
|
130
76
|
version_check_cache_ttl_hours=scheduler_config.version_check_cache_ttl_hours,
|
|
131
77
|
)
|
|
78
|
+
except TaskRegistrationError as e:
|
|
79
|
+
logger.error(
|
|
80
|
+
"version_check_task_registration_failed",
|
|
81
|
+
error=str(e),
|
|
82
|
+
error_type=type(e).__name__,
|
|
83
|
+
exc_info=e,
|
|
84
|
+
)
|
|
132
85
|
except Exception as e:
|
|
133
86
|
logger.error(
|
|
134
87
|
"version_check_task_add_failed",
|
|
135
88
|
error=str(e),
|
|
136
89
|
error_type=type(e).__name__,
|
|
90
|
+
exc_info=e,
|
|
137
91
|
)
|
|
138
92
|
|
|
139
93
|
|
|
140
|
-
def _register_default_tasks(settings: Settings) -> None:
|
|
94
|
+
def _register_default_tasks(registry: TaskRegistry, settings: Settings) -> None:
|
|
141
95
|
"""Register default task types in the global registry based on configuration."""
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
registry = get_task_registry()
|
|
145
|
-
scheduler_config = settings.scheduler
|
|
146
|
-
|
|
147
|
-
# Only register pushgateway task if enabled
|
|
148
|
-
if scheduler_config.pushgateway_enabled and not registry.is_registered(
|
|
149
|
-
"pushgateway"
|
|
150
|
-
):
|
|
151
|
-
register_task("pushgateway", PushgatewayTask)
|
|
152
|
-
|
|
153
|
-
# Only register stats printing task if enabled
|
|
154
|
-
if scheduler_config.stats_printing_enabled and not registry.is_registered(
|
|
155
|
-
"stats_printing"
|
|
156
|
-
):
|
|
157
|
-
register_task("stats_printing", StatsPrintingTask)
|
|
96
|
+
# Registry is provided by DI
|
|
158
97
|
|
|
159
98
|
# Always register core tasks (not metrics-related)
|
|
160
|
-
if not registry.
|
|
161
|
-
|
|
162
|
-
if not registry.
|
|
163
|
-
|
|
164
|
-
if not registry.is_registered("pool_stats"):
|
|
165
|
-
register_task("pool_stats", PoolStatsTask)
|
|
99
|
+
if not registry.has("version_update_check"):
|
|
100
|
+
registry.register("version_update_check", VersionUpdateCheckTask)
|
|
101
|
+
if not registry.has("pool_stats"):
|
|
102
|
+
registry.register("pool_stats", PoolStatsTask)
|
|
166
103
|
|
|
167
104
|
|
|
168
|
-
async def start_scheduler(
|
|
105
|
+
async def start_scheduler(
|
|
106
|
+
settings: Settings, container: ServiceContainer
|
|
107
|
+
) -> Scheduler | None:
|
|
169
108
|
"""
|
|
170
109
|
Start the scheduler with configured tasks.
|
|
171
110
|
|
|
@@ -180,13 +119,15 @@ async def start_scheduler(settings: Settings) -> Scheduler | None:
|
|
|
180
119
|
logger.info("scheduler_disabled")
|
|
181
120
|
return None
|
|
182
121
|
|
|
183
|
-
#
|
|
184
|
-
|
|
122
|
+
# Resolve registry from DI and register task types
|
|
123
|
+
registry = container.get_task_registry()
|
|
124
|
+
_register_default_tasks(registry, settings)
|
|
185
125
|
|
|
186
126
|
# Create scheduler with settings
|
|
187
127
|
scheduler = Scheduler(
|
|
188
128
|
max_concurrent_tasks=settings.scheduler.max_concurrent_tasks,
|
|
189
129
|
graceful_shutdown_timeout=settings.scheduler.graceful_shutdown_timeout,
|
|
130
|
+
task_registry=registry,
|
|
190
131
|
)
|
|
191
132
|
|
|
192
133
|
# Start the scheduler
|
|
@@ -195,26 +136,33 @@ async def start_scheduler(settings: Settings) -> Scheduler | None:
|
|
|
195
136
|
# Setup tasks based on configuration
|
|
196
137
|
await setup_scheduler_tasks(scheduler, settings)
|
|
197
138
|
|
|
198
|
-
|
|
139
|
+
task_names = scheduler.list_tasks()
|
|
140
|
+
logger.debug(
|
|
199
141
|
"scheduler_started",
|
|
200
142
|
max_concurrent_tasks=settings.scheduler.max_concurrent_tasks,
|
|
201
143
|
active_tasks=scheduler.task_count,
|
|
202
144
|
running_tasks=len(
|
|
203
|
-
[
|
|
204
|
-
name
|
|
205
|
-
for name in scheduler.list_tasks()
|
|
206
|
-
if scheduler.get_task(name).is_running
|
|
207
|
-
]
|
|
145
|
+
[name for name in task_names if scheduler.get_task(name).is_running]
|
|
208
146
|
),
|
|
147
|
+
names=task_names,
|
|
209
148
|
)
|
|
210
149
|
|
|
211
150
|
return scheduler
|
|
212
151
|
|
|
152
|
+
except SchedulerError as e:
|
|
153
|
+
logger.error(
|
|
154
|
+
"scheduler_start_scheduler_error",
|
|
155
|
+
error=str(e),
|
|
156
|
+
error_type=type(e).__name__,
|
|
157
|
+
exc_info=e,
|
|
158
|
+
)
|
|
159
|
+
return None
|
|
213
160
|
except Exception as e:
|
|
214
161
|
logger.error(
|
|
215
162
|
"scheduler_start_failed",
|
|
216
163
|
error=str(e),
|
|
217
164
|
error_type=type(e).__name__,
|
|
165
|
+
exc_info=e,
|
|
218
166
|
)
|
|
219
167
|
return None
|
|
220
168
|
|
|
@@ -231,9 +179,17 @@ async def stop_scheduler(scheduler: Scheduler | None) -> None:
|
|
|
231
179
|
|
|
232
180
|
try:
|
|
233
181
|
await scheduler.stop()
|
|
182
|
+
except SchedulerError as e:
|
|
183
|
+
logger.error(
|
|
184
|
+
"scheduler_stop_scheduler_error",
|
|
185
|
+
error=str(e),
|
|
186
|
+
error_type=type(e).__name__,
|
|
187
|
+
exc_info=e,
|
|
188
|
+
)
|
|
234
189
|
except Exception as e:
|
|
235
190
|
logger.error(
|
|
236
191
|
"scheduler_stop_failed",
|
|
237
192
|
error=str(e),
|
|
238
193
|
error_type=type(e).__name__,
|
|
194
|
+
exc_info=e,
|
|
239
195
|
)
|
ccproxy/scheduler/registry.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Task registry for dynamic task registration and discovery."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
from typing import Any
|
|
4
6
|
|
|
5
7
|
import structlog
|
|
@@ -79,7 +81,7 @@ class TaskRegistry:
|
|
|
79
81
|
|
|
80
82
|
return self._tasks[name]
|
|
81
83
|
|
|
82
|
-
def
|
|
84
|
+
def list(self) -> list[str]:
|
|
83
85
|
"""
|
|
84
86
|
Get list of all registered task names.
|
|
85
87
|
|
|
@@ -88,7 +90,7 @@ class TaskRegistry:
|
|
|
88
90
|
"""
|
|
89
91
|
return list(self._tasks.keys())
|
|
90
92
|
|
|
91
|
-
def
|
|
93
|
+
def has(self, name: str) -> bool:
|
|
92
94
|
"""
|
|
93
95
|
Check if a task is registered.
|
|
94
96
|
|
|
@@ -105,7 +107,7 @@ class TaskRegistry:
|
|
|
105
107
|
self._tasks.clear()
|
|
106
108
|
logger.debug("task_registry_cleared")
|
|
107
109
|
|
|
108
|
-
def
|
|
110
|
+
def info(self) -> dict[str, Any]:
|
|
109
111
|
"""
|
|
110
112
|
Get information about the current registry state.
|
|
111
113
|
|
|
@@ -119,32 +121,4 @@ class TaskRegistry:
|
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
|
|
122
|
-
#
|
|
123
|
-
_global_registry: TaskRegistry | None = None
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def get_task_registry() -> TaskRegistry:
|
|
127
|
-
"""
|
|
128
|
-
Get the global task registry instance.
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
Global TaskRegistry instance
|
|
132
|
-
"""
|
|
133
|
-
global _global_registry
|
|
134
|
-
|
|
135
|
-
if _global_registry is None:
|
|
136
|
-
_global_registry = TaskRegistry()
|
|
137
|
-
|
|
138
|
-
return _global_registry
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def register_task(name: str, task_class: type[BaseScheduledTask]) -> None:
|
|
142
|
-
"""
|
|
143
|
-
Register a task in the global registry.
|
|
144
|
-
|
|
145
|
-
Args:
|
|
146
|
-
name: Unique name for the task
|
|
147
|
-
task_class: Task class that inherits from BaseScheduledTask
|
|
148
|
-
"""
|
|
149
|
-
registry = get_task_registry()
|
|
150
|
-
registry.register(name, task_class)
|
|
124
|
+
# Module-level accessors intentionally omitted.
|