mirror of
https://github.com/barelyprofessional/KfChatDotNet.git
synced 2026-04-30 03:22:04 -04:00
Refactored to fix compiler warnings
This commit is contained in:
@@ -88,6 +88,7 @@ public class NewKickChannelCommand : ICommand
|
||||
{
|
||||
var channels = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.KickChannels)).JsonDeserialize<List<KickChannelModel>>();
|
||||
var channelId = Convert.ToInt32(arguments["channel_id"].Value);
|
||||
channels ??= [];
|
||||
if (channels.Any(channel => channel.ChannelId == channelId))
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("Channel is already in the database", true);
|
||||
@@ -119,6 +120,7 @@ public class RemoveKickChannelCommand : ICommand
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
var channels = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.KickChannels)).JsonDeserialize<List<KickChannelModel>>();
|
||||
if (channels == null) throw new Exception("Caught a null when deserializing Kick channels");
|
||||
var channelId = Convert.ToInt32(arguments["channel_id"].Value);
|
||||
var channel = channels.FirstOrDefault(ch => ch.ChannelId == channelId);
|
||||
if (channel == null)
|
||||
@@ -144,6 +146,11 @@ public class ReconnectKickCommand : ICommand
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
if (botInstance.BotServices.KickClient == null)
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("Kick client is not initialized", true);
|
||||
return;
|
||||
}
|
||||
botInstance.BotServices.KickClient.Disconnect();
|
||||
await botInstance.SendChatMessageAsync("Disconnected from Kick. Client should reconnect shortly.", true);
|
||||
}
|
||||
@@ -365,6 +372,11 @@ public class SetAlmanacIntervalCommand : ICommand
|
||||
return;
|
||||
}
|
||||
await SettingsProvider.SetValueAsync(BuiltIn.Keys.BotAlmanacInterval, arguments["interval"].Value);
|
||||
if (botInstance.BotServices.AlmanacShill == null)
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("Value has been saved but almanac shill has not been initialized", true);
|
||||
return;
|
||||
}
|
||||
await botInstance.BotServices.AlmanacShill.StopShillTaskAsync();
|
||||
botInstance.BotServices.AlmanacShill.StartShillTask();
|
||||
await botInstance.SendChatMessageAsync($"@{message.Author.Username}, updated interval and restarted the shill task", true);
|
||||
@@ -383,6 +395,11 @@ public class StopAlmanacCommand : ICommand
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments,
|
||||
CancellationToken ctx)
|
||||
{
|
||||
if (botInstance.BotServices.AlmanacShill == null)
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("AlmanacShill is null", true);
|
||||
return;
|
||||
}
|
||||
if (!botInstance.BotServices.AlmanacShill.IsShillTaskRunning())
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("Looks like the task isn't even running", true);
|
||||
@@ -407,6 +424,11 @@ public class StartAlmanacCommand : ICommand
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments,
|
||||
CancellationToken ctx)
|
||||
{
|
||||
if (botInstance.BotServices.AlmanacShill == null)
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("AlmanacShill is null", true);
|
||||
return;
|
||||
}
|
||||
if (botInstance.BotServices.AlmanacShill.IsShillTaskRunning())
|
||||
{
|
||||
await botInstance.SendChatMessageAsync("Looks like the task is already running", true);
|
||||
|
||||
@@ -79,7 +79,7 @@ public class ExceptionTestCommand : ICommand
|
||||
public UserRight RequiredRight => UserRight.Admin;
|
||||
// Increased timeout as it has to wait for Sneedchat to echo the message and that can be slow sometimes
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(15);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
public Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
throw new Exception("Caused by the test exception command");
|
||||
}
|
||||
|
||||
@@ -64,8 +64,14 @@ public class GetVersionCommand : ICommand
|
||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||
public async Task RunCommand(ChatBot botInstance, MessageModel message, UserDbModel user, GroupCollection arguments, CancellationToken ctx)
|
||||
{
|
||||
var version = Assembly.GetEntryAssembly()
|
||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
var version = Assembly.GetEntryAssembly()?
|
||||
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
|
||||
if (version == null)
|
||||
{
|
||||
await botInstance.SendChatMessageAsync($"Caught a null when trying to retrieve the bot's assembly version.",
|
||||
true);
|
||||
return;
|
||||
}
|
||||
await botInstance.SendChatMessageAsync($"Bot compiled against {version.Split('+')[1]}", true);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ public class ChipsggBetModel
|
||||
public DateTimeOffset Created { get; set; }
|
||||
// Can actually get the duration of a game from this
|
||||
public DateTimeOffset Updated { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string? UserId { get; set; }
|
||||
// Sometimes null for no discernible reason
|
||||
public string? Username { get; set; }
|
||||
// Win of any amount even if it's less than a 1x multi
|
||||
@@ -16,7 +16,7 @@ public class ChipsggBetModel
|
||||
public float Multiplier { get; set; }
|
||||
public string? Currency { get; set; }
|
||||
public float CurrencyPrice { get; set; }
|
||||
public string BetId { get; set; }
|
||||
public string? BetId { get; set; }
|
||||
}
|
||||
|
||||
public class ChipsggCurrencyModel
|
||||
|
||||
@@ -12,22 +12,22 @@ namespace KfChatDotNetBot.Services;
|
||||
public class BetBolt : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://betbolt.com/api/ws");
|
||||
// Pings every 5 seconds so 15 seconds should be reasonable
|
||||
private int _reconnectTimeout = 15;
|
||||
private string? _proxy;
|
||||
public delegate void OnBetBoltBetEventHandler(object sender, BetBoltBetModel bet);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnBetBoltBetEventHandler OnBetBoltBet;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
private IEnumerable<string>? _cookies = null;
|
||||
private string? _userAgent = null;
|
||||
public BetBolt(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public event OnBetBoltBetEventHandler? OnBetBoltBet;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
private IEnumerable<string>? _cookies;
|
||||
private string? _userAgent;
|
||||
public BetBolt(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Clash.gg WebSocket client created");
|
||||
}
|
||||
public async Task StartWsClient()
|
||||
@@ -86,7 +86,7 @@ public class BetBolt : IDisposable
|
||||
if (reconnectionInfo.Type == ReconnectionType.Initial)
|
||||
{
|
||||
_logger.Info("Sending subscribe payload to BetBolt");
|
||||
_wsClient.Send("{\"topic\":\"system/EN\",\"action\":\"subscribe\"}");
|
||||
_wsClient?.Send("{\"topic\":\"system/EN\",\"action\":\"subscribe\"}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,29 +19,28 @@ public class BotServices
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
internal KickWsClient.KickWsClient KickClient;
|
||||
private Twitch _twitch;
|
||||
private Shuffle _shuffle;
|
||||
private DiscordService _discord;
|
||||
private TwitchChat _twitchChat;
|
||||
private Jackpot _jackpot;
|
||||
private Howlgg _howlgg;
|
||||
private RainbetWs _rainbet;
|
||||
private Chipsgg _chipsgg;
|
||||
private Clashgg _clashgg;
|
||||
private BetBolt _betBolt;
|
||||
private Yeet _yeet;
|
||||
public AlmanacShill AlmanacShill;
|
||||
internal KickWsClient.KickWsClient? KickClient;
|
||||
private Twitch? _twitch;
|
||||
private Shuffle? _shuffle;
|
||||
private DiscordService? _discord;
|
||||
private TwitchChat? _twitchChat;
|
||||
private Jackpot? _jackpot;
|
||||
private Howlgg? _howlgg;
|
||||
private RainbetWs? _rainbet;
|
||||
private Chipsgg? _chipsgg;
|
||||
private Clashgg? _clashgg;
|
||||
private BetBolt? _betBolt;
|
||||
private Yeet? _yeet;
|
||||
public AlmanacShill? AlmanacShill;
|
||||
|
||||
private Task? _websocketWatchdog;
|
||||
private Task? _howlggGetUserTimer;
|
||||
|
||||
private string _bmjTwitchUsername;
|
||||
private bool _twitchDisabled = false;
|
||||
private string? _lastDiscordStatus;
|
||||
internal bool IsBmjLive = false;
|
||||
private bool _isBmjLiveSynced = false;
|
||||
internal bool IsChrisDjLive = false;
|
||||
private string? _bmjTwitchUsername;
|
||||
private bool _twitchDisabled;
|
||||
internal bool IsBmjLive;
|
||||
private bool _isBmjLiveSynced;
|
||||
internal bool IsChrisDjLive;
|
||||
private Dictionary<string, SeenYeetBet> _yeetBets = new();
|
||||
|
||||
// lol
|
||||
@@ -142,7 +141,7 @@ public class BotServices
|
||||
_logger.Debug("Chips.gg is disabled");
|
||||
return;
|
||||
}
|
||||
_chipsgg = new Chipsgg(settings[BuiltIn.Keys.Proxy].Value, _cancellationToken);
|
||||
_chipsgg = new Chipsgg(settings[BuiltIn.Keys.Proxy].Value);
|
||||
_chipsgg.OnChipsggRecentBet += OnChipsggRecentBet;
|
||||
await _chipsgg.StartWsClient();
|
||||
_logger.Info("Built Chips.gg Websocket connection");
|
||||
@@ -302,7 +301,7 @@ public class BotServices
|
||||
]);
|
||||
try
|
||||
{
|
||||
if (!_shuffle.IsConnected())
|
||||
if (_shuffle != null && !_shuffle.IsConnected())
|
||||
{
|
||||
_logger.Error("Shuffle died, recreating it");
|
||||
_shuffle.Dispose();
|
||||
@@ -310,7 +309,7 @@ public class BotServices
|
||||
await BuildShuffle();
|
||||
}
|
||||
|
||||
if (!_discord.IsConnected())
|
||||
if (_discord != null && !_discord.IsConnected())
|
||||
{
|
||||
_logger.Error("Discord died, recreating it");
|
||||
_discord.Dispose();
|
||||
@@ -318,7 +317,7 @@ public class BotServices
|
||||
await BuildDiscord();
|
||||
}
|
||||
|
||||
if (!_twitchDisabled && !_twitch.IsConnected())
|
||||
if (!_twitchDisabled && _twitch != null && !_twitch.IsConnected())
|
||||
{
|
||||
_logger.Error("Twitch died, recreating it");
|
||||
_twitch.Dispose();
|
||||
@@ -326,7 +325,7 @@ public class BotServices
|
||||
await BuildTwitch();
|
||||
}
|
||||
|
||||
if (!_twitchChat.IsConnected())
|
||||
if (_twitchChat != null && !_twitchChat.IsConnected())
|
||||
{
|
||||
_logger.Error("Twitch chat died, recreating it");
|
||||
_twitchChat.Dispose();
|
||||
@@ -334,7 +333,7 @@ public class BotServices
|
||||
await BuildTwitchChat();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.HowlggEnabled].ToBoolean() && !_howlgg.IsConnected())
|
||||
if (settings[BuiltIn.Keys.HowlggEnabled].ToBoolean() && _howlgg != null && !_howlgg.IsConnected())
|
||||
{
|
||||
_logger.Error("Howl.gg died, recreating it");
|
||||
_howlgg.Dispose();
|
||||
@@ -342,7 +341,7 @@ public class BotServices
|
||||
await BuildHowlgg();
|
||||
}
|
||||
|
||||
if (!_jackpot.IsConnected())
|
||||
if (_jackpot != null && !_jackpot.IsConnected())
|
||||
{
|
||||
_logger.Error("Jackpot died, recreating it");
|
||||
_jackpot.Dispose();
|
||||
@@ -350,7 +349,7 @@ public class BotServices
|
||||
await BuildJackpot();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.ChipsggEnabled].ToBoolean() && !_chipsgg.IsConnected())
|
||||
if (settings[BuiltIn.Keys.ChipsggEnabled].ToBoolean() && _chipsgg != null && !_chipsgg.IsConnected())
|
||||
{
|
||||
_logger.Error("Chips died, recreating it");
|
||||
_chipsgg.Dispose();
|
||||
@@ -358,7 +357,7 @@ public class BotServices
|
||||
await BuildChipsgg();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.KickEnabled].ToBoolean() && !KickClient.IsConnected())
|
||||
if (settings[BuiltIn.Keys.KickEnabled].ToBoolean() && KickClient != null && !KickClient.IsConnected())
|
||||
{
|
||||
_logger.Error("Kick died, recreating it");
|
||||
KickClient.Dispose();
|
||||
@@ -366,7 +365,7 @@ public class BotServices
|
||||
await BuildKick();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.ClashggEnabled].ToBoolean() && !_clashgg.IsConnected())
|
||||
if (settings[BuiltIn.Keys.ClashggEnabled].ToBoolean() && _clashgg != null && !_clashgg.IsConnected())
|
||||
{
|
||||
_logger.Error("Clash.gg died, recreating it");
|
||||
_clashgg.Dispose();
|
||||
@@ -374,7 +373,7 @@ public class BotServices
|
||||
await BuildClashgg();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.BetBoltEnabled].ToBoolean() && !_betBolt.IsConnected())
|
||||
if (settings[BuiltIn.Keys.BetBoltEnabled].ToBoolean() && _betBolt != null && !_betBolt.IsConnected())
|
||||
{
|
||||
_logger.Error("BetBolt died, recreating it");
|
||||
_betBolt.Dispose();
|
||||
@@ -382,7 +381,7 @@ public class BotServices
|
||||
await BuildBetBolt();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.YeetEnabled].ToBoolean() && !_yeet.IsConnected())
|
||||
if (settings[BuiltIn.Keys.YeetEnabled].ToBoolean() && _yeet != null && !_yeet.IsConnected())
|
||||
{
|
||||
_logger.Error("Yeet died, recreating it");
|
||||
_yeet.Dispose();
|
||||
@@ -390,7 +389,7 @@ public class BotServices
|
||||
await BuildYeet();
|
||||
}
|
||||
|
||||
if (settings[BuiltIn.Keys.RainbetEnabled].ToBoolean() && !_rainbet.IsConnected())
|
||||
if (settings[BuiltIn.Keys.RainbetEnabled].ToBoolean() && _rainbet != null && !_rainbet.IsConnected())
|
||||
{
|
||||
_logger.Error("Rainbet died, recreating it");
|
||||
_rainbet.Dispose();
|
||||
@@ -549,7 +548,6 @@ public class BotServices
|
||||
}
|
||||
_logger.Info("ALERT BMJ IS BETTING (on Yeet)");
|
||||
if (CheckBmjIsLive(settings[BuiltIn.Keys.TwitchBossmanJackUsername].Value ?? "usernamenotset").Result) return;
|
||||
var payoutColor = settings[BuiltIn.Keys.KiwiFarmsGreenColor].Value;
|
||||
//if (bet.WinAmountFiat < 0) payoutColor = settings[BuiltIn.Keys.KiwiFarmsRedColor].Value;
|
||||
var msg = _chatBot.SendChatMessage($"🚨🚨 JEET BETTING 🚨🚨 {bet.Username} just bet {bet.BetAmount:C} worth of {bet.CurrencyCode} on {bet.GameName} 💩💩", true);
|
||||
_yeetBets.Add(bet.BetIdentifier, new SeenYeetBet {Bet = bet, Message = msg});
|
||||
@@ -809,7 +807,7 @@ public class BotServices
|
||||
BuiltIn.Keys.KiwiFarmsGreenColor, BuiltIn.Keys.KiwiFarmsRedColor
|
||||
]).Result;
|
||||
_logger.Trace("Chips.gg bet has arrived");
|
||||
if (!settings[BuiltIn.Keys.ChipsggBmjUserIds].JsonDeserialize<List<string>>()!.Contains(bet.UserId))
|
||||
if (!settings[BuiltIn.Keys.ChipsggBmjUserIds].JsonDeserialize<List<string>>()!.Contains(bet.UserId ?? "0"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -817,9 +815,9 @@ public class BotServices
|
||||
using var db = new ApplicationDbContext();
|
||||
db.ChipsggBets.Add(new ChipsggBetDbModel
|
||||
{
|
||||
Created = bet.Created, Updated = bet.Updated, UserId = bet.UserId, Username = bet.Username ?? "Unknown", Win = bet.Win,
|
||||
Created = bet.Created, Updated = bet.Updated, UserId = bet.UserId ?? "0", Username = bet.Username ?? "Unknown", Win = bet.Win,
|
||||
Winnings = bet.Winnings, GameTitle = bet.GameTitle!, Amount = bet.Amount, Multiplier = bet.Multiplier,
|
||||
Currency = bet.Currency!, CurrencyPrice = bet.CurrencyPrice, BetId = bet.BetId
|
||||
Currency = bet.Currency!, CurrencyPrice = bet.CurrencyPrice, BetId = bet.BetId ?? "0"
|
||||
});
|
||||
db.SaveChanges();
|
||||
if (CheckBmjIsLive(settings[BuiltIn.Keys.TwitchBossmanJackUsername].Value ?? "usernamenotset").Result) return;
|
||||
@@ -840,7 +838,7 @@ public class BotServices
|
||||
if (kickChannels == null) return;
|
||||
foreach (var channel in kickChannels)
|
||||
{
|
||||
KickClient.SendPusherSubscribe($"channel.{channel.ChannelId}");
|
||||
KickClient?.SendPusherSubscribe($"channel.{channel.ChannelId}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -951,6 +949,11 @@ public class BotServices
|
||||
// He was schizo betting on Dice, so I want to avoid a lot of API requests to Twitch in case they rate limit
|
||||
if (!_isBmjLiveSynced)
|
||||
{
|
||||
if (_twitch == null)
|
||||
{
|
||||
_logger.Error("Twitch client has not been built!");
|
||||
throw new Exception("Twitch client not initialized");
|
||||
}
|
||||
IsBmjLive = await _twitch.IsStreamLive(bmjUsername);
|
||||
_isBmjLiveSynced = true;
|
||||
}
|
||||
|
||||
@@ -10,22 +10,20 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Chipsgg : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://api.chips.gg/prod/socket");
|
||||
// Chips doesn't have a heartbeat packet
|
||||
private int _reconnectTimeout = 30;
|
||||
private string? _proxy;
|
||||
public delegate void OnChipsggRecentBetEventHandler(object sender, ChipsggBetModel bet);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnChipsggRecentBetEventHandler OnChipsggRecentBet;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnChipsggRecentBetEventHandler? OnChipsggRecentBet;
|
||||
private Dictionary<string, ChipsggCurrencyModel> _currencies = new();
|
||||
private bool _authenticated = false;
|
||||
private bool _authenticated;
|
||||
|
||||
public Chipsgg(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Chipsgg(string? proxy = null)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_logger.Info("Chipsgg WebSocket client created");
|
||||
}
|
||||
|
||||
@@ -83,7 +81,7 @@ public class Chipsgg : IDisposable
|
||||
if (reconnectionInfo.Type == ReconnectionType.Initial)
|
||||
{
|
||||
_logger.Info("Sending auth payload to Chips.gg");
|
||||
_wsClient.Send("[\"auth\",1,\"token\",[]]");
|
||||
_wsClient?.Send("[\"auth\",1,\"token\",[]]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +119,7 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
var guid = firstElement[2].GetString();
|
||||
_logger.Info("Received auth packet, sending back GUID auth with " + guid);
|
||||
_wsClient.Send("[\"auth\",2,\"authenticate\",[\"" + guid+ "\"]]");
|
||||
_wsClient?.Send("[\"auth\",2,\"authenticate\",[\"" + guid+ "\"]]");
|
||||
_authenticated = true;
|
||||
return;
|
||||
}
|
||||
@@ -130,7 +128,7 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
_logger.Info("Chips.gg responded to our auth with: " + firstElement[2].GetString());
|
||||
_logger.Info("Sending Chips.gg recent bets subscription packet");
|
||||
_wsClient.Send("[\"stats\",12,\"on\",[{\"game\":\"bets\",\"type\":\"recentBets\"}]]");
|
||||
_wsClient?.Send("[\"stats\",12,\"on\",[{\"game\":\"bets\",\"type\":\"recentBets\"}]]");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,7 +155,7 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
_logger.Info("Received currency payload without getting the auth response. Retarded inconsistent Chips.gg behavior again, sending a made-up GUID");
|
||||
var guid = Guid.NewGuid().ToString();
|
||||
_wsClient.Send("[\"auth\",2,\"authenticate\",[\"" + guid+ "\"]]");
|
||||
_wsClient?.Send("[\"auth\",2,\"authenticate\",[\"" + guid+ "\"]]");
|
||||
}
|
||||
_logger.Info("Received initial currency payload as the path array was empty");
|
||||
var currencyData = dataElement[1].Deserialize<Dictionary<string, JsonElement>>();
|
||||
@@ -172,7 +170,8 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
_logger.Info("Ignoring already defined currency");
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
float? price = null;
|
||||
// Where a price is not set, the element is simply missing
|
||||
if (currencies[currency].TryGetProperty("price", out var priceElement))
|
||||
@@ -206,7 +205,7 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
_logger.Debug("Ignoring packet as it contains koth");
|
||||
return;
|
||||
};
|
||||
}
|
||||
var currency = innerDataPath[1];
|
||||
if (_currencies.TryGetValue(currency, out var updatedCurrency))
|
||||
{
|
||||
@@ -227,7 +226,7 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
_logger.Info("Ignoring replay of recent bets");
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
// Currency data may not be known until after so hold it here til we're done parsing
|
||||
var amount = string.Empty;
|
||||
@@ -323,7 +322,7 @@ public class Chipsgg : IDisposable
|
||||
{
|
||||
_logger.Debug("Currency or GameTitle was null, ignoring");
|
||||
return;
|
||||
};
|
||||
}
|
||||
if (!_currencies.TryGetValue(bet.Currency, out var currencyData))
|
||||
{
|
||||
throw new Exception($"Unknown currency {bet.Currency}");
|
||||
@@ -352,7 +351,7 @@ public class Chipsgg : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text.Json;
|
||||
using KfChatDotNetBot.Models;
|
||||
@@ -11,28 +10,28 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Clashgg : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://ws.clash.gg/");
|
||||
// Ping interval is 30 seconds
|
||||
private int _reconnectTimeout = 60;
|
||||
private string? _proxy;
|
||||
public delegate void OnClashBetEventHandler(object sender, ClashggBetModel data, JsonElement jsonElement);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnClashBetEventHandler OnClashBet;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnClashBetEventHandler? OnClashBet;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
private CancellationTokenSource _pingCts = new();
|
||||
private Task? _heartbeatTask;
|
||||
private TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(60);
|
||||
private bool _isOnline = false;
|
||||
private bool _isOnline;
|
||||
private DateTime _lastBet = DateTime.Now;
|
||||
// How long we can go without any gambling activity until we go 'fuck it' and reconnect
|
||||
private TimeSpan _lastBetTolerance = TimeSpan.FromMinutes(5);
|
||||
|
||||
public Clashgg(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Clashgg(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Clash.gg WebSocket client created");
|
||||
}
|
||||
|
||||
@@ -128,9 +127,9 @@ public class Clashgg : IDisposable
|
||||
if (packet[0].GetString() == "online" && !_isOnline)
|
||||
{
|
||||
_logger.Info("Received online packet from Clash.gg. Subscribing to Plinko, Mines and Keno");
|
||||
_wsClient.Send("[\"subscribe\",\"plinko\"]");
|
||||
_wsClient.Send("[\"subscribe\",\"mines\"]");
|
||||
_wsClient.Send("[\"subscribe\",\"keno\"]");
|
||||
_wsClient?.Send("[\"subscribe\",\"plinko\"]");
|
||||
_wsClient?.Send("[\"subscribe\",\"mines\"]");
|
||||
_wsClient?.Send("[\"subscribe\",\"keno\"]");
|
||||
_isOnline = true;
|
||||
_heartbeatTask = Task.Run(HeartbeatTimer, _cancellationToken);
|
||||
return;
|
||||
@@ -221,7 +220,7 @@ public class Clashgg : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
_pingCts.Cancel();
|
||||
_pingCts.Dispose();
|
||||
_heartbeatTask?.Dispose();
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace KfChatDotNetBot.Services;
|
||||
public class DiscordService : IDisposable
|
||||
{
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private readonly Uri _wsUri = new Uri("wss://gateway.discord.gg/?encoding=json&v=9");
|
||||
// Not sure what a good value for this would be
|
||||
private const int ReconnectTimeout = 60;
|
||||
@@ -29,24 +29,24 @@ public class DiscordService : IDisposable
|
||||
public delegate void ConversationSummaryUpdateEventHandler(object sender,
|
||||
DiscordConversationSummaryUpdateModel summary, string guildId);
|
||||
|
||||
public event MessageReceivedEventHandler OnMessageReceived;
|
||||
public event PresenceUpdateEventHandler OnPresenceUpdated;
|
||||
public event WsDisconnectionEventHandler OnWsDisconnection;
|
||||
public event InvalidCredentialsEventHandler OnInvalidCredentials;
|
||||
public event ChannelCreatedEventHandler OnChannelCreated;
|
||||
public event ChannelDeletedEventHandler OnChannelDeleted;
|
||||
public event ConversationSummaryUpdateEventHandler OnConversationSummaryUpdate;
|
||||
public event MessageReceivedEventHandler? OnMessageReceived;
|
||||
public event PresenceUpdateEventHandler? OnPresenceUpdated;
|
||||
public event WsDisconnectionEventHandler? OnWsDisconnection;
|
||||
public event InvalidCredentialsEventHandler? OnInvalidCredentials;
|
||||
public event ChannelCreatedEventHandler? OnChannelCreated;
|
||||
public event ChannelDeletedEventHandler? OnChannelDeleted;
|
||||
public event ConversationSummaryUpdateEventHandler? OnConversationSummaryUpdate;
|
||||
|
||||
private readonly CancellationToken _cancellationToken = CancellationToken.None;
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
private readonly CancellationTokenSource _pingCts = new();
|
||||
private Task? _heartbeatTask;
|
||||
// Discord tells us the heartbeat interval to use in the op 10 response so this is just a placeholder
|
||||
private TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(40);
|
||||
|
||||
public DiscordService(string authorization, string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public DiscordService(string authorization, string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_authorization = authorization;
|
||||
_logger.Info("Discord Service created");
|
||||
}
|
||||
@@ -159,7 +159,7 @@ public class DiscordService : IDisposable
|
||||
"\"client_build_number\":306208,\"client_event_source\":null,\"design_id\":0},\"presence\":{\"status\":\"unknown\"," +
|
||||
"\"since\":0,\"activities\":[],\"afk\":false},\"compress\":false,\"client_state\":{\"guild_versions\":{}}}}";
|
||||
_logger.Debug(initPayload);
|
||||
_wsClient.SendInstant(initPayload).Wait(_cancellationToken);
|
||||
_wsClient?.SendInstant(initPayload).Wait(_cancellationToken);
|
||||
_heartbeatInterval =
|
||||
TimeSpan.FromMilliseconds(packet.Data.GetProperty("heartbeat_interval").GetInt32());
|
||||
if (_heartbeatTask != null) return;
|
||||
@@ -235,7 +235,7 @@ public class DiscordService : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
_logger.Info("Disposing of the Discord service");
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
_pingCts.Cancel();
|
||||
_pingCts.Dispose();
|
||||
_heartbeatTask?.Dispose();
|
||||
|
||||
@@ -10,25 +10,25 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Howlgg : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://howl.gg/socket.io/?EIO=3&transport=websocket");
|
||||
// Howl will send its own timeout but seems it's always 30 seconds
|
||||
private int _reconnectTimeout = 30;
|
||||
private string? _proxy;
|
||||
public delegate void OnHowlggBetHistoryResponse(object sender, HowlggBetHistoryResponseModel data);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnHowlggBetHistoryResponse OnHowlggBetHistory;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnHowlggBetHistoryResponse? OnHowlggBetHistory;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
private CancellationTokenSource _pingCts = new();
|
||||
private Task? _heartbeatTask;
|
||||
// Howl.gg tells us the heartbeat interval to use in the initial payload so this is just a placeholder
|
||||
private TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(40);
|
||||
|
||||
public Howlgg(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Howlgg(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Howlgg WebSocket client created");
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class Howlgg : IDisposable
|
||||
{
|
||||
var packet = "42/main,0[\"getUserInfo\",{\"userOrSteamId\":\"" + userId + "\",\"interval\":\"lifetime\"}]";
|
||||
_logger.Debug($"Sending packet: {packet}");
|
||||
_wsClient.Send(packet);
|
||||
_wsClient?.Send(packet);
|
||||
}
|
||||
|
||||
private async Task HeartbeatTimer()
|
||||
@@ -141,7 +141,7 @@ public class Howlgg : IDisposable
|
||||
if (message.Text == "40")
|
||||
{
|
||||
_logger.Trace("Ready to subscribe, sending main subscription");
|
||||
_wsClient.Send("40/main,");
|
||||
_wsClient?.Send("40/main,");
|
||||
// To indicate successful subscription it echoes back the channel to you
|
||||
return;
|
||||
}
|
||||
@@ -152,7 +152,6 @@ public class Howlgg : IDisposable
|
||||
var jsonPayload = message.Text.Replace("43/main,0[null,", string.Empty).TrimEnd(']');
|
||||
var data = JsonSerializer.Deserialize<HowlggBetHistoryResponseModel>(jsonPayload);
|
||||
if (data != null) OnHowlggBetHistory?.Invoke(this, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -167,7 +166,7 @@ public class Howlgg : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
_pingCts.Cancel();
|
||||
_pingCts.Dispose();
|
||||
_heartbeatTask?.Dispose();
|
||||
|
||||
@@ -11,25 +11,25 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Jackpot : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://api.jackpot.bet/feeds/websocket");
|
||||
// Ping interval is 30 seconds
|
||||
private int _reconnectTimeout = 60;
|
||||
private string? _proxy;
|
||||
public delegate void OnJackpotBetEventHandler(object sender, JackpotWsBetPayloadModel data);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnJackpotBetEventHandler OnJackpotBet;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnJackpotBetEventHandler? OnJackpotBet;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
private CancellationTokenSource _pingCts = new();
|
||||
private Task? _heartbeatTask;
|
||||
// There's no smarts, it just does 30-second pings
|
||||
private TimeSpan _heartbeatInterval = TimeSpan.FromSeconds(30);
|
||||
|
||||
public Jackpot(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Jackpot(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Jackpot WebSocket client created");
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public class Jackpot : IDisposable
|
||||
if (reconnectionInfo.Type == ReconnectionType.Initial)
|
||||
{
|
||||
_logger.Debug("Sending initial payload");
|
||||
_wsClient.Send("{\"id\":\"lfgkenokasinoinit\",\"type\":\"connection_init\"}");
|
||||
_wsClient?.Send("{\"id\":\"lfgkenokasinoinit\",\"type\":\"connection_init\"}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class Jackpot : IDisposable
|
||||
if (packet.Type == "connection_ack")
|
||||
{
|
||||
_logger.Debug("Received ack from Jackpot. Sending subscription");
|
||||
_wsClient.Send(
|
||||
_wsClient?.Send(
|
||||
"{\"id\":\"lfgkenokasinoallbets\",\"type\":\"subscribe\",\"payload\":{\"feed\":\"all_bets\"}}\n");
|
||||
_logger.Debug("Setting up heartbeat timer");
|
||||
if (_heartbeatTask != null) return;
|
||||
@@ -178,7 +178,7 @@ public class Jackpot : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
_pingCts.Cancel();
|
||||
_pingCts.Dispose();
|
||||
_heartbeatTask?.Dispose();
|
||||
|
||||
@@ -75,7 +75,7 @@ public class KiwiFlare(string kfDomain, string? proxy = null, CancellationToken?
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<KiwiFlareChallengeSolutionModel> ChallengeWorker(KiwiFlareChallengeModel challenge)
|
||||
private Task<KiwiFlareChallengeSolutionModel> ChallengeWorker(KiwiFlareChallengeModel challenge)
|
||||
{
|
||||
var nonce = _random.NextInt64();
|
||||
while (true)
|
||||
@@ -84,11 +84,11 @@ public class KiwiFlare(string kfDomain, string? proxy = null, CancellationToken?
|
||||
var input = Encoding.UTF8.GetBytes($"{challenge.Salt}{nonce}");
|
||||
if (!TestHash(SHA256.HashData(input), challenge.Difficulty)) continue;
|
||||
_logger.Debug($"Hash passed the test, nonce: {nonce}");
|
||||
return new KiwiFlareChallengeSolutionModel
|
||||
return Task.FromResult(new KiwiFlareChallengeSolutionModel
|
||||
{
|
||||
Nonce = nonce,
|
||||
Salt = challenge.Salt
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ public class Rainbet : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
public delegate void OnRainbetBetEventHandler(object sender, List<RainbetBetHistoryModel> bets);
|
||||
public event OnRainbetBetEventHandler OnRainbetBet;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnRainbetBetEventHandler? OnRainbetBet;
|
||||
private CancellationToken _cancellationToken;
|
||||
private CancellationTokenSource _gameHistoryCts = new();
|
||||
private Task? _gameHistoryTask;
|
||||
private TimeSpan _gameHistoryInterval = TimeSpan.FromSeconds(60);
|
||||
@@ -20,9 +20,9 @@ public class Rainbet : IDisposable
|
||||
private string? _userAgent = null;
|
||||
public DateTimeOffset LastSuccessfulRefresh = DateTimeOffset.MinValue;
|
||||
|
||||
public Rainbet(CancellationToken? cancellationToken = null)
|
||||
public Rainbet(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Rainbet client created");
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ public class Rainbet : IDisposable
|
||||
throw new Exception("Cloudflare challenged");
|
||||
}
|
||||
var bets = await response.Content.ReadFromJsonAsync<List<RainbetBetHistoryModel>>(cancellationToken: _cancellationToken);
|
||||
if (bets == null) throw new Exception("Caught a null when deserializing Rainbet bet history");
|
||||
return bets;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,16 +18,16 @@ public class RainbetWs : IDisposable
|
||||
private string? _proxy;
|
||||
public delegate void OnRainbetBetEventHandler(object sender, RainbetWsBetModel bet);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnRainbetBetEventHandler OnRainbetBet;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
private IEnumerable<string>? _cookies = null;
|
||||
private string? _userAgent = null;
|
||||
public event OnRainbetBetEventHandler? OnRainbetBet;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
private IEnumerable<string>? _cookies;
|
||||
private string? _userAgent;
|
||||
|
||||
public RainbetWs(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public RainbetWs(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Rainbet WebSocket client created");
|
||||
}
|
||||
|
||||
@@ -101,14 +101,14 @@ public class RainbetWs : IDisposable
|
||||
{
|
||||
// 0{"sid":"Pf940zhaAqb6BHBiSgLa","upgrades":[],"pingInterval":25000,"pingTimeout":20000,"maxPayload":100000000}
|
||||
_logger.Info("Received initial connection message from Rainbet, sending subscribe");
|
||||
_wsClient.Send("40/game-history,{}");
|
||||
_wsClient?.Send("40/game-history,{}");
|
||||
return;
|
||||
}
|
||||
var packetType = message.Text.Split('/')[0];
|
||||
if (packetType == "2")
|
||||
{
|
||||
_logger.Info("Received ping from Rainbet, replying with pong");
|
||||
_wsClient.Send("3");
|
||||
_wsClient?.Send("3");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,14 +124,14 @@ public class RainbetWs : IDisposable
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<List<JsonElement>>(message.Text.Replace("42/game-history,",
|
||||
string.Empty));
|
||||
if (data == null) throw new Exception("Caught a null when deserializing game history");
|
||||
if (data[0].GetString() == "new-history")
|
||||
{
|
||||
OnRainbetBet?.Invoke(this, data[1].Deserialize<RainbetWsBetModel>());
|
||||
OnRainbetBet?.Invoke(this, data[1].Deserialize<RainbetWsBetModel>()!);
|
||||
return;
|
||||
}
|
||||
_logger.Info($"Event {data[0].GetString()} from Rainbet was not handled");
|
||||
_logger.Info(message.Text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -11,22 +11,22 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Shuffle : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://shuffle.com/main-api/bp-subscription/subscription/graphql");
|
||||
private int _reconnectTimeout = 60;
|
||||
private string? _proxy;
|
||||
public delegate void OnLatestBetUpdatedEventHandler(object sender, ShuffleLatestBetModel bet);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnLatestBetUpdatedEventHandler OnLatestBetUpdated;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnLatestBetUpdatedEventHandler? OnLatestBetUpdated;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
private CancellationTokenSource _pingCts = new();
|
||||
private Task _pingTask;
|
||||
|
||||
public Shuffle(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Shuffle(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
// Moved it up here as I'm concerned about the possibility of reconnections creating multiple ping tasks
|
||||
_pingTask = PeriodicPing();
|
||||
}
|
||||
@@ -103,7 +103,7 @@ public class Shuffle : IDisposable
|
||||
var initPayload =
|
||||
"{\"type\":\"connection_init\",\"payload\":{\"x-correlation-id\":\"pdvlnd9tej-di27abvq19-1.30.2-1i0nef1m7-g::anon\",\"authorization\":\"\"}}";
|
||||
_logger.Debug(initPayload);
|
||||
_wsClient.Send(initPayload);
|
||||
_wsClient?.Send(initPayload);
|
||||
}
|
||||
|
||||
private void WsMessageReceived(ResponseMessage message)
|
||||
@@ -128,7 +128,7 @@ public class Shuffle : IDisposable
|
||||
var payload = "{\"id\":\"" + Guid.NewGuid() +
|
||||
"\",\"type\":\"subscribe\",\"payload\":{\"variables\":{},\"extensions\":{},\"operationName\":\"LatestBetUpdated\",\"query\":\"subscription LatestBetUpdated {\\n latestBetUpdated {\\n ...BetActivityFields\\n __typename\\n }\\n}\\n\\nfragment BetActivityFields on BetActivityPayload {\\n id\\n username\\n vipLevel\\n currency\\n amount\\n payout\\n multiplier\\n gameName\\n gameCategory\\n gameSlug\\n __typename\\n}\"}}";
|
||||
_logger.Debug(payload);
|
||||
_wsClient.SendInstant(payload).Wait(_cancellationToken);
|
||||
_wsClient?.SendInstant(payload).Wait(_cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ public class Shuffle : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
// Rare bug but has happened at least once
|
||||
try
|
||||
{
|
||||
|
||||
@@ -12,15 +12,17 @@ public class ThreeXplPocketWatch
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private string _3xplToken = "3A0_t3st3xplor3rpub11cb3t4efcd21748a5e";
|
||||
private string? _proxy;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
private CancellationToken _cancellationToken;
|
||||
public delegate void OnPocketWatchEventHandler(object sender, PocketWatchTransactionDbModel e);
|
||||
public event OnPocketWatchEventHandler OnPocketWatchEvent;
|
||||
#pragma warning disable CS0067 // Event is never used
|
||||
public event OnPocketWatchEventHandler? OnPocketWatchEvent;
|
||||
#pragma warning restore CS0067 // Event is never used
|
||||
|
||||
public ThreeXplPocketWatch(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public ThreeXplPocketWatch(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_logger.Info("Starting the pocket watch");
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
private async Task CheckAddress(PocketWatchAddressDbModel addy)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Twitch : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://pubsub-edge.twitch.tv/v1");
|
||||
private int _reconnectTimeout = 300;
|
||||
private string? _proxy;
|
||||
@@ -19,18 +19,18 @@ public class Twitch : IDisposable
|
||||
public delegate void OnStreamStateUpdateEventHandler(object sender, int channelId, bool isLive);
|
||||
public delegate void OnStreamCommercialEventHandler(object sender, int channelId, int length, bool scheduled);
|
||||
public delegate void OnStreamTosStrikeEventHandler(object sender, int channelId);
|
||||
public event OnStreamStateUpdateEventHandler OnStreamStateUpdated;
|
||||
public event OnStreamCommercialEventHandler OnStreamCommercial;
|
||||
public event OnStreamTosStrikeEventHandler OnStreamTosStrike;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
private Task? _pingTask = null;
|
||||
public event OnStreamStateUpdateEventHandler? OnStreamStateUpdated;
|
||||
public event OnStreamCommercialEventHandler? OnStreamCommercial;
|
||||
public event OnStreamTosStrikeEventHandler? OnStreamTosStrike;
|
||||
private CancellationToken _cancellationToken;
|
||||
private Task? _pingTask;
|
||||
private CancellationTokenSource _pingCts = new();
|
||||
|
||||
public Twitch(List<int> channels, string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Twitch(List<int> channels, string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
_channels = channels;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
public async Task StartWsClient()
|
||||
@@ -77,7 +77,7 @@ public class Twitch : IDisposable
|
||||
private void SendPing()
|
||||
{
|
||||
_logger.Info("Sending ping to Twitch");
|
||||
_wsClient.Send("{\"type\":\"PING\"}");
|
||||
_wsClient?.Send("{\"type\":\"PING\"}");
|
||||
}
|
||||
|
||||
private async Task PeriodicPing()
|
||||
@@ -107,7 +107,7 @@ public class Twitch : IDisposable
|
||||
Guid.NewGuid() + "\",\"type\":\"LISTEN\"}";
|
||||
_logger.Debug("Sending the following JSON to Twitch");
|
||||
_logger.Debug(payload);
|
||||
_wsClient.Send(payload);
|
||||
_wsClient?.Send(payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,13 +131,13 @@ public class Twitch : IDisposable
|
||||
var packet = JsonSerializer.Deserialize<JsonElement>(message.Text);
|
||||
if (packet.GetProperty("type").GetString() != "MESSAGE")
|
||||
return;
|
||||
var data = packet.GetProperty("data")!;
|
||||
var topicString = data.GetProperty("topic")!.GetString()!;
|
||||
var data = packet.GetProperty("data");
|
||||
var topicString = data.GetProperty("topic").GetString()!;
|
||||
if (!topicString.StartsWith("video-playback-by-id."))
|
||||
return;
|
||||
var topicParts = topicString.Split('.');
|
||||
var channelId = int.Parse(topicParts[^1]);
|
||||
var twitchMessage = JsonSerializer.Deserialize<JsonElement>(data.GetProperty("message").GetString());
|
||||
var twitchMessage = JsonSerializer.Deserialize<JsonElement>(data.GetProperty("message").GetString()!);
|
||||
|
||||
if (twitchMessage.GetProperty("type").GetString() == "stream-up")
|
||||
{
|
||||
@@ -242,7 +242,7 @@ public class Twitch : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
_pingCts.Cancel();
|
||||
_pingCts.Dispose();
|
||||
_pingTask?.Dispose();
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace KfChatDotNetBot.Services;
|
||||
public class TwitchChat : IDisposable
|
||||
{
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private readonly Uri _wsUri = new("wss://irc-ws.chat.twitch.tv/");
|
||||
private const int ReconnectTimeout = 600;
|
||||
private readonly string? _proxy;
|
||||
@@ -19,15 +19,15 @@ public class TwitchChat : IDisposable
|
||||
|
||||
public delegate void MessageReceivedEventHandler(object sender, string nick, string target, string message);
|
||||
public delegate void WsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event MessageReceivedEventHandler OnMessageReceived;
|
||||
public event WsDisconnectionEventHandler OnWsDisconnection;
|
||||
public event MessageReceivedEventHandler? OnMessageReceived;
|
||||
public event WsDisconnectionEventHandler? OnWsDisconnection;
|
||||
|
||||
private readonly CancellationToken _cancellationToken = CancellationToken.None;
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
|
||||
public TwitchChat(string channel, string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public TwitchChat(string channel, string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_channel = channel;
|
||||
var justinFan = new Random().Next(10000, 99999);
|
||||
_nick = $"justinfan{justinFan}";
|
||||
@@ -87,13 +87,13 @@ public class TwitchChat : IDisposable
|
||||
_logger.Error($"Websocket connection dropped and reconnected. Reconnection type is {reconnectionInfo.Type}");
|
||||
_logger.Info("Sending registration info to Twitch IRC");
|
||||
// I've found if you use the message queue then things come out of order, hence using SendInstant
|
||||
_wsClient.SendInstant("CAP REQ :twitch.tv/tags twitch.tv/commands").Wait(_cancellationToken);
|
||||
_wsClient?.SendInstant("CAP REQ :twitch.tv/tags twitch.tv/commands").Wait(_cancellationToken);
|
||||
// Would be an oauth token if you were signed in, but this is just guest access
|
||||
_wsClient.SendInstant("PASS SCHMOOPIIE").Wait(_cancellationToken);
|
||||
_wsClient?.SendInstant("PASS SCHMOOPIIE").Wait(_cancellationToken);
|
||||
// Guest users are just justinfan12345 where the 5 digits are random
|
||||
_wsClient.SendInstant($"NICK {_nick}").Wait(_cancellationToken);
|
||||
_wsClient?.SendInstant($"NICK {_nick}").Wait(_cancellationToken);
|
||||
// I'm ashamed I've forgotten so much IRC protocol shit that I can't remember what the USER params mean :(
|
||||
_wsClient.SendInstant($"USER {_nick} 8 * :{_nick}").Wait(_cancellationToken);
|
||||
_wsClient?.SendInstant($"USER {_nick} 8 * :{_nick}").Wait(_cancellationToken);
|
||||
}
|
||||
|
||||
private void WsMessageReceived(ResponseMessage message)
|
||||
@@ -147,7 +147,7 @@ public class TwitchChat : IDisposable
|
||||
{
|
||||
case "PING":
|
||||
_logger.Info("Received PING, sending PONG");
|
||||
_wsClient.Send("PONG");
|
||||
_wsClient?.Send("PONG");
|
||||
return;
|
||||
case "JOIN":
|
||||
_logger.Debug("Received JOIN response");
|
||||
@@ -155,7 +155,7 @@ public class TwitchChat : IDisposable
|
||||
// MOTD
|
||||
case "001":
|
||||
_logger.Debug("Received MOTD. Sending JOIN");
|
||||
_wsClient.Send($"JOIN {_channel}");
|
||||
_wsClient?.Send($"JOIN {_channel}");
|
||||
return;
|
||||
default:
|
||||
_logger.Debug($"Command {command} was not handled");
|
||||
@@ -174,7 +174,7 @@ public class TwitchChat : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -10,22 +10,22 @@ namespace KfChatDotNetBot.Services;
|
||||
public class Yeet : IDisposable
|
||||
{
|
||||
private Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private WebsocketClient _wsClient;
|
||||
private WebsocketClient? _wsClient;
|
||||
private Uri _wsUri = new("wss://api.yeet.com/room-service/socket/?EIO=4&transport=websocket");
|
||||
private int _reconnectTimeout = 30;
|
||||
private string? _proxy;
|
||||
public delegate void OnYeetBetEventHandler(object sender, YeetCasinoBetModel data);
|
||||
public delegate void OnYeetWinEventHandler(object sender, YeetCasinoWinModel data);
|
||||
public delegate void OnWsDisconnectionEventHandler(object sender, DisconnectionInfo e);
|
||||
public event OnYeetBetEventHandler OnYeetBet;
|
||||
public event OnYeetWinEventHandler OnYeetWin;
|
||||
public event OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken = CancellationToken.None;
|
||||
public event OnYeetBetEventHandler? OnYeetBet;
|
||||
public event OnYeetWinEventHandler? OnYeetWin;
|
||||
public event OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
private CancellationToken _cancellationToken;
|
||||
|
||||
public Yeet(string? proxy = null, CancellationToken? cancellationToken = null)
|
||||
public Yeet(string? proxy = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
_proxy = proxy;
|
||||
if (cancellationToken != null) _cancellationToken = cancellationToken.Value;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger.Info("Yeet WebSocket client created");
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class Yeet : IDisposable
|
||||
if (reconnectionInfo.Type == ReconnectionType.Initial)
|
||||
{
|
||||
_logger.Info("Sending subscribe payload to Yeet");
|
||||
_wsClient.Send("40/public,");
|
||||
_wsClient?.Send("40/public,");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class Yeet : IDisposable
|
||||
if (packetType == "2")
|
||||
{
|
||||
_logger.Info("Received ping from Yeet, replying with pong");
|
||||
_wsClient.Send("3");
|
||||
_wsClient?.Send("3");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,14 +112,15 @@ public class Yeet : IDisposable
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<List<JsonElement>>(message.Text.Replace("42/public,",
|
||||
string.Empty));
|
||||
if (data == null) throw new Exception("Caught a null when deserializing the Yeet bet payload");
|
||||
if (data[0].GetString() == "casino-bet")
|
||||
{
|
||||
OnYeetBet?.Invoke(this, data[1].Deserialize<YeetCasinoBetModel>());
|
||||
OnYeetBet?.Invoke(this, data[1].Deserialize<YeetCasinoBetModel>()!);
|
||||
return;
|
||||
}
|
||||
if (data[0].GetString() == "casino-win")
|
||||
{
|
||||
OnYeetWin?.Invoke(this, data[1].Deserialize<YeetCasinoWinModel>());
|
||||
OnYeetWin?.Invoke(this, data[1].Deserialize<YeetCasinoWinModel>()!);
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -146,7 +147,7 @@ public class Yeet : IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_wsClient.Dispose();
|
||||
_wsClient?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@ public static class SettingsProvider
|
||||
if (!bypassCache && cache.Contains(key))
|
||||
{
|
||||
var cachedSetting = cache.Get(key) as SettingDbModel;
|
||||
if (cachedSetting == null)
|
||||
{
|
||||
logger.Error($"Caught a null in spite of the cache supposedly containing {key}");
|
||||
throw new Exception("Cached Setting entry was null");
|
||||
}
|
||||
var value = cachedSetting.Value;
|
||||
if (cachedSetting.Value == "null") value = null;
|
||||
return new Setting(value, cachedSetting, true);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text.Json;
|
||||
using System.Xml;
|
||||
using KfChatDotNetWsClient.Models;
|
||||
using KfChatDotNetWsClient.Models.Events;
|
||||
using KfChatDotNetWsClient.Models.Json;
|
||||
@@ -14,15 +13,15 @@ namespace KfChatDotNetWsClient;
|
||||
|
||||
public class ChatClient
|
||||
{
|
||||
public event EventHandlers.OnMessagesEventHandler OnMessages;
|
||||
public event EventHandlers.OnUsersPartedEventHandler OnUsersParted;
|
||||
public event EventHandlers.OnUsersJoinedEventHandler OnUsersJoined;
|
||||
public event EventHandlers.OnWsReconnectEventHandler OnWsReconnect;
|
||||
public event EventHandlers.OnDeleteMessagesEventHandler OnDeleteMessages;
|
||||
public event EventHandlers.OnWsDisconnectionEventHandler OnWsDisconnection;
|
||||
public event EventHandlers.OnFailedToJoinRoom OnFailedToJoinRoom;
|
||||
public event EventHandlers.OnUnknownCommand OnUnknownCommand;
|
||||
private WebsocketClient _wsClient;
|
||||
public event EventHandlers.OnMessagesEventHandler? OnMessages;
|
||||
public event EventHandlers.OnUsersPartedEventHandler? OnUsersParted;
|
||||
public event EventHandlers.OnUsersJoinedEventHandler? OnUsersJoined;
|
||||
public event EventHandlers.OnWsReconnectEventHandler? OnWsReconnect;
|
||||
public event EventHandlers.OnDeleteMessagesEventHandler? OnDeleteMessages;
|
||||
public event EventHandlers.OnWsDisconnectionEventHandler? OnWsDisconnection;
|
||||
public event EventHandlers.OnFailedToJoinRoom? OnFailedToJoinRoom;
|
||||
public event EventHandlers.OnUnknownCommand? OnUnknownCommand;
|
||||
private WebsocketClient? _wsClient;
|
||||
private readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
private ChatClientConfigModel _config;
|
||||
public DateTime LastPacketReceived = DateTime.UtcNow;
|
||||
@@ -49,6 +48,7 @@ public class ChatClient
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
_wsClient.Stop(WebSocketCloseStatus.NormalClosure, "Closing websocket").Wait();
|
||||
}
|
||||
|
||||
@@ -57,11 +57,13 @@ public class ChatClient
|
||||
// none for reconnect.
|
||||
public async Task DisconnectAsync()
|
||||
{
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
await _wsClient.Stop(WebSocketCloseStatus.NormalClosure, "Closing websocket");
|
||||
}
|
||||
|
||||
public async Task Reconnect()
|
||||
{
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
await _wsClient.Reconnect();
|
||||
}
|
||||
|
||||
@@ -144,7 +146,7 @@ public class ChatClient
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<string, object> packetType = new Dictionary<string, object>();
|
||||
Dictionary<string, object> packetType;
|
||||
try
|
||||
{
|
||||
packetType = JsonSerializer.Deserialize<Dictionary<string, object>>(message.Text)!;
|
||||
@@ -193,30 +195,35 @@ public class ChatClient
|
||||
public void JoinRoom(int roomId)
|
||||
{
|
||||
_logger.Debug($"Joining {roomId}");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
_wsClient.Send($"/join {roomId}");
|
||||
}
|
||||
|
||||
public void SendMessage(string message)
|
||||
{
|
||||
_logger.Debug($"Sending '{message}'");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
_wsClient.Send(message);
|
||||
}
|
||||
|
||||
public async Task SendMessageInstantAsync(string message)
|
||||
{
|
||||
_logger.Debug($"Sending '{message}', bypassing the queue");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
await _wsClient.SendInstant(message);
|
||||
}
|
||||
|
||||
public void DeleteMessage(int messageId)
|
||||
{
|
||||
_logger.Debug($"Deleting {messageId}");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
_wsClient.Send($"/delete {messageId}");
|
||||
}
|
||||
|
||||
public async Task DeleteMessageAsync(int messageId)
|
||||
{
|
||||
_logger.Debug($"Deleting {messageId}");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
await _wsClient.SendInstant($"/delete {messageId}");
|
||||
}
|
||||
|
||||
@@ -224,6 +231,7 @@ public class ChatClient
|
||||
{
|
||||
var payload = JsonSerializer.Serialize(new EditMessageJsonModel {Id = messageId, Message = newMessage});
|
||||
_logger.Debug($"Editing {messageId} with '{newMessage}'");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
_wsClient.Send($"/edit {payload}");
|
||||
}
|
||||
|
||||
@@ -231,21 +239,22 @@ public class ChatClient
|
||||
{
|
||||
var payload = JsonSerializer.Serialize(new EditMessageJsonModel {Id = messageId, Message = newMessage});
|
||||
_logger.Debug($"Editing {messageId} with '{newMessage}'");
|
||||
if (_wsClient == null) throw new WebSocketNotInitializedException();
|
||||
await _wsClient.SendInstant($"/edit {payload}");
|
||||
}
|
||||
|
||||
private void WsDeleteMessagesReceived(ResponseMessage message)
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<DeleteMessagesJsonModel>(message.Text);
|
||||
_logger.Debug($"Received delete packet for messages: {string.Join(',', data.MessageIdsToDelete)}");
|
||||
var data = JsonSerializer.Deserialize<DeleteMessagesJsonModel>(message.Text!);
|
||||
_logger.Debug($"Received delete packet for messages: {string.Join(',', data!.MessageIdsToDelete)}");
|
||||
OnDeleteMessages?.Invoke(this, data.MessageIdsToDelete);
|
||||
}
|
||||
|
||||
private void WsChatMessagesReceived(ResponseMessage message)
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<MessagesJsonModel>(message.Text);
|
||||
var data = JsonSerializer.Deserialize<MessagesJsonModel>(message.Text!);
|
||||
var messages = new List<MessageModel>();
|
||||
foreach (var chatMessage in data.Messages)
|
||||
foreach (var chatMessage in data!.Messages)
|
||||
{
|
||||
var model = new MessageModel
|
||||
{
|
||||
@@ -260,10 +269,12 @@ public class ChatClient
|
||||
Message = chatMessage.Message,
|
||||
MessageId = chatMessage.MessageId,
|
||||
MessageRaw = chatMessage.MessageRaw,
|
||||
RoomId = chatMessage.RoomId
|
||||
RoomId = chatMessage.RoomId,
|
||||
MessageRawHtmlDecoded = WebUtility.HtmlDecode(chatMessage.MessageRaw),
|
||||
MessageDate = DateTimeOffset.FromUnixTimeSeconds(chatMessage.MessageDate)
|
||||
};
|
||||
|
||||
if(chatMessage.MessageEditDate == 0)
|
||||
if (chatMessage.MessageEditDate == 0)
|
||||
{
|
||||
model.MessageEditDate = null;
|
||||
}
|
||||
@@ -272,8 +283,6 @@ public class ChatClient
|
||||
model.MessageEditDate = DateTimeOffset.FromUnixTimeSeconds(chatMessage.MessageEditDate);
|
||||
}
|
||||
|
||||
model.MessageDate = DateTimeOffset.FromUnixTimeSeconds(chatMessage.MessageDate);
|
||||
|
||||
messages.Add(model);
|
||||
}
|
||||
_logger.Debug($"Received {messages.Count} chat messages");
|
||||
@@ -286,9 +295,9 @@ public class ChatClient
|
||||
|
||||
private void WsChatUsersJoined(ResponseMessage message)
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<UsersJsonModel>(message.Text);
|
||||
var data = JsonSerializer.Deserialize<UsersJsonModel>(message.Text!);
|
||||
var users = new List<UserModel>();
|
||||
foreach (var user in data.Users.Keys)
|
||||
foreach (var user in data!.Users.Keys)
|
||||
{
|
||||
users.Add(new UserModel
|
||||
{
|
||||
@@ -306,9 +315,11 @@ public class ChatClient
|
||||
private void WsChatUsersParted(ResponseMessage message)
|
||||
{
|
||||
// {"user":{"1337":false}}
|
||||
var data = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, bool>>>(message.Text);
|
||||
var data = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, bool>>>(message.Text!);
|
||||
var usersParted = data!["user"].Select(user => int.Parse(user.Key)).ToList();
|
||||
_logger.Debug($"Following users have parted: {string.Join(',', usersParted)}");
|
||||
OnUsersParted?.Invoke(this, usersParted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class WebSocketNotInitializedException : Exception;
|
||||
@@ -5,7 +5,7 @@ public class ChatClientConfigModel
|
||||
// XF session token. Sent as a cookie to auth the user
|
||||
public string? XfSessionToken { get; set; }
|
||||
// Currently wss://kiwifarms.net/chat.ws
|
||||
public Uri WsUri { get; set; }
|
||||
public required Uri WsUri { get; set; }
|
||||
public int ReconnectTimeout { get; set; } = 30;
|
||||
public string CookieDomain { get; set; } = "kiwifarms.net";
|
||||
public string? Proxy { get; set; }
|
||||
|
||||
@@ -2,17 +2,21 @@ namespace KfChatDotNetWsClient.Models.Events;
|
||||
|
||||
public class MessageModel
|
||||
{
|
||||
public UserModel Author { get; set; }
|
||||
public required UserModel Author { get; set; }
|
||||
/// <summary>
|
||||
/// HTML formatted message
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
public int MessageId { get; set; }
|
||||
public required string Message { get; set; }
|
||||
public required int MessageId { get; set; }
|
||||
public DateTimeOffset? MessageEditDate { get; set; }
|
||||
public DateTimeOffset MessageDate { get; set; }
|
||||
public required DateTimeOffset MessageDate { get; set; }
|
||||
/// <summary>
|
||||
/// Unformatted message with original BB code
|
||||
/// Unformatted message with original BB code but retaining HTML encoding
|
||||
/// </summary>
|
||||
public string MessageRaw { get; set; }
|
||||
public int RoomId { get; set; }
|
||||
public required string MessageRaw { get; set; }
|
||||
public required int RoomId { get; set; }
|
||||
/// <summary>
|
||||
/// Unformatted message with original BB code and HTML entities decoded
|
||||
/// </summary>
|
||||
public required string MessageRawHtmlDecoded { get; set; }
|
||||
}
|
||||
@@ -6,8 +6,8 @@ public class UserModel
|
||||
/// <summary>
|
||||
/// Forum display name. Note that it'll be HTML encoded
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
public Uri AvatarUrl { get; set; }
|
||||
public required string Username { get; set; }
|
||||
public Uri? AvatarUrl { get; set; }
|
||||
// Unset if it's related to a chat message
|
||||
public DateTimeOffset? LastActivity { get; set; }
|
||||
}
|
||||
@@ -5,5 +5,5 @@ namespace KfChatDotNetWsClient.Models.Json;
|
||||
public class DeleteMessagesJsonModel
|
||||
{
|
||||
[JsonPropertyName("delete")]
|
||||
public List<int> MessageIdsToDelete { get; set; }
|
||||
public required List<int> MessageIdsToDelete { get; set; }
|
||||
}
|
||||
@@ -5,8 +5,8 @@ namespace KfChatDotNetWsClient.Models.Json;
|
||||
public class EditMessageJsonModel
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
public required int Id { get; set; }
|
||||
|
||||
[JsonPropertyName("message")]
|
||||
public string Message { get; set; }
|
||||
public required string Message { get; set; }
|
||||
}
|
||||
@@ -30,17 +30,17 @@ public class MessagesJsonModel
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
[JsonPropertyName("username")]
|
||||
public string Username { get; set; }
|
||||
public required string Username { get; set; }
|
||||
[JsonPropertyName("avatar_url")]
|
||||
public Uri AvatarUrl { get; set; }
|
||||
public Uri? AvatarUrl { get; set; }
|
||||
}
|
||||
|
||||
public class MessageModel
|
||||
{
|
||||
[JsonPropertyName("author")]
|
||||
public AuthorModel Author { get; set; }
|
||||
public required AuthorModel Author { get; set; }
|
||||
[JsonPropertyName("message")]
|
||||
public string Message { get; set; }
|
||||
public required string Message { get; set; }
|
||||
[JsonPropertyName("message_id")]
|
||||
public int MessageId { get; set; }
|
||||
[JsonPropertyName("message_edit_date")]
|
||||
@@ -48,11 +48,10 @@ public class MessagesJsonModel
|
||||
[JsonPropertyName("message_date")]
|
||||
public int MessageDate { get; set; }
|
||||
[JsonPropertyName("message_raw")]
|
||||
public string MessageRaw { get; set; }
|
||||
public required string MessageRaw { get; set; }
|
||||
[JsonPropertyName("room_id")]
|
||||
public int RoomId { get; set; }
|
||||
}
|
||||
|
||||
[JsonPropertyName("messages")]
|
||||
public List<MessageModel> Messages { get; set; }
|
||||
|
||||
[JsonPropertyName("messages")] public List<MessageModel> Messages { get; set; } = [];
|
||||
}
|
||||
@@ -19,13 +19,13 @@ public class UsersJsonModel
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
[JsonPropertyName("username")]
|
||||
public string Username { get; set; }
|
||||
public required string Username { get; set; }
|
||||
[JsonPropertyName("avatar_url")]
|
||||
public Uri AvatarUrl { get; set; }
|
||||
public Uri? AvatarUrl { get; set; }
|
||||
[JsonPropertyName("last_activity")]
|
||||
public int LastActivity { get; set; }
|
||||
}
|
||||
|
||||
|
||||
[JsonPropertyName("users")]
|
||||
public Dictionary<string, UserModel> Users { get; set; }
|
||||
public Dictionary<string, UserModel> Users { get; set; } = new();
|
||||
}
|
||||
Reference in New Issue
Block a user