From 0da5b8517371f240a54048fd9025dadab644b9c8 Mon Sep 17 00:00:00 2001 From: SikongJueluo Date: Mon, 31 Mar 2025 20:24:26 +0800 Subject: [PATCH] finish web test api --- .editorconfig | 13 +++ flake.nix | 1 + server/Program.cs | 26 +++--- server/server.csproj | 1 + server/src/Common.cs | 83 +++++++++++++++++ server/src/Router.cs | 41 +++++++++ server/src/UdpClientPool.cs | 22 +++++ server/src/UdpServer.cs | 92 ++++++++++++------- server/src/WebProtocol.cs | 167 ++++++++++++++++++++++++++++++++--- src/components/LoginCard.vue | 5 +- 10 files changed, 392 insertions(+), 59 deletions(-) create mode 100644 .editorconfig create mode 100644 server/src/Common.cs create mode 100644 server/src/Router.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7b34861 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +# Default +[*] +indent_style = space +indent_size = 2 +tab_width = 2 + + +[*.cs] +indent_style = space +indent_size = 4 +tab_width = 4 diff --git a/flake.nix b/flake.nix index 1d1c97b..bd3a2c9 100644 --- a/flake.nix +++ b/flake.nix @@ -27,6 +27,7 @@ ]) nuget omnisharp-roslyn + csharpier # LSP typescript-language-server diff --git a/server/Program.cs b/server/Program.cs index 96133a2..5c93acd 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -1,3 +1,4 @@ +using System.Net; using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); @@ -22,22 +23,19 @@ if (app.Environment.IsDevelopment()) }); } +// Setup UDP Server +var udpServer = new UDPServer(33000); +udpServer.Start(); + // Router app.MapGet("/", () => "Hello World!"); +app.MapPut("/api/SendString", Router.API.SendString); +app.MapPut("/api/SendAddrPackage", Router.API.SendAddrPackage); +app.MapPut("/api/SendDataPackage", Router.API.SendDataPackage); -var thrdStartUdpServer = new ThreadStart(UDPServer.Start); -var thrdUdpServer = new Thread(thrdStartUdpServer); -thrdUdpServer.Start(); -Console.WriteLine("Start UDP Server"); -var thrdStartUdpClient = new ThreadStart(UDPClient.Start); -var thrdUdpClient = new Thread(thrdStartUdpClient); -thrdUdpClient.Start(); -Console.WriteLine("Start UDP Client"); - - -thrdUdpServer.Join(); -thrdUdpClient.Join(); - -// app.Run("http://localhost:5000"); +app.Run("http://localhost:5000"); +// Close UDP Server +Console.WriteLine("UDP Server is Closing now..."); +udpServer.Stop(); diff --git a/server/server.csproj b/server/server.csproj index af9d95c..aa05bf8 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -7,6 +7,7 @@ + diff --git a/server/src/Common.cs b/server/src/Common.cs new file mode 100644 index 0000000..5970d07 --- /dev/null +++ b/server/src/Common.cs @@ -0,0 +1,83 @@ +using DotNext; + +namespace Common +{ + class NumberProcessor + { + public static Result NumberToBytes(ulong num, uint length, bool isRightHigh = false) + { + if (length > 8) + { + throw new ArgumentException( + "Unsigned long number can't over 8 bytes(64 bits).", + nameof(length) + ); + } + + var arr = new byte[length]; + + if (isRightHigh) + { + for (var i = 0; i < length; i++) + { + arr[length - 1 - i] = Convert.ToByte((num >> (i << 3)) & (0xFF)); + } + } + else + { + for (var i = 0; i < length; i++) + { + arr[i] = Convert.ToByte((num >> (i << 3)) & (0xFF)); + } + } + return arr; + } + + public static Result BytesToNumber(byte[] bytes, bool isRightLeft = false) + { + if (bytes.Length > 8) + { + throw new ArgumentException( + "Unsigned long number can't over 8 bytes(64 bits).", + nameof(bytes) + ); + } + + ulong num = 0; + int len = bytes.Length; + + if (isRightLeft) + { + for (var i = 0; i < len; i++) + { + num += Convert.ToUInt64(bytes[len - 1 - i] << (i << 3)); + } + } + else + { + for (var i = 0; i < len; i++) + { + num += Convert.ToUInt64(bytes[i] << (i << 3)); + } + } + + return num; + } + + public static Result StringToBytes(string str, int numBase = 16) + { + var len = str.Length; + var bytesLen = len / 2; + var bytes = new byte[bytesLen]; + + for (var i = 0; i < bytesLen; i++) + { + bytes[i] = Convert.ToByte(str.Substring(i * 2, 2), 16); + } + + return bytes; + } + + } + +} diff --git a/server/src/Router.cs b/server/src/Router.cs new file mode 100644 index 0000000..b21e362 --- /dev/null +++ b/server/src/Router.cs @@ -0,0 +1,41 @@ +using System.Net; +using Common; + +namespace Router +{ + class API + { + public static void SendString(string address, int port, string text) + { + var endPoint = new IPEndPoint(IPAddress.Parse(address), port); + UDPClientPool.AsyncSendString(endPoint, [text]); + } + + public static void SendAddrPackage( + string address, + int port, + WebProtocol.BurstType burstType, + byte commandID, + bool isWrite, + byte burstLength, + UInt32 devAddress) + { + WebProtocol.SendAddrPackOptions opts; + opts.burstType = burstType; + opts.commandID = commandID; + opts.isWrite = isWrite; + opts.burstLength = burstLength; + opts.address = devAddress; + + var endPoint = new IPEndPoint(IPAddress.Parse(address), port); + UDPClientPool.SendAddrPack(endPoint, new WebProtocol.SendAddrPackage(opts)); + } + + public static void SendDataPackage(string address, int port, string data) + { + var endPoint = new IPEndPoint(IPAddress.Parse(address), port); + UDPClientPool.SendDataPack(endPoint, + new WebProtocol.SendDataPackage(NumberProcessor.StringToBytes(data).Value)); + } + } +} diff --git a/server/src/UdpClientPool.cs b/server/src/UdpClientPool.cs index 1557af1..d197de9 100644 --- a/server/src/UdpClientPool.cs +++ b/server/src/UdpClientPool.cs @@ -31,6 +31,28 @@ class UDPClientPool await Task.Run(() => { SendBytes(endPoint, buf); }); } + public static void SendAddrPack(IPEndPoint endPoint, WebProtocol.SendAddrPackage pkg) + { + Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + socket.SendTo(pkg.ToBytes(), endPoint); + } + + public async static void AsyncSendAddrPack(IPEndPoint endPoint, WebProtocol.SendAddrPackage pkg) + { + await Task.Run(() => { SendAddrPack(endPoint, pkg); }); + } + + public static void SendDataPack(IPEndPoint endPoint, WebProtocol.SendDataPackage pkg) + { + Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + socket.SendTo(pkg.ToBytes(), endPoint); + } + + public async static void AsyncSendDataPack(IPEndPoint endPoint, WebProtocol.SendDataPackage pkg) + { + await Task.Run(() => { SendDataPack(endPoint, pkg); }); + } + public static void SendLocalHost(int port, string[] stringArray) { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); diff --git a/server/src/UdpServer.cs b/server/src/UdpServer.cs index 8181fe9..35090bb 100644 --- a/server/src/UdpServer.cs +++ b/server/src/UdpServer.cs @@ -7,57 +7,87 @@ public class UDPServer private int listenPort; private UdpClient listener; private IPEndPoint groupEP; - private Thread thrd; - private bool isRunning; - - public UDPServer(int port) { // Construction listenPort = port; - listener = new UdpClient(listenPort); - groupEP = new IPEndPoint(IPAddress.Any, listenPort); - - // New Thread - var thrdStart = new ThreadStart(ReceiveHandler); - thrd = new Thread(thrdStart); - } - - private void ReceiveHandler() - { try { - while (isRunning) - { - byte[] bytes = listener.Receive(ref groupEP); + listener = new UdpClient(listenPort); + groupEP = new IPEndPoint(IPAddress.Any, listenPort); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + throw new ArgumentException( + $"Not currect port num: {port}", + nameof(port) + ); + } + } - Console.WriteLine($"Received broadcast from {groupEP} :"); - Console.WriteLine($" {Encoding.ASCII.GetString(bytes, 0, bytes.Length)}"); - } - } - catch (SocketException e) + private void ReceiveHandler(IAsyncResult res) + { + var remoteEP = new IPEndPoint(IPAddress.Any, listenPort); + byte[] bytes = listener.EndReceive(res, ref remoteEP); + + var sign = bytes[0]; + + string recvData; + if (sign == (byte)WebProtocol.PackSign.SendAddr) { - Console.WriteLine(e); + var resData = WebProtocol.SendAddrPackage.FromBytes(bytes); + if (resData.IsSuccessful) + recvData = resData.Value.ToString(); + else + recvData = resData.Error.ToString(); } - finally + else if (sign == (byte)WebProtocol.PackSign.SendData) { - listener.Close(); + recvData = ""; } + else if (sign == (byte)WebProtocol.PackSign.RecvData) + { + recvData = ""; + } + else if (sign == (byte)WebProtocol.PackSign.RecvResp) + { + recvData = ""; + } + else + { + recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); + } + + string remoteStr = (remoteEP is null) ? "Unknown" : $"{remoteEP.Address.ToString()}:{remoteEP.Port.ToString()}"; + Console.WriteLine($"Receive Data from {remoteStr} at {DateTime.Now.ToString()}:"); + Console.WriteLine($"Original Data: {BitConverter.ToString(bytes).Replace("-", " ")}"); + if (recvData.Length != 0) Console.WriteLine(recvData); + Console.WriteLine(); + + listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); } public void Start() { - isRunning = true; - thrd.Start(); + try + { + listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + } + finally + { + + } } public void Stop() { - isRunning = false; - thrd.Join(); + listener.Close(); } - - } diff --git a/server/src/WebProtocol.cs b/server/src/WebProtocol.cs index 1573d06..16ff7f9 100644 --- a/server/src/WebProtocol.cs +++ b/server/src/WebProtocol.cs @@ -1,6 +1,8 @@ +using DotNext; +using Newtonsoft.Json; + namespace WebProtocol { - public enum PackSign { SendAddr = 0x00, @@ -15,36 +17,179 @@ namespace WebProtocol FixedBurst = 0b01, } + public struct SendAddrPackOptions + { + public BurstType burstType; + public byte commandID; + public bool isWrite; + public byte burstLength; + public UInt32 address; + + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } + } + + public struct RecvPackOptions + { + public byte commandID; + public bool isSuccess; + } + public struct SendAddrPackage { - readonly byte Sign = (byte)PackSign.SendAddr; + readonly byte sign = (byte)PackSign.SendAddr; readonly byte commandType; readonly byte burstLength; - readonly byte _reserved; + readonly byte _reserved = 0; readonly UInt32 address; + public SendAddrPackage(SendAddrPackOptions opts) + { + byte byteBurstType = Convert.ToByte((byte)opts.burstType << 5); + byte byteCommandID = Convert.ToByte((opts.commandID & 0x03) << 3); + byte byteIsWrite = (opts.isWrite ? (byte)0x01 : (byte)0x00); + this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite); + this.burstLength = opts.burstLength; + this.address = opts.address; + } public SendAddrPackage(BurstType burstType, byte commandID, bool isWrite) { - commandType = ( - ((byte)burstType << 5) | - ((commandID & (byte)0x03) << 3) | - (isWrite ? (byte)0x01 : (byte)0x00) - ); + byte byteBurstType = Convert.ToByte((byte)burstType << 5); + byte byteCommandID = Convert.ToByte((commandID & 0x03) << 3); + byte byteIsWrite = (isWrite ? (byte)0x01 : (byte)0x00); + this.commandType = Convert.ToByte(byteBurstType | byteCommandID | byteIsWrite); } - public void toBytes() + public SendAddrPackage(byte commandType, byte burstLength, UInt32 address) { + this.commandType = commandType; + this.burstLength = burstLength; + this.address = address; + } + public byte[] ToBytes() + { + var arr = new byte[8]; + arr[0] = sign; + arr[1] = commandType; + arr[2] = burstLength; + arr[3] = _reserved; + + var bytesAddr = Common.NumberProcessor.NumberToBytes(address, 4).Value; + Array.Copy(bytesAddr, 0, arr, 4, bytesAddr.Length); + + return arr; + } + + public override string ToString() + { + SendAddrPackOptions opts; + opts.burstType = (BurstType)(commandType >> 5); + opts.commandID = Convert.ToByte((commandType >> 3) & 0b0011); + opts.isWrite = Convert.ToBoolean(commandType & 0x01); + opts.burstLength = burstLength; + opts.address = address; + + return JsonConvert.SerializeObject(opts); + } + + public static Result FromBytes(byte[] bytes, bool checkSign = true) + { + if (bytes.Length != 8) + { + throw new ArgumentException( + "Bytes are not equal to 8 bytes.", + nameof(bytes) + ); + } + + if (checkSign && bytes[0] != (byte)PackSign.SendAddr) + { + throw new ArgumentException( + "The sign of bytes is not SendAddr Package, but you can disable it by set checkSign false.", + nameof(bytes) + ); + } + + var address = Common.NumberProcessor.BytesToNumber(bytes[4..]).Value; + return new SendAddrPackage(bytes[1], bytes[2], Convert.ToUInt32(address)); } } - public struct RecvRackage + public struct SendDataPackage { + readonly byte sign = (byte)PackSign.SendData; + readonly byte[] _reserved = new byte[3]; + readonly byte[] bodyData; - public void toBytes() + public SendDataPackage(byte[] bodyData) { + this.bodyData = bodyData; + } + public byte[] ToBytes() + { + var bodyDataLen = bodyData.Length; + var arr = new byte[4 + bodyDataLen]; + + arr[0] = sign; + + Array.Copy(bodyData, 0, arr, 4, bodyDataLen); + + return arr; + } + + + } + + public struct RecvDataPackage + { + readonly byte sign = (byte)PackSign.RecvData; + readonly byte commandID; + readonly byte resp; + readonly byte _reserved = 0; + readonly byte[] bodyData; + + public RecvDataPackage(byte commandID, byte resp, byte[] bodyData) + { + this.commandID = commandID; + this.resp = resp; + this.bodyData = bodyData; + } + + public RecvPackOptions Options() + { + RecvPackOptions opts; + opts.commandID = commandID; + opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false); + + return opts; + } + } + + public struct RecvRespPackage + { + readonly byte sign = (byte)PackSign.RecvResp; + readonly byte commandID; + readonly byte resp; + readonly byte _reserved = 0; + + public RecvRespPackage(byte commandID, byte resp) + { + this.commandID = commandID; + this.resp = resp; + } + + public RecvPackOptions Options() + { + RecvPackOptions opts; + opts.commandID = commandID; + opts.isSuccess = Convert.ToBoolean((resp >> 1) == 0b01 ? true : false); + + return opts; } } } diff --git a/src/components/LoginCard.vue b/src/components/LoginCard.vue index d8ab82b..3907fed 100644 --- a/src/components/LoginCard.vue +++ b/src/components/LoginCard.vue @@ -23,9 +23,8 @@ - +