Files
better-genshin-impact/BetterGenshinImpact/Service/Notifier/TelegramNotifier.cs
DR-lin-eng a662791b6b Tgbot推送机器人 (#1296)
* feat: add email and websocket notification

* fix typos.

* refactor(notifiers): 重构邮件和 WebSocket 通知器

- 提升 EmailNotifier 中的 SmtpClient 为类的成员变量,并在构造函数中初始化,优化资源使用
- 改进 WebSocketNotifier 的连接和重连逻辑,提高稳定性
- 优化通知器的错误处理和日志记录,增强可维护性

* Create BarkNotifier.cs

* Update NotificationConfig.cs

* Update NotificationService.cs

* Update CommonSettingsPageViewModel.cs

* Add files via upload

* Add files via upload

* Add files via upload

* Update CommonSettingsPage.xaml

* Delete BetterGenshinImpact/Service/Notifier/BarkNotifier.cs

* Add files via upload

* Update BarkNotifier.cs

* Update NotificationService.cs

* Update CommonSettingsPageViewModel.cs

* Update CommonSettingsPage.xaml

* Delete BetterGenshinImpact/Service/BarkNotifier.cs

* Add files via upload

* Add files via upload

* Add files via upload

* Update CommonSettingsPage.xaml

* fix: 回退部分代码,修复了程序崩溃的错误

* fix: remove api.day.app

* Update CommonSettingsPageViewModel.cs

* Update CommonSettingsPage.xaml

* Update CommonSettingsPage.xaml

* Update CommonSettingsPageViewModel.cs

* Update EmailNotifier.cs

* Update EmailNotifier.cs

* Update BarkNotifier.cs

* 修正并更新前端介绍

* Revert "1"

* 修正公益服务器请求兼容性

* Revert "Revert "1""

This reverts commit 8c6effb1

* 新增tg推送但是有发送问题?(疑似我的电脑问题,稍后解决)

Signed-off-by: DR-lin-eng <@DR-lin-eng>

* feat: Telegram notification and ui.

* 修正tgbot推送,修正变量

Signed-off-by: DR-lin-eng <@DR-lin-eng>

---------

Signed-off-by: DR-lin-eng <@DR-lin-eng>
Co-authored-by: 秋云 <physligl@gmail.com>
Co-authored-by: 禹仔二号 <87601913+wy3057@users.noreply.github.com>
Co-authored-by: yuzai <3020834774@qq.com>
Co-authored-by: DR-lin-eng <@DR-lin-eng>
Co-authored-by: 辉鸭蛋 <huiyadanli@gmail.com>
2025-03-14 19:39:16 +08:00

226 lines
7.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using BetterGenshinImpact.Service.Notification.Model;
using BetterGenshinImpact.Service.Notifier.Exception;
using BetterGenshinImpact.Service.Notifier.Interface;
namespace BetterGenshinImpact.Service.Notifier;
public class TelegramNotifier : INotifier, IDisposable
{
// 永远不更改此URL常量这是Telegram API的标准URL前缀
private const string TELEGRAM_API_URL = "https://api.telegram.org/bot";
private readonly bool _createdHttpClient;
private readonly HttpClient _httpClient;
private readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};
/// <summary>
/// 创建一个新的Telegram通知器实例
/// </summary>
/// <param name="httpClient">可选的HttpClient如果不提供则创建新的</param>
/// <param name="telegramBotToken">Telegram机器人Token</param>
/// <param name="telegramChatId">Telegram聊天ID</param>
/// <param name="telegramApiBaseUrl">不再使用,保留参数仅为兼容性</param>
public TelegramNotifier(HttpClient httpClient = null, string telegramBotToken = "", string telegramChatId = "",
string telegramApiBaseUrl = "")
{
TelegramBotToken = telegramBotToken;
TelegramChatId = telegramChatId;
if (httpClient != null)
{
_httpClient = httpClient;
_createdHttpClient = false;
}
else
{
_httpClient = new HttpClient();
_createdHttpClient = true;
_httpClient.Timeout = TimeSpan.FromSeconds(30);
}
// 忽略自定义API URL始终使用标准Telegram API URL
TelegramApiBaseUrl = TELEGRAM_API_URL;
}
/// <summary>
/// Telegram机器人Token
/// </summary>
public string TelegramBotToken { get; set; }
/// <summary>
/// Telegram聊天ID
/// </summary>
public string TelegramChatId { get; set; }
/// <summary>
/// Telegram API基础URL - 内部使用
/// </summary>
private string TelegramApiBaseUrl { get; set; }
public void Dispose()
{
if (_createdHttpClient)
{
_httpClient?.Dispose();
}
}
/// <summary>
/// 通知器名称
/// </summary>
public string Name { get; set; } = "Telegram";
public async Task SendAsync(BaseNotificationData content)
{
if (string.IsNullOrEmpty(TelegramBotToken))
{
throw new NotifierException("Telegram bot token is not set");
}
if (string.IsNullOrEmpty(TelegramChatId))
{
throw new NotifierException("Telegram chat ID is not set");
}
try
{
var message = content.Message;
var fullMessage = !string.IsNullOrEmpty(message) ? message : "";
if (!string.IsNullOrEmpty(fullMessage))
{
await SendTextMessageAsync(fullMessage);
}
else
{
throw new NotifierException("No message content to send");
}
}
catch (HttpRequestException ex)
{
throw new NotifierException("Network error sending Telegram notification: " + ex.Message);
}
catch (TaskCanceledException)
{
throw new NotifierException("Telegram API request timed out. Check your internet connection.");
}
catch (NotifierException)
{
throw;
}
catch (System.Exception ex)
{
throw new NotifierException("Error sending Telegram notification: " + ex.Message);
}
}
private async Task SendTextMessageAsync(string message)
{
// 构建Telegram API URL - 固定格式https://api.telegram.org/bot{token}/sendMessage
var endpoint = $"{TELEGRAM_API_URL}{TelegramBotToken}/sendMessage";
try
{
var jsonContent = new
{
chat_id = TelegramChatId,
text = message,
disable_web_page_preview = true
};
var json = JsonSerializer.Serialize(jsonContent, _jsonSerializerOptions);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(HttpMethod.Post, endpoint)
{
Content = content
};
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.UserAgent.Add(new ProductInfoHeaderValue("BetterGenshinImpact", "1.0"));
var response = await _httpClient.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new NotifierException(
$"Telegram message failed with code: {response.StatusCode}, Error: {responseContent}");
}
// Check for API errors in the response
var (isSuccess, errorCode, errorDescription) = ValidateApiResponse(responseContent);
if (!isSuccess)
{
if (errorCode == 400)
{
throw new NotifierException(
"Please send a message to the bot first and check that the chat ID is correct.");
}
if (errorCode == 401)
{
throw new NotifierException("Telegram bot token is incorrect.");
}
if (errorCode == 404)
throw new NotifierException(
$"Telegram API not found (404). Please verify your bot token is correct. URL: {endpoint}");
throw new NotifierException($"Telegram API error: {errorDescription} (Code: {errorCode})");
}
}
catch (System.Exception ex) when (!(ex is NotifierException))
{
throw new NotifierException("Error sending Telegram notification: " + ex.Message);
}
}
private (bool isSuccess, int errorCode, string errorDescription) ValidateApiResponse(string responseJson)
{
try
{
using (var doc = JsonDocument.Parse(responseJson))
{
var root = doc.RootElement;
// Telegram API returns "ok": true for success
if (root.TryGetProperty("ok", out var okElement))
{
var isOk = okElement.GetBoolean();
if (!isOk)
{
var errorDescription = "Unknown Telegram API error";
if (root.TryGetProperty("description", out var descriptionElement))
errorDescription = descriptionElement.GetString();
var errorCode = 0;
if (root.TryGetProperty("error_code", out var errorCodeElement))
errorCode = errorCodeElement.GetInt32();
return (false, errorCode, errorDescription);
}
return (true, 0, string.Empty);
}
return (false, 0, "Invalid API response: 'ok' field missing");
}
}
catch (JsonException ex)
{
return (false, 0, "Failed to parse API response: " + ex.Message);
}
}
}