Gateway client basics

This commit is contained in:
Kecskeméti László 2024-07-21 00:01:05 +02:00
parent bc58ae98ea
commit 6df9346de1

View File

@ -0,0 +1,76 @@
using System.Collections.Specialized;
using System.Text.Json;
using Serilog;
using Websocket.Client;
namespace Discord.API;
public class GatewayClient {
private const int ApiVersion = 10;
private string ApiKey;
private WebsocketClient Websocket;
private CancellationTokenSource? heartbeat_cts;
private ulong? Sequence = null;
public GatewayClient(string url, string api_key){
this.ApiKey=api_key;
UriBuilder uriBuilder = new(url);
NameValueCollection query = System.Web.HttpUtility.ParseQueryString("");
query.Add("v", ApiVersion.ToString());
query.Add("encoding", "json");
uriBuilder.Query=query.ToString();
Websocket = new WebsocketClient(uriBuilder.Uri);
Websocket.DisconnectionHappened.Subscribe(DisconnectionHandler);
Websocket.ReconnectionHappened.Subscribe(ReconnectionHandler);
Websocket.MessageReceived.Subscribe(MessageReceivedHandler);
Log.Debug("GATEWAY: Created new gateway, with url: {url}", uriBuilder.ToString());
}
private void DisconnectionHandler(DisconnectionInfo info){
Log.Information("GATEWAY: Disconnected. Type: {DisconnectionType}", info.Type);
}
private void ReconnectionHandler(ReconnectionInfo info){
Log.Information("GATEWAY: (Re)Connected to server. Url: {url}, Type: {Type}", Websocket.Url, info.Type);
}
private void MessageReceivedHandler(ResponseMessage msg){
if(msg.MessageType != System.Net.WebSockets.WebSocketMessageType.Text) return;
try{
GatewayPacket packet = JsonSerializer.Deserialize(msg.Text!, SourceGenerationContext.Default.GatewayPacket)
?? throw new Exception("Failed to deserialize packet"); // This can be optimized //TODO
switch(packet){
case HelloPacket helloPacket:
HelloPacketHandler(helloPacket);
break;
}
}catch(Exception ex){
Log.Warning(ex, "GATEWAY: Error processing gateway event");
}
}
private void HelloPacketHandler(HelloPacket packet){
StartHeartbeat((int)packet.Data.HeartbeatInterval);
}
private void StartHeartbeat(int heartbeat_interval){
heartbeat_cts?.Cancel();
heartbeat_cts = new CancellationTokenSource();
CancellationToken ct = heartbeat_cts.Token;
Task.Run(async ()=>{
await Task.Delay(Random.Shared.Next(1, heartbeat_interval));
using PeriodicTimer pd = new(TimeSpan.FromMilliseconds(heartbeat_interval));
do{
HeartbeatPacket packet = new HeartbeatPacket(){
Sequence=this.Sequence
};
if(Websocket.IsRunning)
if(!Websocket.Send(JsonSerializer.Serialize(packet, SourceGenerationContext.Default.HeartbeatPacket))){
Log.Warning("GATEWAY: Failed to queue heartbeat message");
}
}while(await pd.WaitForNextTickAsync(ct) && !ct.IsCancellationRequested);
});
}
}