Lagrange.Core/Lagrange.OneBot/Core/Network/ReverseWSService.cs

96 lines
3.2 KiB
C#

using System.Net.WebSockets;
using System.Text.Json;
using Lagrange.OneBot.Core.Entity.Meta;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Websocket.Client;
using Timer = System.Threading.Timer;
namespace Lagrange.OneBot.Core.Network;
public sealed class ReverseWSService : ILagrangeWebService
{
private const string Tag = nameof(ReverseWSService);
public event EventHandler<MsgRecvEventArgs> OnMessageReceived = delegate { };
private readonly WebsocketClient _socket;
private readonly IConfiguration _config;
private readonly ILogger _logger;
private readonly Timer _timer;
public ReverseWSService(IConfiguration config, ILogger<LagrangeApp> logger)
{
_config = config;
_logger = logger;
var ws = _config.GetSection("Implementation").GetSection("ReverseWebSocket");
string url = $"ws://{ws["Host"]}:{ws["Port"]}{ws["Suffix"]}";
_socket = new WebsocketClient(new Uri(url), () =>
{
var socket = new ClientWebSocket();
SetRequestHeader(socket, new Dictionary<string, string>
{
{ "X-Client-Role", "Universal" },
{ "X-Self-ID", _config.GetValue<uint>("Account:Uin").ToString() },
{ "User-Agent", Constant.OneBotImpl }
});
socket.Options.KeepAliveInterval = TimeSpan.FromSeconds(5);
if (_config["AccessToken"] != null) socket.Options.SetRequestHeader("Authorization", $"Bearer {_config["AccessToken"]}");
return socket;
});
_timer = new Timer(OnHeartbeat, null, int.MaxValue, config.GetValue<int>("Implementation:ReverseWebSocket:HeartBeatInterval"));
_socket.MessageReceived.Subscribe(resp =>
{
_logger.LogTrace($"[{Tag}] Receive: {resp.Text}");
OnMessageReceived.Invoke(this, new MsgRecvEventArgs(resp.Text ?? ""));
});
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await _socket.Start();
var lifecycle = new OneBotLifecycle(_config.GetValue<uint>("Account:Uin"), "connect");
await SendJsonAsync(lifecycle, cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer.Dispose();
_socket.Dispose();
return Task.CompletedTask;
}
public Task SendJsonAsync<T>(T json, CancellationToken cancellationToken = default)
{
string payload = JsonSerializer.Serialize(json);
_logger.LogTrace($"[{Tag}] Send: {payload}");
return _socket.SendInstant(payload);
}
private void OnHeartbeat(object? sender)
{
var status = new OneBotStatus(true, true);
var heartBeat = new OneBotHeartBeat(
_config.GetValue<uint>("Account:Uin"),
_config.GetValue<int>("Implementation:ReverseWebSocket:HeartBeatInterval"),
status);
SendJsonAsync(heartBeat);
}
private static void SetRequestHeader(ClientWebSocket webSocket, Dictionary<string, string> headers)
{
foreach (var (key, value) in headers) webSocket.Options.SetRequestHeader(key, value);
}
}