diff --git a/SysBot.Base/Connection/Switch/Wireless/SwitchSocketAsync.cs b/SysBot.Base/Connection/Switch/Wireless/SwitchSocketAsync.cs
index cb5dd63..a3aab2a 100644
--- a/SysBot.Base/Connection/Switch/Wireless/SwitchSocketAsync.cs
+++ b/SysBot.Base/Connection/Switch/Wireless/SwitchSocketAsync.cs
@@ -1,6 +1,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
@@ -36,16 +37,35 @@ public override void Connect()
}
Log("Connecting to device...");
- IAsyncResult result = Connection.BeginConnect(Info.IP, Info.Port, null, null);
- bool success = result.AsyncWaitHandle.WaitOne(5000, true);
- if (!success || !Connection.Connected)
+ int retryCount = 0;
+ const int maxRetries = 10;
+
+ while (retryCount < maxRetries)
{
- InitializeSocket();
- throw new Exception("Failed to connect to device.");
+ try
+ {
+ IAsyncResult result = Connection.BeginConnect(Info.IP, Info.Port, null, null);
+ bool success = result.AsyncWaitHandle.WaitOne(5000, true);
+ if (!success || !Connection.Connected)
+ {
+ throw new Exception("Failed to connect to device.");
+ }
+ Connection.EndConnect(result);
+ Log("Connected!");
+ Label = Name;
+ return;
+ }
+ catch (Exception ex)
+ {
+ retryCount++;
+ Log($"Connection attempt {retryCount} failed: {ex.Message}");
+ if (retryCount >= maxRetries)
+ {
+ throw;
+ }
+ Task.Delay(1000 * retryCount).Wait(); // Wait before retrying
+ }
}
- Connection.EndConnect(result);
- Log("Connected!");
- Label = Name;
}
public override void Reset()
@@ -75,19 +95,42 @@ public override void Disconnect()
/// Only call this if you are sending small commands.
public async Task SendAsync(byte[] buffer, CancellationToken token)
{
- return await Connection.SendAsync(buffer, token).AsTask();
+ return await RetryOperation(async (ct) => await Connection.SendAsync(buffer, ct).AsTask(), token);
+ }
+
+ public async Task EnsureConnectedAsync(CancellationToken token)
+ {
+ if (!Connected)
+ {
+ Log("Connection lost. Attempting to reconnect...");
+ await RetryOperation(async (ct) =>
+ {
+ Reset();
+ Connect();
+ return true;
+ }, token);
+ }
}
private async Task ReadBytesFromCmdAsync(byte[] cmd, int length, CancellationToken token)
{
- await SendAsync(cmd, token).ConfigureAwait(false);
- var size = (length * 2) + 1;
- var buffer = ArrayPool.Shared.Rent(size);
- var mem = buffer.AsMemory()[..size];
- await Connection.ReceiveAsync(mem, token);
- var result = DecodeResult(mem, length);
- ArrayPool.Shared.Return(buffer, true);
- return result;
+ return await RetryOperation(async (ct) =>
+ {
+ await EnsureConnectedAsync(ct);
+ await SendAsync(cmd, ct).ConfigureAwait(false);
+ var size = (length * 2) + 1;
+ var buffer = ArrayPool.Shared.Rent(size);
+ try
+ {
+ var mem = buffer.AsMemory()[..size];
+ await Connection.ReceiveAsync(mem, ct);
+ return DecodeResult(mem, length);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(buffer, true);
+ }
+ }, token);
}
private static byte[] DecodeResult(ReadOnlyMemory buffer, int length)
@@ -157,6 +200,7 @@ public async Task IsProgramRunning(ulong pid, CancellationToken token)
private async Task Read(ulong offset, int length, SwitchOffsetType type, CancellationToken token)
{
+ await EnsureConnectedAsync(token);
var method = type.GetReadMethod();
if (length <= MaximumTransferSize)
{
@@ -296,5 +340,40 @@ public async Task GetUnixTime(CancellationToken token)
Array.Reverse(result);
return BitConverter.ToInt64(result, 0);
}
+
+ private void HandleDisconnect()
+ {
+ Log("Unexpected disconnection detected. Attempting to reconnect...");
+ try
+ {
+ Reset();
+ Connect();
+ }
+ catch (Exception ex)
+ {
+ LogError($"Failed to reconnect: {ex.Message}");
+ }
+ }
+
+ private async Task RetryOperation(Func> operation, CancellationToken token, int maxRetries = 3)
+ {
+ int retryCount = 0;
+ while (true)
+ {
+ try
+ {
+ return await operation(token);
+ }
+ catch (Exception ex) when (ex is SocketException or IOException)
+ {
+ if (++retryCount > maxRetries)
+ throw;
+
+ int delay = (int)Math.Pow(2, retryCount) * 1000; // Exponential backoff
+ Log($"Connection error. Retrying in {delay}ms. Attempt {retryCount} of {maxRetries}");
+ await Task.Delay(delay, token);
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/SysBot.Base/SysBot.Base.csproj b/SysBot.Base/SysBot.Base.csproj
index eaaad16..9f68f53 100644
--- a/SysBot.Base/SysBot.Base.csproj
+++ b/SysBot.Base/SysBot.Base.csproj
@@ -4,7 +4,7 @@
Debug;Release;sysbottest
-
+
diff --git a/SysBot.Pokemon.ConsoleApp/SysBot.Pokemon.ConsoleApp.csproj b/SysBot.Pokemon.ConsoleApp/SysBot.Pokemon.ConsoleApp.csproj
index eae0410..031118c 100644
--- a/SysBot.Pokemon.ConsoleApp/SysBot.Pokemon.ConsoleApp.csproj
+++ b/SysBot.Pokemon.ConsoleApp/SysBot.Pokemon.ConsoleApp.csproj
@@ -7,7 +7,7 @@
net8.0
-
+
diff --git a/SysBot.Pokemon.Discord/Commands/Bots/RaidModule.cs b/SysBot.Pokemon.Discord/Commands/Bots/RaidModule.cs
index ad5a788..5d21f84 100644
--- a/SysBot.Pokemon.Discord/Commands/Bots/RaidModule.cs
+++ b/SysBot.Pokemon.Discord/Commands/Bots/RaidModule.cs
@@ -748,7 +748,7 @@ public async Task AddRaidPK([Summary("Showdown Set")][Remainder] string content)
{
raidToUpdate.PartyPK = partyPK;
await Context.Message.DeleteAsync().ConfigureAwait(false);
- var embed = RPEmbed.PokeEmbed(pkm, Context.User.Username);
+ var embed = await RPEmbed.PokeEmbedAsync(pkm, Context.User.Username);
await ReplyAsync(embed: embed).ConfigureAwait(false);
}
else
@@ -795,7 +795,7 @@ public async Task AddRaidPK()
{
raidToUpdate.PartyPK = partyPK;
await Context.Message.DeleteAsync().ConfigureAwait(false);
- var embed = RPEmbed.PokeEmbed(pk, Context.User.Username);
+ var embed = await RPEmbed.PokeEmbedAsync(pk, Context.User.Username);
await ReplyAsync(embed: embed).ConfigureAwait(false);
}
else
diff --git a/SysBot.Pokemon.Discord/Helpers/RPEmbed.cs b/SysBot.Pokemon.Discord/Helpers/RPEmbed.cs
index d765966..ec50248 100644
--- a/SysBot.Pokemon.Discord/Helpers/RPEmbed.cs
+++ b/SysBot.Pokemon.Discord/Helpers/RPEmbed.cs
@@ -1,18 +1,20 @@
using Discord;
using PKHeX.Core;
+using System.Threading.Tasks;
using Color = Discord.Color;
namespace SysBot.Pokemon.Discord.Helpers;
public static class RPEmbed
{
- public static Embed PokeEmbed(PKM pk, string username)
+ public static async Task