XeronOwO / Makabaka

基于 OneBot-11标准 的、适配于 Lagrange.Onebot 的、C# .NET Standard 2.1 的异步机器人开发框架。
GNU General Public License v3.0
18 stars 2 forks source link

请教问题如何主动给某人发送消息,怎么实现SendPrivateMessage #3

Open Pinkuburu opened 4 weeks ago

Pinkuburu commented 4 weeks ago

代码示例中的发送消息,都是收到消息再发送回复,根据EventArgs的内容来获取相关信息 但是请问想要主动给某人发送消息,怎么实现SendPrivateMessage

XeronOwO commented 4 weeks ago

感谢提问。 在使用ServiceFactory创建服务后,会返回IWebSocketService接口,接口中有Contexts属性,表示当前有效的上下文。 https://github.com/XeronOwO/Makabaka/blob/main/Makabaka%2FServices%2FIWebSocketService.cs#L43-L43 当存在有效的上下文时,可以通过调用上下文进行主动的消息操作,比如SendPrivateMessageAsync。

Pinkuburu commented 4 weeks ago

意思要有上下文的聊天内容文字,才能触发主动的消息发送? 但是我和某用户就没有聊天记录呢?例如我A定时给B发送一个消息 不好意思我可能显得过于愚笨,如果可以,我想看一下代码示例,感谢您 如有打扰,抱歉

XeronOwO commented 4 weeks ago

大致的运行逻辑如下:

https://github.com/XeronOwO/Makabaka/blob/main/Makabaka/Services/ServiceFactory.cs#L17 通过ServiceFactory创建并返回IWebSocketService接口。这个接口负责启动、停止整体的服务。

https://github.com/XeronOwO/Makabaka/blob/main/Makabaka/Services/ForwardWebSocketService.cs#L58 当启动服务后,会创建对应的IWebSocketContext,保存到Contexts属性中,该IWebSocketContext负责处理Lagrange.Core的网络连接。

也就是说,这个“上下文”指的是WebSocket这个连接,而不是指具体跟某个用户的聊天记录。 所以IWebSocketService的Contexts其实就是WebSocket连接,直接调用其接口功能就行了。我也不记得当初为什么要用List来存,感觉用nullable就行了。 这样解释好理解不

Pinkuburu commented 4 weeks ago

那大概理解了 所以我把service 变量设为全局变量 然后我在需要的地方await service.Contexts[0].SendPrivateMessageAsync(123456789, new TextSegment("测试!"));

但你的这个SDK设计的方法是在service正式启动前,把需要监听的事件绑定上去,诸如OnPrivateMessage、OnGroupMessage

但我SendPrivateMessageAsync不经事件触发,或者说场景更极端点,机器人A和用户B,从来不聊天,只有A主动给B发消息 那就无法在程序一开始通过绑定一系列事件去允许触发SendPrivateMessageAsync service.OnGroupMessage += OnGroupMessage; service.OnPrivateMessage += OnPrivateMessage;

例如我30分钟执行一次 Notice(){ await service.Contexts[0].SendPrivateMessageAsync(123456789, new TextSegment("测试!")); }

XeronOwO commented 4 weeks ago

SendPrivateMessageAsync的本质就是向Lagrange.Core发送WebSocket数据。即 Makabaka --SendPacket --> Lagrange.Core 。 而OnPrivateMessage,是在接收到Lagrange.Core发来的数据并解析后,再调用,类似于C/C++的回调函数。即 Lagrange.Core --SendPacket --> Makabaka 。 这两个没有谁先谁后的要求。在成功连接上Lagrange.Core后,就可以使用SendPrivateMessageAsync发送消息,不需要OnPrivateMessage事件。

Pinkuburu commented 4 weeks ago

🫣那有可能是我的框架问题,其实我用的是napcat的那个…我下午试试改下代码看看,现在如果在非事件中的地方运行那句代码,就断开了ws链接…🫣🫣🫣应该是我太菜了哪里写错了

Pinkuburu commented 4 weeks ago

Program.cs

private const string ConfigPath = "config.json";
 public static IWebSocketService service;

 static async Task Main(string[] args)
 {
     Log.Logger = new LoggerConfiguration()
         .MinimumLevel.Verbose()
         .WriteTo.Console()
         .CreateLogger(); // 配置日志

     // 加载配置
     ForwardWebSocketServiceConfig? config = null;
     if (File.Exists(ConfigPath))
     {
         config = JsonConvert.DeserializeObject<ForwardWebSocketServiceConfig>(File.ReadAllText(ConfigPath));
     }
     config ??= new();
     File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(config, Formatting.Indented));

     // 初始化服务
     service = ServiceFactory.CreateForwardWebSocketService(config);
     service.OnGroupMessage += OnGroupMessage;
     service.OnPrivateMessage += OnPrivateMessage;
     service.OnGroupRequest += OnGroupRequest;
     service.OnAddFriendRequest += OnFriendRequest;
     //service.OnGroupFileUpload += OnGroupFileUpload;

     // 启动服务
     var cts = new CancellationTokenSource();
     AssemblyLoadContext.Default.Unloading += ctx => cts.Cancel();
     Console.CancelKeyPress += (sender, eventArgs) => cts.Cancel();

     await service.StartAsync();

     await WatchRunner.UpdateAllPlayersEveryXMinutes(0.1);
     // 等待取消信号
     try
     {
         await Task.Delay(Timeout.Infinite, cts.Token);
     }
     catch (TaskCanceledException)
     {
         // 服务停止
     }

     await service.StopAsync();
 }

WatchRunner.cs

namespace Makabaka.Test.app.Dota2Bot
{
    internal static class WatchRunner
    {

        /// <summary>
        /// 定时更新所有在playerHelper数据库中的玩家的比赛信息
        /// 并将战报发送出去
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        static public async Task UpdateAllPlayersEveryXMinutes(double x)
        {
            while (true)
            {
                //如果改为true,就是报喜不报忧
                if (true)
                {
                    Console.WriteLine("UpdateAllPlayersEveryXMinutes");
                    await Program.service.Contexts[0].SendGroupMessageAsync(100399266, new TextSegment("回复测试!"));
                }
                Thread.Sleep(TimeSpan.FromMinutes(x));
            }
        }
    }
}

控制台输出

[21:03:07 INF] 正在启动正向WebSocket服务 [21:03:07 INF] 创建正向WebSocket[6a82e1fa-b8bd-45fc-b44c-d32caee71474] [21:03:07 INF] [6a82e1fa-b8bd-45fc-b44c-d32caee71474]尝试连接ws://192.168.50.162:43001/ UpdateAllPlayersEveryXMinutes [21:03:07 DBG] [6a82e1fa-b8bd-45fc-b44c-d32caee71474]发送数据:{"params":{"group_id":100399266,"message":[{"type":"text","data":{"text":"回复测试!"}}],"auto_escape":false},"action":"send_group_msg","echo":"4f39852f-424a-4fe5-be61-6956336c7ed5"} [21:03:07 INF] [6a82e1fa-b8bd-45fc-b44c-d32caee71474]断开连接

实在不好意思,学习的水平有限,劳请指教一下……谢谢

XeronOwO commented 4 weeks ago

这个的问题是操作太快了,这还没连接上就发送数据了。 而且连接上之后,需要握手鉴权,如果没有鉴权或者鉴权失败,是会直接断开连接的。 可以用下OnLifeCycle事件,具体的EventArgs可以参考 Onebot生命周期

Pinkuburu commented 4 weeks ago

搞定了,应该是可以了 我没想到OnLifeCycle这个东西……我继续去研究下

Pinkuburu commented 1 week ago

`[02:26:58 DBG] [de432cc7-d0fc-499f-a8e2-e86bad873228]接收数据:{"time":1726252018,"self_id":999999999,"post_type":"notice","notice_type":"notify","sub_type":"input_status","status_text":"对方正在输入...","event_type":1,"user_id":1012803704,"group_id":0}

[02:26:58 ERR] [de432cc7-d0fc-499f-a8e2-e86bad873228]处理数据时出现异常 System.Exception: 不支持的notice_type:notify at Makabaka.Utils.DataProcessor.ProcessNotice(String data, JObject json) in D:\ProgramRepos\Makabaka-main\Makabaka\Utils\DataProcessor.cs:line 217 at Makabaka.Utils.DataProcessor.ProcessPost(String data, JObject json) in D:\ProgramRepos\Makabaka-main\Makabaka\Utils\DataProcessor.cs:line 91 at Makabaka.Utils.DataProcessor.Process(String data) in D:\ProgramRepos\Makabaka-main\Makabaka\Utils\DataProcessor.cs:line 73 at Makabaka.Network.ForwardWebSocketContext.MessageReceived(Object sender, MessageReceivedEventArgs e) in D:\ProgramRepos\Makabaka-main\Makabaka\Network\ForwardWebSocketContext.cs:line 97 `

我拿手机给机器人打消息(还没发出去的时候)就会发生报错(不影响程序),你看是不是要修

XeronOwO commented 1 week ago

这个看样子是“正在输入”的数据包,我还没写解析,不过不影响运行。感觉这个数据包一般也用不上吧,要支持解析倒也不难,DataProcessor里面添加处理函数就行。主要是最近比较忙,也没啥时间维护项目了