diff --git a/src/TelegramPanel.Core/Interfaces/ITelegramClientPool.cs b/src/TelegramPanel.Core/Interfaces/ITelegramClientPool.cs index 193af86..081d801 100644 --- a/src/TelegramPanel.Core/Interfaces/ITelegramClientPool.cs +++ b/src/TelegramPanel.Core/Interfaces/ITelegramClientPool.cs @@ -11,7 +11,14 @@ public interface ITelegramClientPool /// /// 获取或创建指定账号的客户端 /// - Task GetOrCreateClientAsync(int accountId, int apiId, string apiHash, string sessionPath, string? phoneNumber = null, long? userId = null); + Task GetOrCreateClientAsync( + int accountId, + int apiId, + string apiHash, + string sessionPath, + string? sessionKey = null, + string? phoneNumber = null, + long? userId = null); /// /// 获取已存在的客户端 diff --git a/src/TelegramPanel.Core/Services/Telegram/AccountService.cs b/src/TelegramPanel.Core/Services/Telegram/AccountService.cs index a7c0aec..f5281ab 100644 --- a/src/TelegramPanel.Core/Services/Telegram/AccountService.cs +++ b/src/TelegramPanel.Core/Services/Telegram/AccountService.cs @@ -44,7 +44,7 @@ public class AccountService : IAccountService _logger.LogInformation("Starting login for phone {Phone}", phone); - var client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, phoneNumber: phone, userId: null); + var client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, sessionKey: apiHash, phoneNumber: phone, userId: null); string result; try @@ -57,7 +57,7 @@ public class AccountService : IAccountService TryBackupCorruptedSessionIfExists(sessionPath); await _clientPool.RemoveClientAsync(accountId); - client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, phoneNumber: phone, userId: null); + client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, sessionKey: apiHash, phoneNumber: phone, userId: null); result = await client.Login(phone); } diff --git a/src/TelegramPanel.Core/Services/Telegram/ChannelService.cs b/src/TelegramPanel.Core/Services/Telegram/ChannelService.cs index e8b5261..5294d40 100644 --- a/src/TelegramPanel.Core/Services/Telegram/ChannelService.cs +++ b/src/TelegramPanel.Core/Services/Telegram/ChannelService.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; using TelegramPanel.Core.Interfaces; using TelegramPanel.Core.Models; using TelegramPanel.Core.Services; @@ -14,15 +15,18 @@ public class ChannelService : IChannelService { private readonly ITelegramClientPool _clientPool; private readonly AccountManagementService _accountManagement; + private readonly IConfiguration _configuration; private readonly ILogger _logger; public ChannelService( ITelegramClientPool clientPool, AccountManagementService accountManagement, + IConfiguration configuration, ILogger logger) { _clientPool = clientPool; _accountManagement = accountManagement; + _configuration = configuration; _logger = logger; } @@ -81,11 +85,23 @@ public class ChannelService : IChannelService _logger.LogInformation("Creating channel '{Title}' for account {AccountId}", title, accountId); - var updates = await client.Channels_CreateChannel( - title: title, - about: about, - broadcast: true // true=频道, false=超级群组 - ); + UpdatesBase updates; + try + { + updates = await client.Channels_CreateChannel( + title: title, + about: about, + broadcast: true // true=频道, false=超级群组 + ); + } + catch (RpcException ex) when (ex.Code == 420 && string.Equals(ex.Message, "FROZEN_METHOD_INVALID", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException( + "Telegram 返回 FROZEN_METHOD_INVALID:当前 ApiId/ApiHash 或账号被 Telegram 限制调用创建频道接口。" + + "建议:在【系统设置】更换全局 ApiId/ApiHash(推荐使用你自己在 my.telegram.org 申请的)," + + "并重新导入/重新登录生成 session 后再试。", + ex); + } var channel = updates.Chats.Values.OfType().FirstOrDefault() ?? throw new InvalidOperationException("Channel creation failed"); @@ -249,8 +265,9 @@ public class ChannelService : IChannelService var account = await _accountManagement.GetAccountAsync(accountId) ?? throw new InvalidOperationException($"账号不存在:{accountId}"); - if (account.ApiId <= 0 || string.IsNullOrWhiteSpace(account.ApiHash)) - throw new InvalidOperationException("账号缺少 ApiId/ApiHash,无法创建 Telegram 客户端"); + var apiId = ResolveApiId(account); + var apiHash = ResolveApiHash(account); + var sessionKey = ResolveSessionKey(account, apiHash); if (string.IsNullOrWhiteSpace(account.SessionPath)) throw new InvalidOperationException("账号缺少 SessionPath,无法创建 Telegram 客户端"); @@ -276,7 +293,7 @@ public class ChannelService : IChannelService } await _clientPool.RemoveClientAsync(accountId); - var client = await _clientPool.GetOrCreateClientAsync(accountId, account.ApiId, account.ApiHash, account.SessionPath, account.Phone, account.UserId); + var client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, account.SessionPath, sessionKey, account.Phone, account.UserId); try { @@ -303,6 +320,32 @@ public class ChannelService : IChannelService return client; } + private int ResolveApiId(TelegramPanel.Data.Entities.Account account) + { + if (int.TryParse(_configuration["Telegram:ApiId"], out var globalApiId) && globalApiId > 0) + return globalApiId; + if (account.ApiId > 0) + return account.ApiId; + throw new InvalidOperationException("未配置全局 ApiId,且账号缺少 ApiId"); + } + + private string ResolveApiHash(TelegramPanel.Data.Entities.Account account) + { + var global = _configuration["Telegram:ApiHash"]; + if (!string.IsNullOrWhiteSpace(global)) + return global.Trim(); + if (!string.IsNullOrWhiteSpace(account.ApiHash)) + return account.ApiHash.Trim(); + throw new InvalidOperationException("未配置全局 ApiHash,且账号缺少 ApiHash"); + } + + private static string ResolveSessionKey(TelegramPanel.Data.Entities.Account account, string apiHash) + { + // session 文件加密 key(session_key)必须与生成该 session 的 key 一致 + // 这里优先使用账号自带 ApiHash(导入时保存的),否则退回 apiHash(全局) + return !string.IsNullOrWhiteSpace(account.ApiHash) ? account.ApiHash.Trim() : apiHash.Trim(); + } + private static bool LooksLikeSessionApiMismatchOrCorrupted(Exception ex) { var msg = ex.Message ?? string.Empty; diff --git a/src/TelegramPanel.Core/Services/Telegram/GroupService.cs b/src/TelegramPanel.Core/Services/Telegram/GroupService.cs index cc30cbe..56128ae 100644 --- a/src/TelegramPanel.Core/Services/Telegram/GroupService.cs +++ b/src/TelegramPanel.Core/Services/Telegram/GroupService.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Configuration; using TelegramPanel.Core.Interfaces; using TelegramPanel.Core.Models; using TelegramPanel.Core.Services; @@ -13,15 +14,18 @@ public class GroupService : IGroupService { private readonly ITelegramClientPool _clientPool; private readonly AccountManagementService _accountManagement; + private readonly IConfiguration _configuration; private readonly ILogger _logger; public GroupService( ITelegramClientPool clientPool, AccountManagementService accountManagement, + IConfiguration configuration, ILogger logger) { _clientPool = clientPool; _accountManagement = accountManagement; + _configuration = configuration; _logger = logger; } @@ -116,8 +120,9 @@ public class GroupService : IGroupService var account = await _accountManagement.GetAccountAsync(accountId) ?? throw new InvalidOperationException($"账号不存在:{accountId}"); - if (account.ApiId <= 0 || string.IsNullOrWhiteSpace(account.ApiHash)) - throw new InvalidOperationException("账号缺少 ApiId/ApiHash,无法创建 Telegram 客户端"); + var apiId = ResolveApiId(account); + var apiHash = ResolveApiHash(account); + var sessionKey = ResolveSessionKey(account, apiHash); if (string.IsNullOrWhiteSpace(account.SessionPath)) throw new InvalidOperationException("账号缺少 SessionPath,无法创建 Telegram 客户端"); @@ -143,7 +148,7 @@ public class GroupService : IGroupService } await _clientPool.RemoveClientAsync(accountId); - var client = await _clientPool.GetOrCreateClientAsync(accountId, account.ApiId, account.ApiHash, account.SessionPath, account.Phone, account.UserId); + var client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, account.SessionPath, sessionKey, account.Phone, account.UserId); try { @@ -170,6 +175,30 @@ public class GroupService : IGroupService return client; } + private int ResolveApiId(TelegramPanel.Data.Entities.Account account) + { + if (int.TryParse(_configuration["Telegram:ApiId"], out var globalApiId) && globalApiId > 0) + return globalApiId; + if (account.ApiId > 0) + return account.ApiId; + throw new InvalidOperationException("未配置全局 ApiId,且账号缺少 ApiId"); + } + + private string ResolveApiHash(TelegramPanel.Data.Entities.Account account) + { + var global = _configuration["Telegram:ApiHash"]; + if (!string.IsNullOrWhiteSpace(global)) + return global.Trim(); + if (!string.IsNullOrWhiteSpace(account.ApiHash)) + return account.ApiHash.Trim(); + throw new InvalidOperationException("未配置全局 ApiHash,且账号缺少 ApiHash"); + } + + private static string ResolveSessionKey(TelegramPanel.Data.Entities.Account account, string apiHash) + { + return !string.IsNullOrWhiteSpace(account.ApiHash) ? account.ApiHash.Trim() : apiHash.Trim(); + } + private static bool LooksLikeSessionApiMismatchOrCorrupted(Exception ex) { var msg = ex.Message ?? string.Empty; diff --git a/src/TelegramPanel.Core/Services/Telegram/TelegramClientPool.cs b/src/TelegramPanel.Core/Services/Telegram/TelegramClientPool.cs index ad17205..f7c61f1 100644 --- a/src/TelegramPanel.Core/Services/Telegram/TelegramClientPool.cs +++ b/src/TelegramPanel.Core/Services/Telegram/TelegramClientPool.cs @@ -23,7 +23,14 @@ public class TelegramClientPool : ITelegramClientPool, IDisposable public int ActiveClientCount => _clients.Count; - public async Task GetOrCreateClientAsync(int accountId, int apiId, string apiHash, string sessionPath, string? phoneNumber = null, long? userId = null) + public async Task GetOrCreateClientAsync( + int accountId, + int apiId, + string apiHash, + string sessionPath, + string? sessionKey = null, + string? phoneNumber = null, + long? userId = null) { if (_clients.TryGetValue(accountId, out var existingClient)) { @@ -57,6 +64,7 @@ public class TelegramClientPool : ITelegramClientPool, IDisposable "api_id" => apiId.ToString(), "api_hash" => apiHash, "session_pathname" => sessionPath, + "session_key" => string.IsNullOrWhiteSpace(sessionKey) ? null! : sessionKey, "phone_number" => string.IsNullOrWhiteSpace(phoneNumber) ? null! : phoneNumber, "user_id" => userId.HasValue && userId.Value > 0 ? userId.Value.ToString() : null!, _ => null! // 使用 null! 抑制警告,这是 WTelegramClient 的预期行为