Conversation
Route embedded telegram-bot-api startup through the managed child-process launcher, add explicit ExternalLocalBotApiBaseUrl support for external local API usage, and consume child process output so startup no longer breaks on spaced paths or silent process failures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📝 WalkthroughWalkthroughThis PR adds support for external Local Bot API endpoints by introducing a new Changes
Sequence DiagramsequenceDiagram
participant Config as Configuration
participant Env as Env.ResolveBotApiEndpoint
participant Bootstrap as Bootstrap.Startup
participant EmbeddedMode as Embedded Mode
participant ExternalMode as External Mode
participant TCPWaiter as WaitForTcpServiceReady
participant Service as Bot API Service
Config->>Env: Load settings (EnableLocalBotAPI, ExternalLocalBotApiBaseUrl)
Env->>Env: Determine endpoint mode
alt EnableLocalBotAPI == true
Env->>EmbeddedMode: Resolve to embedded local mode
EmbeddedMode->>Bootstrap: Return http://127.0.0.1:{port}
Bootstrap->>EmbeddedMode: StartEmbeddedLocalBotApiAsync()
EmbeddedMode->>Service: Fork telegram-bot-api.exe process
Service->>TCPWaiter: Process started
TCPWaiter->>Service: Poll TCP port
Service->>TCPWaiter: Port becomes available
else ExternalLocalBotApiBaseUrl provided
Env->>ExternalMode: Resolve to external local mode
ExternalMode->>Bootstrap: Return ExternalLocalBotApiBaseUrl
Bootstrap->>ExternalMode: WaitForExternalLocalBotApiIfNeededAsync()
ExternalMode->>TCPWaiter: Wait for external service port
Service->>TCPWaiter: External service ready on port
else Default
Env->>Bootstrap: Resolve to cloud API (api.telegram.org)
Bootstrap->>Bootstrap: Skip local API startup
end
Bootstrap->>Bootstrap: Startup complete
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 PR检查报告📋 检查概览
🧪 测试结果
📊 代码质量
📁 测试产物
🔗 相关链接此报告由GitHub Actions自动生成 |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Docs/Architecture_Overview.md (1)
131-136:⚠️ Potential issue | 🟡 MinorAlign the config-management section with
Config.json.This PR adds a persistent
Config.jsonoption, but this section still points users atappsettings.json/environment/database config. Please update it to mention%LOCALAPPDATA%/TelegramSearchBot/Config.jsonas the source of these runtime settings. As per coding guidelines,**/Env.cs: Load configuration from%LOCALAPPDATA%/TelegramSearchBot/Config.jsonvia Env.cs, not from appsettings.json.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Docs/Architecture_Overview.md` around lines 131 - 136, Update the "配置管理" section to document the new persistent runtime config file: mention that runtime settings are loaded from %LOCALAPPDATA%/TelegramSearchBot/Config.json (Config.json) rather than appsettings.json or env/database sources, and state that Env.cs implements this load path (i.e., Env.cs reads %LOCALAPPDATA%/TelegramSearchBot/Config.json to populate runtime configuration); remove or de-emphasize appsettings.json as the primary runtime source and note appsettings.json/environment/database remain secondary/legacy where applicable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Docs/Architecture_Overview.md`:
- Around line 272-273: Update the document footer to reflect the new change by
replacing the existing footer fields "*最后更新: 2026-03-26*" and "*文档版本: 1.1*" with
the current last-updated date and new document version (e.g., update the date
and bump the version string accordingly) so the footer matches the new external
Local Bot API mode changes.
In `@TelegramSearchBot.Common/Env.cs`:
- Around line 72-76: The current branch that returns a new
BotApiEndpointSettings when normalizedExternalLocalBotApiBaseUrl is non-empty
incorrectly forces IsLocalApi=true for any string; update the guard in the code
that checks normalizedExternalLocalBotApiBaseUrl so it first parses and
validates it as an absolute URI with scheme http or https and, if this option is
intended to be local-only, also require the host is loopback/localhost (or an IP
in 127.0.0.0/8). Only if the URI validation passes should you construct and
return new BotApiEndpointSettings(normalizedExternalLocalBotApiBaseUrl, true,
normalizedExternalLocalBotApiBaseUrl); otherwise treat it as invalid (skip local
mode and/or throw/log an error).
In `@TelegramSearchBot/AppBootstrap/AppBootstrap.cs`:
- Around line 201-204: The process display name currently includes raw
command-line arguments (see Fork and the StartManagedProcess call), which leaks
secrets like --api-hash into logs; change the display name construction so it
does not include full args: either omit args entirely (use only exePath) or
build a redactedArgs string that replaces sensitive values for known flags (e.g.
--api-hash=, --token=, --password=) with a placeholder like "<REDACTED>" or show
only arg names without values, then pass that safe display string into
StartManagedProcess/StartManagedProcess logging; update the Fork method (and the
similar code between lines 246–278) to use this redaction logic and ensure
CreateManagedStartInfo remains unchanged.
In `@TelegramSearchBot/AppBootstrap/GeneralBootstrap.cs`:
- Around line 75-85: The StartEmbeddedLocalBotApiAsync method currently returns
silently when required pieces are missing; instead fail fast so configuration
errors are visible: when Env.EnableLocalBotAPI is true and the bot API
executable is missing (botApiExePath) or TelegramBotApiId/TelegramBotApiHash are
not configured, throw a clear exception (e.g., InvalidOperationException) with a
descriptive message rather than returning; update StartEmbeddedLocalBotApiAsync
to validate Env.EnableLocalBotAPI/Env.BaseUrl and then raise on these missing
prerequisites so callers (and startup) fail immediately and do not continue with
an unstarted embedded API.
- Around line 47-64: WaitForTcpServiceReady currently logs and returns on
dependency process exit or timeout which lets startup continue with missing
services; change it to fail-fast by throwing exceptions instead of returning:
when the optional Process has exited, log and then throw an
InvalidOperationException including serviceName and process.ExitCode; when
maxRetries elapse, log and then throw a TimeoutException including serviceName,
host and port. Update the method (WaitForTcpServiceReady) to preserve the
existing log messages but throw the appropriate exceptions so callers cannot
continue with unavailable TCP dependencies.
---
Outside diff comments:
In `@Docs/Architecture_Overview.md`:
- Around line 131-136: Update the "配置管理" section to document the new persistent
runtime config file: mention that runtime settings are loaded from
%LOCALAPPDATA%/TelegramSearchBot/Config.json (Config.json) rather than
appsettings.json or env/database sources, and state that Env.cs implements this
load path (i.e., Env.cs reads %LOCALAPPDATA%/TelegramSearchBot/Config.json to
populate runtime configuration); remove or de-emphasize appsettings.json as the
primary runtime source and note appsettings.json/environment/database remain
secondary/legacy where applicable.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e81169c2-1e6b-4ffa-8bf3-acae2ab50d73
📒 Files selected for processing (7)
Docs/Architecture_Overview.mdDocs/README_MCP.mdREADME.mdTelegramSearchBot.Common/Env.csTelegramSearchBot.Test/Common/EnvBotApiEndpointTests.csTelegramSearchBot/AppBootstrap/AppBootstrap.csTelegramSearchBot/AppBootstrap/GeneralBootstrap.cs
| *最后更新: 2026-03-26* | ||
| *文档版本: 1.1* No newline at end of file | ||
| *文档版本: 1.1* |
There was a problem hiding this comment.
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
-*最后更新: 2026-03-26*
-*文档版本: 1.1*
+*最后更新: 2026-04-21*
+*文档版本: 1.2*📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| *最后更新: 2026-03-26* | |
| *文档版本: 1.1* | |
| \ No newline at end of file | |
| *文档版本: 1.1* | |
| *最后更新: 2026-04-21* | |
| *文档版本: 1.2* |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Docs/Architecture_Overview.md` around lines 272 - 273, Update the document
footer to reflect the new change by replacing the existing footer fields "*最后更新:
2026-03-26*" and "*文档版本: 1.1*" with the current last-updated date and new
document version (e.g., update the date and bump the version string accordingly)
so the footer matches the new external Local Bot API mode changes.
| if (!string.IsNullOrWhiteSpace(normalizedExternalLocalBotApiBaseUrl)) { | ||
| return new BotApiEndpointSettings( | ||
| normalizedExternalLocalBotApiBaseUrl, | ||
| true, | ||
| normalizedExternalLocalBotApiBaseUrl); |
There was a problem hiding this comment.
Validate ExternalLocalBotApiBaseUrl before forcing local API mode.
Any non-empty value currently sets IsLocalApi=true, including malformed URLs or non-local hosts. That can leave startup checks skipped later and may make the Telegram client treat a remote endpoint as a trusted local Bot API. Please require an absolute http/https URI and, if this option is intended to be local-only, enforce loopback/localhost here.
🛡️ 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
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!string.IsNullOrWhiteSpace(normalizedExternalLocalBotApiBaseUrl)) { | |
| return new BotApiEndpointSettings( | |
| normalizedExternalLocalBotApiBaseUrl, | |
| true, | |
| 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, | |
| normalizedExternalLocalBotApiBaseUrl); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@TelegramSearchBot.Common/Env.cs` around lines 72 - 76, The current branch
that returns a new BotApiEndpointSettings when
normalizedExternalLocalBotApiBaseUrl is non-empty incorrectly forces
IsLocalApi=true for any string; update the guard in the code that checks
normalizedExternalLocalBotApiBaseUrl so it first parses and validates it as an
absolute URI with scheme http or https and, if this option is intended to be
local-only, also require the host is loopback/localhost (or an IP in
127.0.0.0/8). Only if the URI validation passes should you construct and return
new BotApiEndpointSettings(normalizedExternalLocalBotApiBaseUrl, true,
normalizedExternalLocalBotApiBaseUrl); otherwise treat it as invalid (skip local
mode and/or throw/log an error).
| public static Process Fork(string exePath, string[] args, long? processMemoryLimitBytes = null) { | ||
| // 将参数数组转换为空格分隔的字符串,并正确处理包含空格的参数 | ||
| string arguments = string.Join(" ", args.Select(arg => $"{arg}")); | ||
|
|
||
| // 启动新的进程(自己) | ||
| ProcessStartInfo startInfo = new ProcessStartInfo { | ||
| FileName = exePath, | ||
| Arguments = arguments, | ||
| UseShellExecute = false, | ||
| RedirectStandardOutput = true, | ||
| RedirectStandardError = true | ||
| }; | ||
|
|
||
| var newProcess = Process.Start(startInfo); | ||
| if (newProcess == null) { | ||
| throw new Exception("启动新进程失败"); | ||
| } | ||
| childProcessManager.AddProcess(newProcess, processMemoryLimitBytes); | ||
| Log.Logger.Information($"进程:{exePath} {string.Join(" ", args)}已启动"); | ||
| return newProcess; | ||
| var workingDirectory = Path.GetDirectoryName(exePath); | ||
| var startInfo = CreateManagedStartInfo(exePath, args, string.IsNullOrWhiteSpace(workingDirectory) ? Environment.CurrentDirectory : workingDirectory); | ||
| return StartManagedProcess(startInfo, $"进程:{exePath} {string.Join(" ", args)}", processMemoryLimitBytes); |
There was a problem hiding this comment.
Avoid logging raw child-process arguments.
processDisplayName includes every argument and is logged on startup plus every stdout/stderr line. GeneralBootstrap passes --api-hash={Env.TelegramBotApiHash} into this overload, so the Telegram API hash will be written to logs.
🔒 Proposed safer display name
public static Process Fork(string exePath, string[] args, long? processMemoryLimitBytes = null) {
var workingDirectory = Path.GetDirectoryName(exePath);
var startInfo = CreateManagedStartInfo(exePath, args, string.IsNullOrWhiteSpace(workingDirectory) ? Environment.CurrentDirectory : workingDirectory);
- return StartManagedProcess(startInfo, $"进程:{exePath} {string.Join(" ", args)}", processMemoryLimitBytes);
+ return StartManagedProcess(startInfo, $"进程:{exePath}", processMemoryLimitBytes);
}If argument visibility is needed, log only a redacted list.
Also applies to: 246-278
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@TelegramSearchBot/AppBootstrap/AppBootstrap.cs` around lines 201 - 204, The
process display name currently includes raw command-line arguments (see Fork and
the StartManagedProcess call), which leaks secrets like --api-hash into logs;
change the display name construction so it does not include full args: either
omit args entirely (use only exePath) or build a redactedArgs string that
replaces sensitive values for known flags (e.g. --api-hash=, --token=,
--password=) with a placeholder like "<REDACTED>" or show only arg names without
values, then pass that safe display string into
StartManagedProcess/StartManagedProcess logging; update the Fork method (and the
similar code between lines 246–278) to use this redaction logic and ensure
CreateManagedStartInfo remains unchanged.
| private static async Task WaitForTcpServiceReady(string host, int port, string serviceName, Process? process = null, int maxRetries = 20, int delayMs = 500) { | ||
| for (int i = 0; i < maxRetries; i++) { | ||
| try { | ||
| using var tcp = new System.Net.Sockets.TcpClient(); | ||
| await tcp.ConnectAsync("127.0.0.1", port); | ||
| Log.Information("Garnet 服务已就绪 (端口 {Port}),耗时约 {ElapsedMs}ms", port, i * delayMs); | ||
| if (process is { HasExited: true }) { | ||
| Log.Warning("{ServiceName} 进程在端口就绪前退出,退出码 {ExitCode}", serviceName, process.ExitCode); | ||
| return; | ||
| } catch { | ||
| await Task.Delay(delayMs); | ||
| } | ||
| } | ||
| Log.Warning("等待 Garnet 服务就绪超时 (端口 {Port}),将继续启动(Redis 连接会自动重试)", port); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// 等待本地 telegram-bot-api 服务端口就绪,最多等待 20 秒 | ||
| /// </summary> | ||
| private static async Task WaitForLocalBotApiReady(int port, int maxRetries = 40, int delayMs = 500) { | ||
| for (int i = 0; i < maxRetries; i++) { | ||
| try { | ||
| using var tcp = new System.Net.Sockets.TcpClient(); | ||
| await tcp.ConnectAsync("127.0.0.1", port); | ||
| Log.Information("telegram-bot-api 服务已就绪 (端口 {Port}),耗时约 {ElapsedMs}ms", port, i * delayMs); | ||
| await tcp.ConnectAsync(host, port); | ||
| Log.Information("{ServiceName} 服务已就绪 ({Host}:{Port}),耗时约 {ElapsedMs}ms", serviceName, host, port, i * delayMs); | ||
| return; | ||
| } catch { | ||
| await Task.Delay(delayMs); | ||
| } | ||
| } | ||
| Log.Warning("等待 telegram-bot-api 服务就绪超时 (端口 {Port}),将继续启动", port); | ||
| Log.Warning("等待 {ServiceName} 服务就绪超时 ({Host}:{Port}),将继续启动", serviceName, host, port); | ||
| } |
There was a problem hiding this comment.
Fail startup when a required TCP dependency exits or never becomes ready.
This helper logs and returns on process exit/timeout, so callers continue with Garnet or Local Bot API unavailable. For the scheduler path, that turns a deterministic startup failure into later Redis errors; for local Bot API mode, Telegram calls will hit a dead endpoint.
🛠️ Proposed fail-fast behavior
if (process is { HasExited: true }) {
Log.Warning("{ServiceName} 进程在端口就绪前退出,退出码 {ExitCode}", serviceName, process.ExitCode);
- return;
+ throw new InvalidOperationException($"{serviceName} exited before {host}:{port} became ready.");
}
@@
- Log.Warning("等待 {ServiceName} 服务就绪超时 ({Host}:{Port}),将继续启动", serviceName, host, port);
+ throw new TimeoutException($"Timed out waiting for {serviceName} at {host}:{port}.");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private static async Task WaitForTcpServiceReady(string host, int port, string serviceName, Process? process = null, int maxRetries = 20, int delayMs = 500) { | |
| for (int i = 0; i < maxRetries; i++) { | |
| try { | |
| using var tcp = new System.Net.Sockets.TcpClient(); | |
| await tcp.ConnectAsync("127.0.0.1", port); | |
| Log.Information("Garnet 服务已就绪 (端口 {Port}),耗时约 {ElapsedMs}ms", port, i * delayMs); | |
| if (process is { HasExited: true }) { | |
| Log.Warning("{ServiceName} 进程在端口就绪前退出,退出码 {ExitCode}", serviceName, process.ExitCode); | |
| return; | |
| } catch { | |
| await Task.Delay(delayMs); | |
| } | |
| } | |
| Log.Warning("等待 Garnet 服务就绪超时 (端口 {Port}),将继续启动(Redis 连接会自动重试)", port); | |
| } | |
| /// <summary> | |
| /// 等待本地 telegram-bot-api 服务端口就绪,最多等待 20 秒 | |
| /// </summary> | |
| private static async Task WaitForLocalBotApiReady(int port, int maxRetries = 40, int delayMs = 500) { | |
| for (int i = 0; i < maxRetries; i++) { | |
| try { | |
| using var tcp = new System.Net.Sockets.TcpClient(); | |
| await tcp.ConnectAsync("127.0.0.1", port); | |
| Log.Information("telegram-bot-api 服务已就绪 (端口 {Port}),耗时约 {ElapsedMs}ms", port, i * delayMs); | |
| await tcp.ConnectAsync(host, port); | |
| Log.Information("{ServiceName} 服务已就绪 ({Host}:{Port}),耗时约 {ElapsedMs}ms", serviceName, host, port, i * delayMs); | |
| return; | |
| } catch { | |
| await Task.Delay(delayMs); | |
| } | |
| } | |
| Log.Warning("等待 telegram-bot-api 服务就绪超时 (端口 {Port}),将继续启动", port); | |
| Log.Warning("等待 {ServiceName} 服务就绪超时 ({Host}:{Port}),将继续启动", serviceName, host, port); | |
| } | |
| private static async Task WaitForTcpServiceReady(string host, int port, string serviceName, Process? process = null, int maxRetries = 20, int delayMs = 500) { | |
| for (int i = 0; i < maxRetries; i++) { | |
| if (process is { HasExited: true }) { | |
| Log.Warning("{ServiceName} 进程在端口就绪前退出,退出码 {ExitCode}", serviceName, process.ExitCode); | |
| throw new InvalidOperationException($"{serviceName} exited before {host}:{port} became ready."); | |
| } | |
| try { | |
| using var tcp = new System.Net.Sockets.TcpClient(); | |
| await tcp.ConnectAsync(host, port); | |
| Log.Information("{ServiceName} 服务已就绪 ({Host}:{Port}),耗时约 {ElapsedMs}ms", serviceName, host, port, i * delayMs); | |
| return; | |
| } catch { | |
| await Task.Delay(delayMs); | |
| } | |
| } | |
| throw new TimeoutException($"Timed out waiting for {serviceName} at {host}:{port}."); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@TelegramSearchBot/AppBootstrap/GeneralBootstrap.cs` around lines 47 - 64,
WaitForTcpServiceReady currently logs and returns on dependency process exit or
timeout which lets startup continue with missing services; change it to
fail-fast by throwing exceptions instead of returning: when the optional Process
has exited, log and then throw an InvalidOperationException including
serviceName and process.ExitCode; when maxRetries elapse, log and then throw a
TimeoutException including serviceName, host and port. Update the method
(WaitForTcpServiceReady) to preserve the existing log messages but throw the
appropriate exceptions so callers cannot continue with unavailable TCP
dependencies.
| private static async Task StartEmbeddedLocalBotApiAsync() { | ||
| string botApiExePath = Path.Combine(AppContext.BaseDirectory, "telegram-bot-api.exe"); | ||
| if (!File.Exists(botApiExePath)) { | ||
| Log.Warning("未找到 telegram-bot-api 可执行文件 {Path},跳过内置本地 Bot API 启动", botApiExePath); | ||
| return; | ||
| } | ||
|
|
||
| if (string.IsNullOrWhiteSpace(Env.TelegramBotApiId) || string.IsNullOrWhiteSpace(Env.TelegramBotApiHash)) { | ||
| Log.Warning("EnableLocalBotAPI 为 true,但 TelegramBotApiId 或 TelegramBotApiHash 未配置,跳过内置本地 Bot API 启动"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Don’t silently skip embedded Local Bot API when it is enabled.
With Env.EnableLocalBotAPI=true, Env.BaseUrl already points to the embedded local endpoint. Returning here leaves the bot configured for an API server that was never started; fail fast instead so the misconfiguration is visible.
🛠️ Proposed fail-fast checks
if (!File.Exists(botApiExePath)) {
- Log.Warning("未找到 telegram-bot-api 可执行文件 {Path},跳过内置本地 Bot API 启动", botApiExePath);
- return;
+ throw new FileNotFoundException("EnableLocalBotAPI is true but telegram-bot-api executable was not found.", botApiExePath);
}
if (string.IsNullOrWhiteSpace(Env.TelegramBotApiId) || string.IsNullOrWhiteSpace(Env.TelegramBotApiHash)) {
- Log.Warning("EnableLocalBotAPI 为 true,但 TelegramBotApiId 或 TelegramBotApiHash 未配置,跳过内置本地 Bot API 启动");
- return;
+ throw new InvalidOperationException("EnableLocalBotAPI is true but TelegramBotApiId or TelegramBotApiHash is not configured.");
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private static async Task StartEmbeddedLocalBotApiAsync() { | |
| string botApiExePath = Path.Combine(AppContext.BaseDirectory, "telegram-bot-api.exe"); | |
| if (!File.Exists(botApiExePath)) { | |
| Log.Warning("未找到 telegram-bot-api 可执行文件 {Path},跳过内置本地 Bot API 启动", botApiExePath); | |
| return; | |
| } | |
| if (string.IsNullOrWhiteSpace(Env.TelegramBotApiId) || string.IsNullOrWhiteSpace(Env.TelegramBotApiHash)) { | |
| Log.Warning("EnableLocalBotAPI 为 true,但 TelegramBotApiId 或 TelegramBotApiHash 未配置,跳过内置本地 Bot API 启动"); | |
| return; | |
| } | |
| private static async Task StartEmbeddedLocalBotApiAsync() { | |
| string botApiExePath = Path.Combine(AppContext.BaseDirectory, "telegram-bot-api.exe"); | |
| if (!File.Exists(botApiExePath)) { | |
| throw new FileNotFoundException("EnableLocalBotAPI is true but telegram-bot-api executable was not found.", botApiExePath); | |
| } | |
| if (string.IsNullOrWhiteSpace(Env.TelegramBotApiId) || string.IsNullOrWhiteSpace(Env.TelegramBotApiHash)) { | |
| throw new InvalidOperationException("EnableLocalBotAPI is true but TelegramBotApiId or TelegramBotApiHash is not configured."); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@TelegramSearchBot/AppBootstrap/GeneralBootstrap.cs` around lines 75 - 85, The
StartEmbeddedLocalBotApiAsync method currently returns silently when required
pieces are missing; instead fail fast so configuration errors are visible: when
Env.EnableLocalBotAPI is true and the bot API executable is missing
(botApiExePath) or TelegramBotApiId/TelegramBotApiHash are not configured, throw
a clear exception (e.g., InvalidOperationException) with a descriptive message
rather than returning; update StartEmbeddedLocalBotApiAsync to validate
Env.EnableLocalBotAPI/Env.BaseUrl and then raise on these missing prerequisites
so callers (and startup) fail immediately and do not continue with an unstarted
embedded API.
Summary
Why
The embedded Local Bot API path was not using the same managed startup flow as other child processes, which made startup fragile and prevented consistent Job Object-based lifetime handling. On top of that, configuration did not expose a clean way to use an already-running external Local Bot API instance.
Validation
Summary by CodeRabbit
New Features
ExternalLocalBotApiBaseUrlsettingDocumentation
Tests