Initial commit: Client Doc docs Server Tools

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ud18010
2026-07-10 10:24:29 +08:00
co-authored by Cursor
commit 7e35d8da31
3374 changed files with 680813 additions and 0 deletions
@@ -0,0 +1,82 @@
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Xunit;
using XWorld.Framework.Protocol;
using XWorld.Server.Gateway;
namespace XWorld.Server.Gateway.Tests
{
public class DevDiscoveryResponderTests
{
private static async Task<DevDiscoveryReply?> QueryAsync(int port, string token, uint nonce, int timeoutMs)
{
using var client = new UdpClient(AddressFamily.InterNetwork);
byte[] q = DevDiscoveryCodec.EncodeQuery(new DevDiscoveryQuery
{
ProtoVersion = DevDiscovery.ProtoVersion,
Nonce = nonce,
Token = token,
});
await client.SendAsync(q, q.Length, new IPEndPoint(IPAddress.Loopback, port));
var recv = client.ReceiveAsync();
var done = await Task.WhenAny(recv, Task.Delay(timeoutMs));
if (done != recv) return null;
UdpReceiveResult result = await recv;
if (!DevDiscoveryCodec.TryDecodeReply(result.Buffer, out var reply)) return null;
return reply;
}
[Fact]
public async Task ValidQuery_ReceivesReply_WithAdvertisedAddresses()
{
var responder = new DevDiscoveryResponder(
"dev-pc", "ws://192.168.1.23:5005/ws", "http://192.168.1.23:15081/minigame/",
token: "secret", listenPort: 0);
responder.Start();
try
{
var reply = await QueryAsync(responder.Port, "secret", nonce: 7, timeoutMs: 2000);
Assert.NotNull(reply);
Assert.Equal("ws://192.168.1.23:5005/ws", reply.Value.GatewayUrl);
Assert.Equal("http://192.168.1.23:15081/minigame/", reply.Value.ResourceBaseUrl);
Assert.Equal("dev-pc", reply.Value.ServerName);
Assert.Equal(7u, reply.Value.Nonce);
}
finally { await responder.StopAsync(); }
}
[Fact]
public async Task WrongToken_NoReply()
{
var responder = new DevDiscoveryResponder("dev-pc", "ws://x", "http://y", token: "secret", listenPort: 0);
responder.Start();
try
{
var reply = await QueryAsync(responder.Port, "WRONG", nonce: 1, timeoutMs: 800);
Assert.Null(reply);
}
finally { await responder.StopAsync(); }
}
[Fact]
public async Task GarbagePacket_Ignored_LoopStillAnswers()
{
var responder = new DevDiscoveryResponder("dev-pc", "ws://x", "http://y", token: "secret", listenPort: 0);
responder.Start();
try
{
using (var raw = new UdpClient(AddressFamily.InterNetwork))
{
byte[] junk = { 1, 2, 3 };
await raw.SendAsync(junk, junk.Length, new IPEndPoint(IPAddress.Loopback, responder.Port));
}
var reply = await QueryAsync(responder.Port, "secret", nonce: 9, timeoutMs: 2000);
Assert.NotNull(reply);
Assert.Equal(9u, reply.Value.Nonce);
}
finally { await responder.StopAsync(); }
}
}
}