diff --git a/src/Bot/BotInstance.cs b/src/Bot/BotInstance.cs index 9aa15cb..9b02771 100644 --- a/src/Bot/BotInstance.cs +++ b/src/Bot/BotInstance.cs @@ -1,23 +1,34 @@ using DXKumaBot.Bot.Lagrange; using DXKumaBot.Bot.Telegram; +using DXKumaBot.Functions; using DXKumaBot.Utils; namespace DXKumaBot.Bot; -public sealed class BotInstance +public sealed class BotInstance(Config config) { - private readonly QQBot _qqBot = new(); - private readonly TgBot _tgBot = new(); + private readonly QqBot _qqBot = new(); + private readonly TgBot _tgBot = new(config.Telegram); - public static event AsyncEventHandler MessageReceived; + public static event AsyncEventHandler? MessageReceived; - public async Task RunAsync() + private static void RegisterFunctions() { - await Task.WhenAll(_qqBot.RunAsync(), _tgBot.RunAsync()); + LoveYou loveYou = new(); + loveYou.Register(); } - public async Task SendMessageAsync(object message) + private void RegisterEvents() + { + _qqBot.MessageReceived += MessageReceived; + _tgBot.MessageReceived += MessageReceived; + } + + public async Task RunAsync() { - throw new NotImplementedException(); + RegisterFunctions(); + RegisterEvents(); + _tgBot.Run(); + await _qqBot.RunAsync(); } } \ No newline at end of file diff --git a/src/Bot/Lagrange/OneBotSigner.cs b/src/Bot/Lagrange/CustomSignProvider.cs similarity index 76% rename from src/Bot/Lagrange/OneBotSigner.cs rename to src/Bot/Lagrange/CustomSignProvider.cs index b4c69be..503ea2a 100644 --- a/src/Bot/Lagrange/OneBotSigner.cs +++ b/src/Bot/Lagrange/CustomSignProvider.cs @@ -12,27 +12,16 @@ namespace DXKumaBot.Bot.Lagrange; -public class OneBotSigner : SignProvider +public class CustomSignProvider : SignProvider { private readonly HttpClient _client; private readonly string _signServer; private readonly Timer _timer; - public OneBotSigner() + public CustomSignProvider() { _signServer = "https://sign.lagrangecore.org/api/sign"; _client = new(); - - if (string.IsNullOrEmpty(_signServer)) - { - Available = false; - Console.WriteLine("Signature Service is not available, login may be failed"); - } - else - { - Console.WriteLine("Signature Service is successfully established"); - } - _timer = new(_ => { bool reconnect = Available = Test(); @@ -53,7 +42,7 @@ public OneBotSigner() return null; } - if (!Available || string.IsNullOrEmpty(_signServer)) + if (!Available) { return new byte[35]; // Dummy signature } @@ -81,7 +70,6 @@ public OneBotSigner() Available = false; _timer.Change(0, 5000); - Console.WriteLine("Failed to get signature, using dummy signature"); return new byte[35]; // Dummy signature } } @@ -95,13 +83,7 @@ public override bool Test() uriBuilder.Query = query.ToString(); using HttpResponseMessage response = _client.GetAsync(uriBuilder.Uri).Result; string responseStr = response.Content.ReadAsStringAsync().Result; - if (JsonSerializer.Deserialize(responseStr)?["code"]?.GetValue() is not 0) - { - return false; - } - - Console.WriteLine("Reconnected to Signature Service successfully"); - return true; + return JsonSerializer.Deserialize(responseStr)?["code"]?.GetValue() is 0; } catch { diff --git a/src/Bot/Lagrange/QQBot.cs b/src/Bot/Lagrange/QQBot.cs index 6073b15..580ea2f 100644 --- a/src/Bot/Lagrange/QQBot.cs +++ b/src/Bot/Lagrange/QQBot.cs @@ -1,4 +1,5 @@ using DXKumaBot.Bot.Message; +using DXKumaBot.Utils; using Lagrange.Core; using Lagrange.Core.Common; using Lagrange.Core.Common.Interface; @@ -9,23 +10,22 @@ namespace DXKumaBot.Bot.Lagrange; -public class QQBot : IBot +public class QqBot : IBot { private readonly BotContext _bot; private readonly BotKeystore? _keyStore; - public QQBot() + public QqBot() { BotDeviceInfo deviceInfo = GetDeviceInfo(); _keyStore = LoadKeystore(); - _bot = BotFactory.Create(new() { UseIPv6Network = false, GetOptimumServer = true, AutoReconnect = true, Protocol = Protocols.Linux, - CustomSignProvider = new OneBotSigner() + CustomSignProvider = new CustomSignProvider() }, deviceInfo, _keyStore ?? new BotKeystore()); } @@ -34,36 +34,55 @@ public async Task SendMessageAsync(MessageReceivedEventArgs messageToReply, Mess await SendMessageAsync(messageToReply.QqMessage!.Chain.GroupUin, messages); } + public event AsyncEventHandler? MessageReceived; + + private void RegisterEvents() + { + _bot.Invoker.OnBotCaptchaEvent += (_, @event) => { Console.WriteLine(@event.ToString()); }; + _bot.Invoker.OnBotOfflineEvent += (_, @event) => { Console.WriteLine(@event.ToString()); }; + _bot.Invoker.OnBotOnlineEvent += (_, @event) => { Console.WriteLine(@event.ToString()); }; + _bot.Invoker.OnBotNewDeviceVerify += (_, @event) => { Console.WriteLine(@event.ToString()); }; + _bot.Invoker.OnGroupMessageReceived += async (sender, args) => + { + if (MessageReceived is null) + { + return; + } + + await MessageReceived.Invoke(sender, new(this, args)); + }; + } + public async Task RunAsync() { + RegisterEvents(); if (_keyStore is null) { - Console.WriteLine("try fetching qr code"); (string Url, byte[] QrCode)? qrCode = await _bot.FetchQrCode(); if (qrCode is null) { - return; + throw new NotSupportedException(); } await File.WriteAllBytesAsync("qr.png", qrCode.Value.QrCode); await _bot.LoginByQrCode(); + SaveKeystore(_bot.UpdateKeystore()); + return; } - else - { - await _bot.LoginByPassword(); - } + + await _bot.LoginByPassword(); } private static BotDeviceInfo GetDeviceInfo() { - if (!File.Exists("Config/DeviceInfo.json")) + if (!File.Exists("DeviceInfo.json")) { BotDeviceInfo deviceInfo = BotDeviceInfo.GenerateInfo(); - File.WriteAllText("Config/DeviceInfo.json", JsonSerializer.Serialize(deviceInfo)); + File.WriteAllText("DeviceInfo.json", JsonSerializer.Serialize(deviceInfo)); return deviceInfo; } - string text = File.ReadAllText("Config/DeviceInfo.json"); + string text = File.ReadAllText("DeviceInfo.json"); BotDeviceInfo? info = JsonSerializer.Deserialize(text); if (info is not null) { @@ -71,31 +90,30 @@ private static BotDeviceInfo GetDeviceInfo() } info = BotDeviceInfo.GenerateInfo(); - File.WriteAllText("Config/DeviceInfo.json", JsonSerializer.Serialize(info)); - + File.WriteAllText("DeviceInfo.json", JsonSerializer.Serialize(info)); return info; } private static void SaveKeystore(BotKeystore keystore) { - File.WriteAllText("Config/Keystore.json", JsonSerializer.Serialize(keystore)); + File.WriteAllText("Keystore.json", JsonSerializer.Serialize(keystore)); } private static BotKeystore? LoadKeystore() { - if (!File.Exists("Config/Keystore.json")) + if (!File.Exists("Keystore.json")) { return null; } - string text = File.ReadAllText("Config/Keystore.json"); + string text = File.ReadAllText("Keystore.json"); return JsonSerializer.Deserialize(text, new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve }); } - public async Task SendMessageAsync(uint? id, MessagePair messages) + private async Task SendMessageAsync(uint? id, MessagePair messages) { if (id is null) { @@ -103,27 +121,27 @@ public async Task SendMessageAsync(uint? id, MessagePair messages) } MessageBuilder messageBuilder = MessageBuilder.Group((uint)id); + if (messages.Text is not null) + { + messageBuilder.Text(messages.Text); + } + if (messages.Media is not null) { - byte[] dataStream = messages.Media.Data.ToArray(); + byte[] data = await File.ReadAllBytesAsync(messages.Media.Path); switch (messages.Media.Type) { case MediaType.Audio: - messageBuilder.Record(dataStream); + messageBuilder.Record(data); break; case MediaType.Photo: - messageBuilder.Image(dataStream); + messageBuilder.Image(data); break; default: throw new ArgumentOutOfRangeException(nameof(messages)); } } - if (messages.Text is not null) - { - messageBuilder.Text(messages.Text); - } - await _bot.SendMessage(messageBuilder.Build()); } } \ No newline at end of file diff --git a/src/Bot/Message/MediaMessage.cs b/src/Bot/Message/MediaMessage.cs index 8f377d2..76fd3ed 100644 --- a/src/Bot/Message/MediaMessage.cs +++ b/src/Bot/Message/MediaMessage.cs @@ -1,10 +1,10 @@ namespace DXKumaBot.Bot.Message; -public class MediaMessage(MediaType type, MemoryStream stream) +public class MediaMessage(MediaType type, string path) { public MediaType Type { get; } = type; - public MemoryStream Data { get; } = stream; + public string Path { get; } = path; public static implicit operator MessagePair(MediaMessage message) { diff --git a/src/Bot/Message/IMessage.cs b/src/Bot/Message/MessagePair.cs similarity index 100% rename from src/Bot/Message/IMessage.cs rename to src/Bot/Message/MessagePair.cs diff --git a/src/Bot/MessageRecivedEventArgs.cs b/src/Bot/MessageRecivedEventArgs.cs index 4847673..b62a575 100644 --- a/src/Bot/MessageRecivedEventArgs.cs +++ b/src/Bot/MessageRecivedEventArgs.cs @@ -22,7 +22,7 @@ public MessageReceivedEventArgs(IBot bot, TgMessage message) public GroupMessageEvent? QqMessage { get; } public TgMessage? TgMessage { get; } - public string Text => QqMessage?.EventMessage ?? TgMessage?.Text ?? throw new NullReferenceException(); + public string Text => QqMessage?.Chain.ToPreviewText() ?? TgMessage?.Text ?? throw new NullReferenceException(); public async Task Reply(MessagePair messages) { diff --git a/src/Bot/Telegram/TgBot.cs b/src/Bot/Telegram/TgBot.cs index ea2602b..c732644 100644 --- a/src/Bot/Telegram/TgBot.cs +++ b/src/Bot/Telegram/TgBot.cs @@ -1,18 +1,16 @@ using DXKumaBot.Bot.Message; +using System.Net; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; +using File = System.IO.File; namespace DXKumaBot.Bot.Telegram; -public class TgBot : IBot +public class TgBot(TelegramConfig config) : IBot { - private readonly TelegramBotClient _bot; - - public TgBot() - { - // _bot = new TelegramBotClient(); - } + private readonly TelegramBotClient _bot = new(config.BotToken, + config.Proxy.Enabled ? new(new HttpClientHandler { Proxy = new WebProxy(config.Proxy.Url, true) }) : default); public async Task SendMessageAsync(MessageReceivedEventArgs messageToReply, MessagePair messages) { @@ -21,15 +19,33 @@ public async Task SendMessageAsync(MessageReceivedEventArgs messageToReply, Mess throw new ArgumentNullException(nameof(messageToReply)); } - await SendMessageAsync(messageToReply.TgMessage.MessageId, messages); + await SendMessageAsync(messageToReply.TgMessage.Chat.Id, messages); } - public async Task RunAsync() + public event Utils.AsyncEventHandler? MessageReceived; + + public void Run() { - throw new NotImplementedException(); + _bot.StartReceiving(async (bot, update, _) => + { + if (update is not + { + Type: UpdateType.Message, + Message: + { + Type: MessageType.Text, + Text: not null + } + } || MessageReceived is null) + { + return; + } + + await MessageReceived.Invoke(bot, new(this, update.Message)); + }, (_, e, _) => { Console.WriteLine(e); }); } - public async Task SendMessageAsync(long id, MessagePair messages, int? threadId = null) + private async Task SendMessageAsync(long id, MessagePair messages, int? threadId = null) { if (messages.Media is null) { @@ -37,7 +53,7 @@ public async Task SendMessageAsync(long id, MessagePair messages, int? threadId return; } - InputFileStream file = InputFile.FromStream(messages.Media.Data); + InputFile file = InputFile.FromStream(File.OpenRead(messages.Media.Path)); switch (messages.Media.Type) { case MediaType.Audio: diff --git a/src/Config.cs b/src/Config.cs new file mode 100644 index 0000000..1acd018 --- /dev/null +++ b/src/Config.cs @@ -0,0 +1,7 @@ +namespace DXKumaBot; + +public record Config(TelegramConfig Telegram); + +public record TelegramConfig(string BotToken, ProxyConfig Proxy); + +public record ProxyConfig(bool Enabled, string Url); \ No newline at end of file diff --git a/src/DXKumaBot.csproj b/src/DXKumaBot.csproj index d2b49e4..f6ffd7a 100644 --- a/src/DXKumaBot.csproj +++ b/src/DXKumaBot.csproj @@ -10,8 +10,13 @@ + + + + + diff --git a/src/Functions/LoveYou.cs b/src/Functions/LoveYou.cs index 302b913..b4940b2 100644 --- a/src/Functions/LoveYou.cs +++ b/src/Functions/LoveYou.cs @@ -8,11 +8,9 @@ public sealed partial class LoveYou : RegexFunctionBase { protected override async Task Main(object? sender, MessageReceivedEventArgs args) { - TextMessage message = new() - { - Text = "迪拉熊也喜欢你❤️" - }; - await args.Reply(message); + string filePath = Path.Combine("Static", "LoveYou", "0.png"); + MediaMessage message = new(MediaType.Photo, filePath); + await args.Reply(new("迪拉熊也喜欢你❤️", message)); } [GeneratedRegex("^(迪拉熊|dlx)我喜欢你$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)] diff --git a/src/Program.cs b/src/Program.cs index cfaa227..95358fa 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,4 +1,15 @@ -using DXKumaBot.Bot; +using DXKumaBot; +using DXKumaBot.Bot; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Tomlyn.Extensions.Configuration; -BotInstance bot = new(); +HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); +builder.Configuration.Sources.Clear(); +IHostEnvironment env = builder.Environment; +builder.Configuration.AddTomlFile("appsettings.toml", true, true) + .AddTomlFile($"appsettings.{env.EnvironmentName}.toml", true, true); + +Config config = builder.Configuration.Get()!; +BotInstance bot = new(config); await bot.RunAsync(); \ No newline at end of file