mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-21 09:45:48 +08:00
* 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>
226 lines
7.5 KiB
C#
226 lines
7.5 KiB
C#
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);
|
||
}
|
||
}
|
||
} |