-
Notifications
You must be signed in to change notification settings - Fork 2
fix: restore local bot api startup #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,52 +11,85 @@ static Env() { | |||||||||||||||||||||||||||||||||
| if (!Directory.Exists(WorkDir)) { | ||||||||||||||||||||||||||||||||||
| Directory.CreateDirectory(WorkDir); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| var config = new Config(); | ||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||
| var config = JsonConvert.DeserializeObject<Config>(File.ReadAllText(Path.Combine(WorkDir, "Config.json"))); | ||||||||||||||||||||||||||||||||||
| if (config is null) return; | ||||||||||||||||||||||||||||||||||
| EnableLocalBotAPI = config.EnableLocalBotAPI; | ||||||||||||||||||||||||||||||||||
| TelegramBotApiId = config.TelegramBotApiId; | ||||||||||||||||||||||||||||||||||
| TelegramBotApiHash = config.TelegramBotApiHash; | ||||||||||||||||||||||||||||||||||
| LocalBotApiPort = config.LocalBotApiPort; | ||||||||||||||||||||||||||||||||||
| if (config.EnableLocalBotAPI) { | ||||||||||||||||||||||||||||||||||
| BaseUrl = $"http://127.0.0.1:{config.LocalBotApiPort}"; | ||||||||||||||||||||||||||||||||||
| IsLocalAPI = true; | ||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||
| BaseUrl = config.BaseUrl; | ||||||||||||||||||||||||||||||||||
| IsLocalAPI = config.IsLocalAPI; | ||||||||||||||||||||||||||||||||||
| var loadedConfig = JsonConvert.DeserializeObject<Config>(File.ReadAllText(Path.Combine(WorkDir, "Config.json"))); | ||||||||||||||||||||||||||||||||||
| if (loadedConfig is not null) { | ||||||||||||||||||||||||||||||||||
| config = loadedConfig; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| BotToken = config.BotToken; | ||||||||||||||||||||||||||||||||||
| AdminId = config.AdminId; | ||||||||||||||||||||||||||||||||||
| EnableAutoOCR = config.EnableAutoOCR; | ||||||||||||||||||||||||||||||||||
| EnableAutoASR = config.EnableAutoASR; | ||||||||||||||||||||||||||||||||||
| //WorkDir = config.WorkDir; | ||||||||||||||||||||||||||||||||||
| TaskDelayTimeout = config.TaskDelayTimeout; | ||||||||||||||||||||||||||||||||||
| SameServer = config.SameServer; | ||||||||||||||||||||||||||||||||||
| OllamaModelName = config.OllamaModelName; | ||||||||||||||||||||||||||||||||||
| EnableVideoASR = config.EnableVideoASR; | ||||||||||||||||||||||||||||||||||
| EnableOpenAI = config.EnableOpenAI; | ||||||||||||||||||||||||||||||||||
| OpenAIModelName = config.OpenAIModelName; | ||||||||||||||||||||||||||||||||||
| OLTPAuth = config.OLTPAuth; | ||||||||||||||||||||||||||||||||||
| OLTPAuthUrl = config.OLTPAuthUrl; | ||||||||||||||||||||||||||||||||||
| OLTPName = config.OLTPName; | ||||||||||||||||||||||||||||||||||
| BraveApiKey = config.BraveApiKey; | ||||||||||||||||||||||||||||||||||
| EnableAccounting = config.EnableAccounting; | ||||||||||||||||||||||||||||||||||
| MaxToolCycles = config.MaxToolCycles; | ||||||||||||||||||||||||||||||||||
| EnableLLMAgentProcess = config.EnableLLMAgentProcess; | ||||||||||||||||||||||||||||||||||
| AgentHeartbeatIntervalSeconds = config.AgentHeartbeatIntervalSeconds; | ||||||||||||||||||||||||||||||||||
| AgentHeartbeatTimeoutSeconds = config.AgentHeartbeatTimeoutSeconds; | ||||||||||||||||||||||||||||||||||
| AgentChunkPollingIntervalMilliseconds = config.AgentChunkPollingIntervalMilliseconds; | ||||||||||||||||||||||||||||||||||
| AgentIdleTimeoutMinutes = config.AgentIdleTimeoutMinutes; | ||||||||||||||||||||||||||||||||||
| MaxConcurrentAgents = config.MaxConcurrentAgents; | ||||||||||||||||||||||||||||||||||
| AgentTaskTimeoutSeconds = config.AgentTaskTimeoutSeconds; | ||||||||||||||||||||||||||||||||||
| AgentShutdownGracePeriodSeconds = config.AgentShutdownGracePeriodSeconds; | ||||||||||||||||||||||||||||||||||
| AgentMaxRecoveryAttempts = config.AgentMaxRecoveryAttempts; | ||||||||||||||||||||||||||||||||||
| AgentQueueBacklogWarningThreshold = config.AgentQueueBacklogWarningThreshold; | ||||||||||||||||||||||||||||||||||
| AgentProcessMemoryLimitMb = config.AgentProcessMemoryLimitMb; | ||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| var botApiEndpoint = ResolveBotApiEndpoint(config); | ||||||||||||||||||||||||||||||||||
| EnableLocalBotAPI = config.EnableLocalBotAPI; | ||||||||||||||||||||||||||||||||||
| TelegramBotApiId = config.TelegramBotApiId; | ||||||||||||||||||||||||||||||||||
| TelegramBotApiHash = config.TelegramBotApiHash; | ||||||||||||||||||||||||||||||||||
| LocalBotApiPort = config.LocalBotApiPort; | ||||||||||||||||||||||||||||||||||
| ExternalLocalBotApiBaseUrl = botApiEndpoint.ExternalLocalBotApiBaseUrl; | ||||||||||||||||||||||||||||||||||
| BaseUrl = botApiEndpoint.BaseUrl; | ||||||||||||||||||||||||||||||||||
| IsLocalAPI = botApiEndpoint.IsLocalApi; | ||||||||||||||||||||||||||||||||||
| BotToken = config.BotToken; | ||||||||||||||||||||||||||||||||||
| AdminId = config.AdminId; | ||||||||||||||||||||||||||||||||||
| EnableAutoOCR = config.EnableAutoOCR; | ||||||||||||||||||||||||||||||||||
| EnableAutoASR = config.EnableAutoASR; | ||||||||||||||||||||||||||||||||||
| //WorkDir = config.WorkDir; | ||||||||||||||||||||||||||||||||||
| TaskDelayTimeout = config.TaskDelayTimeout; | ||||||||||||||||||||||||||||||||||
| SameServer = config.SameServer; | ||||||||||||||||||||||||||||||||||
| OllamaModelName = config.OllamaModelName; | ||||||||||||||||||||||||||||||||||
| EnableVideoASR = config.EnableVideoASR; | ||||||||||||||||||||||||||||||||||
| EnableOpenAI = config.EnableOpenAI; | ||||||||||||||||||||||||||||||||||
| OpenAIModelName = config.OpenAIModelName; | ||||||||||||||||||||||||||||||||||
| OLTPAuth = config.OLTPAuth; | ||||||||||||||||||||||||||||||||||
| OLTPAuthUrl = config.OLTPAuthUrl; | ||||||||||||||||||||||||||||||||||
| OLTPName = config.OLTPName; | ||||||||||||||||||||||||||||||||||
| BraveApiKey = config.BraveApiKey; | ||||||||||||||||||||||||||||||||||
| EnableAccounting = config.EnableAccounting; | ||||||||||||||||||||||||||||||||||
| MaxToolCycles = config.MaxToolCycles; | ||||||||||||||||||||||||||||||||||
| EnableLLMAgentProcess = config.EnableLLMAgentProcess; | ||||||||||||||||||||||||||||||||||
| AgentHeartbeatIntervalSeconds = config.AgentHeartbeatIntervalSeconds; | ||||||||||||||||||||||||||||||||||
| AgentHeartbeatTimeoutSeconds = config.AgentHeartbeatTimeoutSeconds; | ||||||||||||||||||||||||||||||||||
| AgentChunkPollingIntervalMilliseconds = config.AgentChunkPollingIntervalMilliseconds; | ||||||||||||||||||||||||||||||||||
| AgentIdleTimeoutMinutes = config.AgentIdleTimeoutMinutes; | ||||||||||||||||||||||||||||||||||
| MaxConcurrentAgents = config.MaxConcurrentAgents; | ||||||||||||||||||||||||||||||||||
| AgentTaskTimeoutSeconds = config.AgentTaskTimeoutSeconds; | ||||||||||||||||||||||||||||||||||
| AgentShutdownGracePeriodSeconds = config.AgentShutdownGracePeriodSeconds; | ||||||||||||||||||||||||||||||||||
| AgentMaxRecoveryAttempts = config.AgentMaxRecoveryAttempts; | ||||||||||||||||||||||||||||||||||
| AgentQueueBacklogWarningThreshold = config.AgentQueueBacklogWarningThreshold; | ||||||||||||||||||||||||||||||||||
| AgentProcessMemoryLimitMb = config.AgentProcessMemoryLimitMb; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| public static BotApiEndpointSettings ResolveBotApiEndpoint(Config config) { | ||||||||||||||||||||||||||||||||||
| ArgumentNullException.ThrowIfNull(config); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| var normalizedExternalLocalBotApiBaseUrl = NormalizeBaseUrl(config.ExternalLocalBotApiBaseUrl, string.Empty); | ||||||||||||||||||||||||||||||||||
| if (config.EnableLocalBotAPI) { | ||||||||||||||||||||||||||||||||||
| return new BotApiEndpointSettings( | ||||||||||||||||||||||||||||||||||
| $"http://127.0.0.1:{config.LocalBotApiPort}", | ||||||||||||||||||||||||||||||||||
| true, | ||||||||||||||||||||||||||||||||||
| normalizedExternalLocalBotApiBaseUrl); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (!string.IsNullOrWhiteSpace(normalizedExternalLocalBotApiBaseUrl)) { | ||||||||||||||||||||||||||||||||||
| return new BotApiEndpointSettings( | ||||||||||||||||||||||||||||||||||
| normalizedExternalLocalBotApiBaseUrl, | ||||||||||||||||||||||||||||||||||
| true, | ||||||||||||||||||||||||||||||||||
| normalizedExternalLocalBotApiBaseUrl); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+72
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate Any non-empty value currently sets 🛡️ Proposed validation guard- if (!string.IsNullOrWhiteSpace(normalizedExternalLocalBotApiBaseUrl)) {
+ if (!string.IsNullOrWhiteSpace(normalizedExternalLocalBotApiBaseUrl)) {
+ if (!Uri.TryCreate(normalizedExternalLocalBotApiBaseUrl, UriKind.Absolute, out var externalUri) ||
+ (externalUri.Scheme != Uri.UriSchemeHttp && externalUri.Scheme != Uri.UriSchemeHttps) ||
+ !(externalUri.IsLoopback || string.Equals(externalUri.Host, "localhost", StringComparison.OrdinalIgnoreCase))) {
+ throw new InvalidOperationException("ExternalLocalBotApiBaseUrl must be an absolute loopback http/https URL.");
+ }
+
return new BotApiEndpointSettings(
normalizedExternalLocalBotApiBaseUrl,
true,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return new BotApiEndpointSettings( | ||||||||||||||||||||||||||||||||||
| NormalizeBaseUrl(config.BaseUrl, "https://api.telegram.org"), | ||||||||||||||||||||||||||||||||||
| config.IsLocalAPI, | ||||||||||||||||||||||||||||||||||
| normalizedExternalLocalBotApiBaseUrl); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| private static string NormalizeBaseUrl(string? baseUrl, string fallback) { | ||||||||||||||||||||||||||||||||||
| if (string.IsNullOrWhiteSpace(baseUrl)) { | ||||||||||||||||||||||||||||||||||
| return fallback; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return baseUrl.Trim().TrimEnd('/'); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| public static readonly string BaseUrl = null!; | ||||||||||||||||||||||||||||||||||
| #pragma warning disable CS8604 // 引用类型参数可能为 null。 | ||||||||||||||||||||||||||||||||||
| public static readonly bool IsLocalAPI; | ||||||||||||||||||||||||||||||||||
|
|
@@ -69,6 +102,7 @@ static Env() { | |||||||||||||||||||||||||||||||||
| public static readonly string TelegramBotApiId = null!; | ||||||||||||||||||||||||||||||||||
| public static readonly string TelegramBotApiHash = null!; | ||||||||||||||||||||||||||||||||||
| public static readonly int LocalBotApiPort; | ||||||||||||||||||||||||||||||||||
| public static readonly string ExternalLocalBotApiBaseUrl = string.Empty; | ||||||||||||||||||||||||||||||||||
| public static readonly string WorkDir = null!; | ||||||||||||||||||||||||||||||||||
| public static readonly int TaskDelayTimeout; | ||||||||||||||||||||||||||||||||||
| public static readonly bool SameServer; | ||||||||||||||||||||||||||||||||||
|
|
@@ -107,6 +141,7 @@ public class Config { | |||||||||||||||||||||||||||||||||
| //public string WorkDir { get; set; } = "/data/TelegramSearchBot"; | ||||||||||||||||||||||||||||||||||
| public bool IsLocalAPI { get; set; } = false; | ||||||||||||||||||||||||||||||||||
| public bool EnableLocalBotAPI { get; set; } = false; | ||||||||||||||||||||||||||||||||||
| public string ExternalLocalBotApiBaseUrl { get; set; } = string.Empty; | ||||||||||||||||||||||||||||||||||
| public string TelegramBotApiId { get; set; } = null!; | ||||||||||||||||||||||||||||||||||
| public string TelegramBotApiHash { get; set; } = null!; | ||||||||||||||||||||||||||||||||||
| public int LocalBotApiPort { get; set; } = 8081; | ||||||||||||||||||||||||||||||||||
|
|
@@ -134,4 +169,6 @@ public class Config { | |||||||||||||||||||||||||||||||||
| public int AgentQueueBacklogWarningThreshold { get; set; } = 20; | ||||||||||||||||||||||||||||||||||
| public int AgentProcessMemoryLimitMb { get; set; } = 256; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| public sealed record BotApiEndpointSettings(string BaseUrl, bool IsLocalApi, string ExternalLocalBotApiBaseUrl); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| using TelegramSearchBot.Common; | ||
| using Xunit; | ||
|
|
||
| namespace TelegramSearchBot.Test.Common { | ||
| public class EnvBotApiEndpointTests { | ||
| [Fact] | ||
| public void ResolveBotApiEndpoint_UsesEmbeddedLocalApiWhenEnabled() { | ||
| var result = Env.ResolveBotApiEndpoint(new Config { | ||
| BaseUrl = "https://api.telegram.org", | ||
| EnableLocalBotAPI = true, | ||
| LocalBotApiPort = 8081, | ||
| ExternalLocalBotApiBaseUrl = "http://127.0.0.1:8082/" | ||
| }); | ||
|
|
||
| Assert.Equal("http://127.0.0.1:8081", result.BaseUrl); | ||
| Assert.True(result.IsLocalApi); | ||
| Assert.Equal("http://127.0.0.1:8082", result.ExternalLocalBotApiBaseUrl); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ResolveBotApiEndpoint_UsesExternalLocalApiWhenConfigured() { | ||
| var result = Env.ResolveBotApiEndpoint(new Config { | ||
| BaseUrl = "https://api.telegram.org", | ||
| IsLocalAPI = false, | ||
| EnableLocalBotAPI = false, | ||
| ExternalLocalBotApiBaseUrl = "http://127.0.0.1:8082/" | ||
| }); | ||
|
|
||
| Assert.Equal("http://127.0.0.1:8082", result.BaseUrl); | ||
| Assert.True(result.IsLocalApi); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ResolveBotApiEndpoint_FallsBackToConfiguredBaseUrlWhenNoLocalApiConfigured() { | ||
| var result = Env.ResolveBotApiEndpoint(new Config { | ||
| BaseUrl = "https://api.telegram.org/", | ||
| IsLocalAPI = false, | ||
| EnableLocalBotAPI = false | ||
| }); | ||
|
|
||
| Assert.Equal("https://api.telegram.org", result.BaseUrl); | ||
| Assert.False(result.IsLocalApi); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refresh the document footer.
The architecture doc content changed for the new external Local Bot API mode, but the footer still shows the prior update date/version.
📝 Proposed footer update
📝 Committable suggestion
🤖 Prompt for AI Agents