using Newtonsoft.Json.Linq; using System.Data; using System.Net; namespace Pilz.Networking; public abstract class ConnectionManagerBase(int port) { private const int HEADER_LENGTH = 12; private bool listening = false; private readonly Dictionary> dicData = []; public int Port { get; private set; } = port; public bool UseAssemblyQualifiedName { get; set; } = false; public event RetriveDataEventHandler RetriveData; public delegate void RetriveDataEventHandler(ConnectionManagerBase manager, string senderIP, string cmd, object content); public bool IsListening { get => listening; protected set => listening = value; } ~ConnectionManagerBase() { Stop(); } public abstract void Start(); public abstract void Stop(); protected abstract void SendData(IPEndPoint endPoint, byte[] data); protected abstract int GetBufferSize(); public virtual void Send(string empfängerIP, string cmd) { Send(empfängerIP, cmd, string.Empty); } public virtual void Send(string empfängerIP, string cmd, string info) { Send(empfängerIP, cmd, (object)info); } private void RaiseRetriveData(string senderIP, string cmd, object content) { RetriveData?.Invoke(this, senderIP, cmd, content); } protected void ProcessRetrivedData(string senderIP, byte[] buf) { int readInteger(int index) => buf[index] << 24 | buf[index + 1] << 16 | buf[index + 2] << 8 | buf[index + 3]; int dataID = readInteger(0); int packageID = readInteger(4); int packageCount = readInteger(8); bool resolveData = true; // Remember data byte[] data = buf.Skip(HEADER_LENGTH).ToArray(); Dictionary dicMyData; if (dicData.ContainsKey(dataID)) { dicMyData = dicData[dataID]; if (dicMyData.ContainsKey(packageID)) dicMyData[packageID] = data; else dicMyData.Add(packageID, data); } else { dicMyData = new Dictionary() { { packageID, data } }; dicData.Add(dataID, dicMyData); } if (dicMyData.Count < packageCount) resolveData = false; // Resolve Data if (resolveData) { dicMyData ??= dicData[dataID]; var myData = new List(); foreach (var kvp in dicMyData.OrderBy(n => n.Key)) myData.AddRange(kvp.Value); dicMyData.Remove(dataID); object content = null; string cmd = string.Empty; try { var res = DecodeFromBytes(myData.ToArray()); cmd = res.cmd; content = res.content; } catch (Exception) { } RaiseRetriveData(senderIP, cmd, content); } } private Random _Send_rnd = new(); public void Send(string empfängerIP, string cmd, object content) { var ep = new IPEndPoint(NetworkFeatures.GetIPFromHost(empfängerIP).MapToIPv4(), Port); var finalBuffer = new List(); int maxBufferSize = GetBufferSize(); int maxDataSize = maxBufferSize - HEADER_LENGTH; byte[] data = EncodeToBytes(cmd, content, UseAssemblyQualifiedName); int dataID = _Send_rnd.Next(); // Some methods for later user void send() => SendData(ep, finalBuffer.ToArray()); void addInteger(int value) { finalBuffer.Add((byte)(value >> 24 & 0xFF)); finalBuffer.Add((byte)(value >> 16 & 0xFF)); finalBuffer.Add((byte)(value >> 8 & 0xFF)); finalBuffer.Add((byte)(value & 0xFF)); }; void addHeader(int packageID, int packagesCount) { addInteger(dataID); // Data ID addInteger(packageID); // Package ID addInteger(packagesCount); // Packages Count }; // Send data (this if statement and else content might be useless) if (data.Length > maxDataSize) { int curIndex = 0; int curID = 0; int packagesCount = (int)Math.Round(Math.Ceiling(data.Length / (double)maxDataSize)); while (curIndex < data.Length) { finalBuffer.Clear(); addHeader(curID, packagesCount); for (int i = 1, loopTo = maxDataSize; i <= loopTo; i++) { if (curIndex < data.Length) { finalBuffer.Add(data[curIndex]); curIndex += 1; } } send(); curID += 1; } } else { addHeader(0, 1); finalBuffer.AddRange(data); send(); } } private static byte[] EncodeToBytes(string cmd, object content, bool useAssemblyQualifiedName) { var ms = new MemoryStream(); var bw = new BinaryWriter(ms); var obj = new JObject { // Write header ["Cmd"] = cmd, ["ContentType"] = useAssemblyQualifiedName ? (content?.GetType()?.AssemblyQualifiedName) : (content?.GetType()?.ToString()), // Content ["Content"] = JToken.FromObject(content) }; // Write Json to MemoryStream bw.Write(System.Text.Encoding.Default.GetBytes(obj.ToString())); // Get Buffer Bytes byte[] buf = ms.ToArray(); ms.Close(); return buf; } private static (string cmd, object content) DecodeFromBytes(byte[] buf) { string contentstring = System.Text.Encoding.Default.GetString(buf); object content = null; var contentobj = JObject.Parse(contentstring); string cmd = (string)contentobj["Cmd"]; string contenttypestring = (string)contentobj["ContentType"]; var contentlinq = contentobj["Content"]; if (!string.IsNullOrEmpty(contenttypestring)) { var contenttype = Type.GetType(contenttypestring); content = contentlinq.ToObject(contenttype); } return (cmd, content); } }