using System.Net.WebSockets; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace PartyDamage; public class Client : IDisposable { private ClientWebSocket WebSocket { get; } private CancellationTokenSource TokenSource { get; } private Task? MainTask { get; set; } private bool _disposed; internal CombatData? Data { get; private set; } internal Client() { this.WebSocket = new ClientWebSocket(); this.TokenSource = new CancellationTokenSource(); this.MainTask = Task.Run(async () => { while (!this._disposed) { try { await this.Main(); } catch (TaskCanceledException) { break; } catch (Exception ex) { Plugin.Log.Error(ex, "Error in WebSocket loop"); await Task.Delay(TimeSpan.FromSeconds(3)); } } }); } public void Dispose() { if (this._disposed) { return; } this._disposed = true; this.TokenSource.Cancel(); this.WebSocket.Dispose(); } private async Task Main() { await this.WebSocket.ConnectAsync(new Uri("ws://127.0.0.1:10501/ws"), this.TokenSource.Token); const string msg = "{\"call\": \"subscribe\", \"events\": [\"CombatData\"]}"; var msgBytes = Encoding.UTF8.GetBytes(msg); await this.WebSocket.SendAsync(msgBytes, WebSocketMessageType.Text, true, this.TokenSource.Token); var buf = new byte[1024]; var bytes = new List(); while (this.WebSocket.State == WebSocketState.Open) { var resp = await this.WebSocket.ReceiveAsync(buf, this.TokenSource.Token); bytes.AddRange(buf[..resp.Count]); if (!resp.EndOfMessage) { continue; } var text = Encoding.UTF8.GetString(bytes.ToArray()); bytes.Clear(); var jobj = JObject.Parse(text); if (jobj["type"]?.Value() == "CombatData") { var data = JsonConvert.DeserializeObject(text); this.Data = data; } } Plugin.Log.Info("websocket loop shut down"); } }