Skip to content

Commit

Permalink
修复bc命令, 添加服务器可用性测试命令
Browse files Browse the repository at this point in the history
  • Loading branch information
Megghy committed Jan 22, 2022
1 parent d88d2f3 commit 2546b5b
Show file tree
Hide file tree
Showing 15 changed files with 255 additions and 69 deletions.
4 changes: 2 additions & 2 deletions MultiSEngine/Core/Adapter/BaseAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public BaseAdapter(ClientData client, Socket connection)
{
Client = client;
Connection = connection;
NetReader = new BinaryReader(new NetworkStream(Connection));
}
#region 变量
public int ErrorCount { get; protected set; } = 0;
Expand All @@ -46,6 +45,7 @@ public BaseAdapter(ClientData client, Socket connection)
public abstract void SendPacket(Packet packet);
public virtual BaseAdapter Start()
{
NetReader = new BinaryReader(new NetworkStream(Connection));
Task.Run(RecieveLoop);
Task.Run(ProcessPacketLoop);
return this;
Expand All @@ -56,7 +56,7 @@ public virtual void Stop(bool disposeConnection = false)
Logs.Warn($"[{GetType()}] <{Connection?.RemoteEndPoint}> Stopped");
#endif
ShouldStop = true;
Client.TimeOutTimer?.Stop();
Client?.TimeOutTimer?.Stop();
if (disposeConnection)
{
try { Connection?.Shutdown(SocketShutdown.Both); } catch { }
Expand Down
6 changes: 2 additions & 4 deletions MultiSEngine/Core/Adapter/ClientAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using TrProtocol;
using TrProtocol.Packets;

Expand All @@ -14,8 +15,6 @@ public class ClientAdapter : BaseAdapter
{
public ClientAdapter(ClientData client, Socket connection) : base(client, connection)
{
client.IP = (Connection.RemoteEndPoint as IPEndPoint)?.Address.ToString();
client.Port = (Connection.RemoteEndPoint as IPEndPoint)?.Port ?? -1;
}
protected override void OnRecieveLoopError(Exception ex)
{
Expand All @@ -34,7 +33,7 @@ public override bool GetPacket(Packet packet)
if (Config.Instance.DefaultServerInternal is { })
{
Client.ReadVersion(hello);
Client.Join(Config.Instance.DefaultServerInternal);
Task.Run(() => Client.Join(Config.Instance.DefaultServerInternal));
}
else
Client.Disconnect("No default server is set for the current server.");
Expand Down Expand Up @@ -83,7 +82,6 @@ public override bool GetPacket(Packet packet)
}
public override void SendPacket(Packet packet)
{
//bool shouldSerializeLikeClient = packet.GetType().GetProperties().Any(p => p.GetCustomAttributes(true)?.Any(a => a.GetType() == typeof(S2COnlyAttribute)) ?? false);
if (!ShouldStop)
Client.SendDataToServer(packet);
}
Expand Down
109 changes: 109 additions & 0 deletions MultiSEngine/Core/Adapter/TestAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using MultiSEngine.DataStruct;
using MultiSEngine.Modules;
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using TrProtocol;
using TrProtocol.Packets;

namespace MultiSEngine.Core.Adapter
{
internal class TestAdapter : ClientAdapter, IDisposable
{
public TestAdapter(ServerInfo server, bool showDetails) : base(null, new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
this.server = server;
ShowDetails = showDetails;
}
private bool ShowDetails { get; init; }
public int State { get; private set; } = 0;
public bool? IsSuccess { get; private set; }
public ServerInfo server { get; private set; }
private void Log(string msg, bool isDetail = true, ConsoleColor color = ConsoleColor.Blue)
{
if (isDetail && !ShowDetails)
return;
Logs.LogAndSave(msg, $"[TEST] <{server.Name}> {(IsSuccess.HasValue ? ((bool)IsSuccess) ? "SUCCESS" : "FAILED" : "TESTING")}: {State} -", color, false);
}
public override BaseAdapter Start()
{
Task.Run(StartTest);
return this;
}
private async Task StartTest()
{
Log($"Start connecting to [{server.Name}]<{server.IP}:{server.Port}>");
await Connection.ConnectAsync(server.IP, server.Port);
base.Start();
State = 1;
Log($"Sending [ConnectRequest] packet");
InternalSendPacket(new ClientHello()
{
Version = $"Terraria{server.VersionNum}"
}); //发起连接请求
}
protected override void OnRecieveLoopError(Exception ex)
{
throw ex;
}
public override bool GetPacket(Packet packet)
{
switch (packet)
{
case Kick kick:
var reason = kick.Reason.GetText();
Stop(true);
IsSuccess = false;
Log($"Kicked. Reason: {(string.IsNullOrEmpty(reason) ? "Unkown" : reason)}", false, ConsoleColor.Red);
break;
case LoadPlayer:
State = 2;
Log($"Sending [PlayerInfo] packet");
InternalSendPacket(new SyncPlayer()
{
Name = "MultiSEngine"
});
Log($"Sending [UUID] packet");
InternalSendPacket(new ClientUUID()
{
UUID = "114514"
});
Log($"Requesting world data");
InternalSendPacket(new RequestWorldInfo() { });
State = 3;
break;
case WorldData:
if (!IsSuccess.HasValue)
{
State = 4;
Log($"Requesting map data");
InternalSendPacket(new RequestTileData()
{
Position = new(-1, -1)
});//请求物块数据
Log($"Requesting spawn player");
InternalSendPacket(new SpawnPlayer()
{
Position = new(-1, -1)
});
}
break;
case RequestPassword:
IsSuccess = false;
Log($"Target server request password", false, ConsoleColor.Red);
break;
case StartPlaying:
State = 10;
IsSuccess = true;
Log($"Server authentication completed, allow client to start running", true, ConsoleColor.Green);
break;
}
return false;
}
public void Dispose()
{
base.Stop(true);
server = null;
}
}
}
32 changes: 18 additions & 14 deletions MultiSEngine/Core/Adapter/VisualPlayerAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@
using MultiSEngine.Modules;
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using TrProtocol;
using TrProtocol.Packets;

namespace MultiSEngine.Core.Adapter
{
public class VisualPlayerAdapter : ServerAdapter, IStatusChangeable
{
public VisualPlayerAdapter(ClientData client, Socket connection) : base(client, connection)
public VisualPlayerAdapter(ClientData client, ServerInfo server) : base(client, new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
TargetServer = server;
}
internal MSEPlayer Player => Client.Player;

internal PlayerInfo Player => Client.Player;
internal bool TestConnecting = false;
internal ServerInfo TempServer;
internal Action<ClientData> Callback;
internal ServerInfo TargetServer;
internal Action<ClientData> SuccessCallback;
public bool RunningAsNormal { get; set; } = false;
public void ChangeProcessState(bool asNormal)
{
Expand All @@ -34,13 +37,14 @@ public override BaseAdapter Start()
/// 如果成功连接的话则调用所给的函数
/// </summary>
/// <param name="successCallback"></param>
public void TryConnect(ServerInfo server, Action<ClientData> successCallback)
public async Task TryConnect(ServerInfo server, Action<ClientData> successCallback)
{
if (TestConnecting)
return;
await Connection.ConnectAsync(server.IP, server.Port);
base.Start();
TempServer = server;
Callback = successCallback;
TargetServer = server;
SuccessCallback = successCallback;
TestConnecting = true;
InternalSendPacket(new ClientHello()
{
Expand All @@ -58,7 +62,7 @@ public override bool GetPacket(Packet packet)
{
case Kick kick:
Stop(true);
Client.SendErrorMessage(Localization.Instance["Prompt_Disconnect", (Client.Server ?? TempServer)?.Name, kick.Reason.GetText()]);
Client.SendErrorMessage(Localization.Instance["Prompt_Disconnect", (Client.Server ?? TargetServer)?.Name, kick.Reason.GetText()]);
Client.State = ClientData.ClientState.Disconnect;
break;
case LoadPlayer slot:
Expand All @@ -84,12 +88,12 @@ public override bool GetPacket(Packet packet)
Client.SendInfoMessage($"SSC: {worldData.EventInfo1[6]}");
#endif
Player.UpdateData(worldData, false);
if (Callback != null)
if (SuccessCallback != null)
{
TestConnecting = false;
Callback?.Invoke(Client);
Callback = null;
Client.Server = TempServer;
SuccessCallback?.Invoke(Client);
SuccessCallback = null;
Client.Server = TargetServer;
}
InternalSendPacket(new RequestTileData() { Position = new(Client.SpawnX, Client.SpawnY) });//请求物块数据
InternalSendPacket(new SpawnPlayer() { Position = new(Client.SpawnX, Client.SpawnY) });//请求物块数据
Expand All @@ -102,12 +106,12 @@ public override bool GetPacket(Packet packet)
return false;
if (Client.State == ClientData.ClientState.RequestPassword)
{
Client.SendInfoMessage(Localization.Instance["Prompt_WrongPassword", TempServer.Name, Localization.Get("Help_Password")]);
Client.SendInfoMessage(Localization.Instance["Prompt_WrongPassword", TargetServer.Name, Localization.Get("Help_Password")]);
}
else
{
Client.State = ClientData.ClientState.RequestPassword;
Client.SendInfoMessage(Localization.Instance["Prompt_NeedPassword", TempServer.Name, Localization.Get("Help_Password")]);
Client.SendInfoMessage(Localization.Instance["Prompt_NeedPassword", TargetServer.Name, Localization.Get("Help_Password")]);
}
Client.TimeOutTimer.Stop();
Client.TimeOutTimer.Start();
Expand Down
54 changes: 54 additions & 0 deletions MultiSEngine/Core/Net.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,60 @@ public static void WatchConnecting()
}
}
}
static bool isTesting = false;
internal static void TestAll(bool showDetails = false)
{
Task.Run(() =>
{
Logs.Info($"Ready to start testing all server connectivity");
int successCount = 0;
Config.Instance.Servers.ForEach(s =>
{
if (TestConnect(s, showDetails))
successCount++;
});
Logs.Info($"Test completed. Number of available servers:{successCount}/{Config.Instance.Servers.Count}");
});
}
internal static bool TestConnect(ServerInfo server, bool showDetails = false)
{
return Task.Run(() =>
{
if (isTesting)
{
Logs.Warn($"Now testing other servers, please do so when it finished");
return false;
}
isTesting = true;
try
{
using var tempConnection = new TestAdapter(server, showDetails);
Logs.Info($"Start testing the connectivity of [{server.Name}]");
tempConnection.Start();
long waitTime = 0;
while (Config.Instance.SwitchTimeOut > waitTime)
{
if (tempConnection?.IsSuccess ?? false)
{
isTesting = false;
Logs.Success($"Server [{server.Name}] is in good condition :)");
return true;
}
else
waitTime += 50;
Task.Delay(50).Wait();
}
if (!tempConnection.IsSuccess.HasValue)
Logs.LogAndSave($"Test FAILED: Time out", $"[TEST] <{server.Name}>", ConsoleColor.Red, false);
}
catch (Exception ex)
{
Logs.LogAndSave($"Test FAILED: Unable to connect to {server.IP}:{server.Port}{Environment.NewLine}{ex}", $"[TEST] <{server.Name}>", ConsoleColor.Red, false);
}
isTesting = false;
return false;
}).Result;
}
}

}
23 changes: 9 additions & 14 deletions MultiSEngine/DataStruct/ClientData.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using MultiSEngine.Core.Adapter;
using MultiSEngine.Modules;
using System;
using System.Net;
using System.Net.Sockets;
using System.Timers;

namespace MultiSEngine.DataStruct
{
public class ClientData : IClientAdapter<FakeWorldAdapter>, IServerAdapter<VisualPlayerAdapter>, IDisposable
public class ClientData : IClientAdapter<FakeWorldAdapter>, IServerAdapter<VisualPlayerAdapter>
{
public enum ClientState
{
Expand All @@ -30,14 +31,13 @@ public ClientData()
}
public FakeWorldAdapter CAdapter { get; set; }
public VisualPlayerAdapter SAdapter { get; set; }
internal Socket TempConnection { get; set; }
internal VisualPlayerAdapter TempAdapter { get; set; }
public Timer TimeOutTimer { get; init; }

#region 客户端信息
public ClientState State { get; set; } = ClientState.NewConnection;
public string IP { get; internal set; }
public int Port { get; internal set; }
public string IP => (CAdapter?.Connection?.RemoteEndPoint as IPEndPoint)?.Address?.ToString();
public int Port => (CAdapter?.Connection?.RemoteEndPoint as IPEndPoint)?.Port ?? -1;
public string Address => $"{IP}:{Port}"; public bool Syncing { get; internal set; } = false;
public bool Disposed { get; private set; } = false;
#endregion
Expand All @@ -48,7 +48,7 @@ public ClientData()
public ServerInfo Server { get; set; }
public string Name => Player?.Name ?? Address;
public byte Index => Player?.Index ?? 0;
public MSEPlayer Player { get; private set; } = new();
public PlayerInfo Player { get; private set; } = new();
#endregion

#region 方法
Expand All @@ -57,18 +57,13 @@ protected void OnTimeOut(object sender, ElapsedEventArgs args)
if (State == ClientState.RequestPassword)
this.SendErrorMessage(Localization.Instance["Prompt_PasswordTimeout"]);
else if (State >= ClientState.Switching && State < ClientState.InGame)
this.SendErrorMessage(Localization.Instance["Prompt_CannotConnect", (TempAdapter as VisualPlayerAdapter)?.TempServer?.Name]);
this.SendErrorMessage(Localization.Instance["Prompt_CannotConnect", (TempAdapter as VisualPlayerAdapter)?.TargetServer?.Name]);
State = ClientState.ReadyToSwitch;

if (TempAdapter is VisualPlayerAdapter vpa)
{
Logs.Warn($"[{Name}] timeout when request is switch to: {vpa.TempServer.Name}");
vpa.Callback = null;
}
Logs.Warn($"[{Name}] timeout when request is switch to: {TempAdapter.TargetServer?.Name}");

TempConnection?.Shutdown(SocketShutdown.Both);
TempConnection?.Dispose();
TempConnection = null;
TempAdapter.Stop(true);
TempAdapter = null;
}
public override string ToString()
=> $"{Address}:{Name}_{Player.UUID}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace MultiSEngine.DataStruct
{
public class MSEPlayer
public class PlayerInfo
{
public class PlayerData
{
Expand Down
Loading

0 comments on commit 2546b5b

Please sign in to comment.