commit 7d9e542ffbfd6ac46006d3f8f12dc13f9a53ffbb Author: U-WALDRENNACH\haraldwolff Date: Tue Nov 17 23:48:34 2020 +0100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bf793ed --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Autosave files +*~ + +# build +[Oo]bj/ +[Bb]in/ +packages/ +TestResults/ + +# globs +Makefile.in +*.DS_Store +*.sln.cache +*.suo +*.cache +*.pidb +*.userprefs +*.usertasks +config.log +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.user +*.tar.gz +tarballs/ +test-results/ +Thumbs.db +.vs/ + +# Mac bundle stuff +*.dmg +*.app + +# resharper +*_Resharper.* +*.Resharper + +# dotCover +*.dotCover diff --git a/ByteArrayExtensions.cs b/ByteArrayExtensions.cs new file mode 100644 index 0000000..0284e13 --- /dev/null +++ b/ByteArrayExtensions.cs @@ -0,0 +1,75 @@ +// /** +// * File: ByteArrayExtensions.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +namespace ln.type +{ + public enum Endianess { BIG, LITTLE } + + public static class ByteArrayExtensions + { + + public static byte[] To(this byte[] bytes,Endianess endianess) + { + if (BitConverter.IsLittleEndian == (endianess==Endianess.BIG)) + Array.Reverse(bytes); + return bytes; + } + + public static byte GetByte(this byte[] bytes, ref int offset) => bytes[offset++]; + public static byte[] GetByte(this byte[] bytes,ref int offset,out byte value) + { + value = GetByte(bytes, ref offset); + return bytes; + } + + + public static byte[] GetShort(this byte[] bytes, ref int offset, out short value) => GetShort(bytes, ref offset, out value, Endianess.LITTLE); + public static byte[] GetShort(this byte[] bytes, ref int offset, out short value, Endianess endianess) + { + value = GetShort(bytes, ref offset, endianess); + return bytes; + } + public static short GetShort(this byte[] bytes, ref int offset, Endianess endianess) => BitConverter.ToInt16(bytes.Slice(ref offset, 2).To(endianess), 0); + + public static byte[] GetUShort(this byte[] bytes, ref int offset, out ushort value) => GetUShort(bytes, ref offset, out value, Endianess.LITTLE); + public static byte[] GetUShort(this byte[] bytes, ref int offset, out ushort value, Endianess endianess) + { + value = GetUShort(bytes, ref offset, endianess); + return bytes; + } + public static ushort GetUShort(this byte[] bytes, ref int offset, Endianess endianess) => BitConverter.ToUInt16(bytes.Slice(ref offset, 2).To(endianess), 0); + + public static byte[] GetInt(this byte[] bytes, ref int offset, out int value) => GetInt(bytes, ref offset, out value, Endianess.LITTLE); + public static byte[] GetInt(this byte[] bytes, ref int offset, out int value, Endianess endianess) + { + value = GetInt(bytes, ref offset, endianess); + return bytes; + } + public static int GetInt(this byte[] bytes, ref int offset, Endianess endianess) => BitConverter.ToInt32(bytes.Slice(ref offset, 4).To(endianess), 0); + + public static byte[] GetUInt(this byte[] bytes, ref int offset, out uint value) => GetUInt(bytes, ref offset, out value, Endianess.LITTLE); + public static byte[] GetUInt(this byte[] bytes, ref int offset, out uint value, Endianess endianess) + { + value = GetUInt(bytes, ref offset, endianess); + return bytes; + } + public static uint GetUInt(this byte[] bytes, ref int offset, Endianess endianess) => BitConverter.ToUInt32(bytes.Slice(ref offset, 4).To(endianess), 0); + + + public static byte[] GetBytes(this byte[] bytes,ref int offset,int length,out byte[] value) + { + value = bytes.Slice(ref offset, length); + return bytes; + } + + + + } +} diff --git a/Cast.cs b/Cast.cs new file mode 100644 index 0000000..815c329 --- /dev/null +++ b/Cast.cs @@ -0,0 +1,103 @@ +// /** +// * File: Cast.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Reflection; +using System.Linq; +using System.Threading; +namespace ln.type +{ + public static class Cast + { + public static T To(object value) => (T)To(value, typeof(T)); + public static object To(object value, Type targetType) + { + if (Object.ReferenceEquals(null, value)) + return null; + + if (targetType.IsInstanceOfType(value)) + return value; + + object casted; + + if ( + !Implicit(value, targetType, out casted) && + !Implicit(value, value.GetType(), targetType, out casted) && + !Explicit(value, targetType, out casted) && + !Explicit(value, value.GetType(), targetType, out casted) + ) + { + if (targetType.IsEnum) + { + if (value is string sValue) + { + casted = Enum.Parse(targetType, sValue); + } else + { + throw new NotSupportedException(); + } + } + else if (targetType.IsArray) + { + Array array = value as Array; + Array castedArray = Array.CreateInstance(targetType.GetElementType(), array.Length); + + for (int n = 0; n < array.Length; n++) + castedArray.SetValue(To(array.GetValue(n), targetType.GetElementType()), n); + + casted = castedArray; + } + else + { + casted = Convert.ChangeType(value, targetType); + } + } + return casted; + } + + public static bool Implicit(object value, Type type, out object casted) => Implicit(value, type, type, out casted); + public static bool Implicit(object value, Type type, Type targetType, out object casted) + { + foreach (MethodInfo methodInfo in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (methodInfo.Name.Equals("op_Implicit") && methodInfo.ReturnType.Equals(targetType)) + { + ParameterInfo parameterInfo = methodInfo.GetParameters().FirstOrDefault(); + if ((parameterInfo != null) && (parameterInfo.ParameterType.Equals(value.GetType()))) + { + casted = methodInfo.Invoke(null, new object[] { value }); + return true; + } + } + } + casted = null; + return false; + } + public static bool Explicit(object value, Type type, out object casted) => Implicit(value, type, type, out casted); + public static bool Explicit(object value, Type type, Type targetType, out object casted) + { + foreach (MethodInfo methodInfo in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (methodInfo.Name.Equals("op_Explicit") && methodInfo.ReturnType.Equals(targetType)) + { + ParameterInfo parameterInfo = methodInfo.GetParameters().FirstOrDefault(); + if ((parameterInfo != null) && (parameterInfo.ParameterType.Equals(value.GetType()))) + { + casted = methodInfo.Invoke(null, new object[] { value }); + return true; + } + } + } + casted = null; + return false; + } + + + } +} diff --git a/Date.cs b/Date.cs new file mode 100644 index 0000000..9a705b2 --- /dev/null +++ b/Date.cs @@ -0,0 +1,25 @@ +using System; +namespace ln.type +{ + public class Date + { + int year, month, day; + + public Date() + { + DateTime now = DateTime.Now; + this.year = now.Year; + this.month = now.Month; + this.day = now.Day; + } + public Date(int year,int month,int day) + { + this.year = year; + this.month = month; + this.day = day; + } + + public static implicit operator DateTime(Date date) => new DateTime(date.year,date.month,date.day); + public static implicit operator Date(DateTime dateTime) => new Date(); + } +} diff --git a/DvDt.cs b/DvDt.cs new file mode 100644 index 0000000..0ba80e2 --- /dev/null +++ b/DvDt.cs @@ -0,0 +1,41 @@ +// /** +// * File: DvDt.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +namespace ln.type +{ + public class dVdT + { + public double Current { get; private set; } + public double LastValue => lastValue; + public DateTime LastTimeStamp => lastTimestamp; + + DateTime lastTimestamp; + double lastValue; + + public dVdT() + { + lastTimestamp = DateTime.MinValue; + lastValue = 0.0; + } + + public void Update(double value) + { + DateTime now = DateTime.Now; + double interval = (now - lastTimestamp).TotalSeconds; + if (Math.Abs(interval) > double.Epsilon) + { + double dV = value - lastValue; + Current = dV / interval; + lastTimestamp = now; + lastValue = value; + } + } + } +} diff --git a/Endpoint.cs b/Endpoint.cs new file mode 100644 index 0000000..c601d77 --- /dev/null +++ b/Endpoint.cs @@ -0,0 +1,69 @@ +// /** +// * File: Endpoint.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Net; +using System.Net.Sockets; + +namespace ln.type +{ + public class Endpoint + { + public IPv6 Address { get; } + public int Port { get; } + + private Endpoint() { } + + public Endpoint(IPv6 address, int port) + { + Address = address; + Port = port; + } + public Endpoint(System.Net.EndPoint netEndpoint) + { + if (netEndpoint is IPEndPoint ipep) + { + Port = ipep.Port; + Address = ipep.Address; + return; + } + throw new ArgumentOutOfRangeException(nameof(netEndpoint)); + } + + public override int GetHashCode() + { + return Address.GetHashCode() ^ Port; + } + + public override bool Equals(object obj) + { + if (obj is Endpoint) + { + Endpoint you = obj as Endpoint; + return Address.Equals(you.Address) && Port.Equals(you.Port); + } + return false; + } + + public Socket CreateSocket(SocketType socketType) + { + Socket socket = new Socket( + IPv6.V4Space.Contains(Address) ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6, + socketType, + ProtocolType.Unspecified + + ); + socket.Bind(this); + return socket; + } + + public static implicit operator Endpoint(EndPoint endPoint) => new Endpoint(endPoint); + public static implicit operator EndPoint(Endpoint endPoint) => new IPEndPoint(endPoint.Address, endPoint.Port); + } +} diff --git a/Extensions.cs b/Extensions.cs new file mode 100644 index 0000000..d2dd070 --- /dev/null +++ b/Extensions.cs @@ -0,0 +1,394 @@ +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using System.Collections; +using System.Xml.Schema; +namespace ln.type +{ + public static class Extensions + { + public static T[] Concat(this T[] me, T[] other) + { + T[] combined = new T[me.Length + other.Length]; + Array.Copy(me, 0, combined, 0, me.Length); + Array.Copy(other, 0, combined, me.Length, combined.Length); + return combined; + } + + + public static T[] Combine(this T[] me, IEnumerable other) + { + HashSet elements = new HashSet(me); + foreach (T e in other) + elements.Add(e); + return elements.ToArray(); + } + public static T[] Remove(this T[] me, IEnumerable remove) + { + HashSet elements = new HashSet(me); + foreach (T e in remove) + elements.Remove(e); + return elements.ToArray(); + } + + + public static bool AreEqual(this T[] me, T[] you) + { + if (me.Length != you.Length) + return false; + + for (int n = 0; n < me.Length; n++) + if (!me[n].Equals(you[n])) + return false; + + return true; + } + + public static byte[] BigEndian(this byte[] bytes) + { + if (BitConverter.IsLittleEndian) + Array.Reverse(bytes); + return bytes; + } + + public static int ReadInteger(this Stream stream) + { + byte[] b = new byte[4]; + stream.Read(b, 0, 4); + return BitConverter.ToInt32(b, 0); + } + public static void WriteInteger(this Stream stream, int i) + { + stream.Write(BitConverter.GetBytes(i), 0, 4); + } + public static uint ReadUInteger(this Stream stream) + { + byte[] b = new byte[4]; + stream.Read(b, 0, 4); + return BitConverter.ToUInt32(b.BigEndian(), 0); + } + public static void WriteUInteger(this Stream stream, uint i) + { + stream.Write(BitConverter.GetBytes(i).BigEndian(), 0, 4); + } + + public static long ReadLong(this Stream stream) + { + byte[] b = new byte[8]; + stream.Read(b, 0, 8); + return BitConverter.ToInt64(b, 0); + } + public static void WriteLong(this Stream stream, long i) + { + stream.Write(BitConverter.GetBytes(i), 0, 8); + } + public static ulong ReadULong(this Stream stream) + { + byte[] b = new byte[8]; + stream.Read(b, 0, 8); + return BitConverter.ToUInt64(b.BigEndian(), 0); + } + public static void WriteULong(this Stream stream, ulong i) + { + stream.Write(BitConverter.GetBytes(i).BigEndian(), 0, 8); + } + + + public static byte[] ReadToEnd(this Stream stream) + { + MemoryStream memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + return memoryStream.ToArray(); + } + + public static void WriteByte(this Stream stream, char ch) + { + if (ch > 255) + throw new ArgumentOutOfRangeException(nameof(ch)); + stream.WriteByte((byte)ch); + } + public static void WriteBytes(this Stream stream, byte[] bytes) + { + stream.Write(bytes, 0, bytes.Length); + } + public static byte[] ReadBytes(this Stream stream, int length) + { + byte[] bytes = new byte[length]; + stream.Read(bytes, 0, length); + return bytes; + } + + public static void WriteShort(this Stream stream, short value, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + stream.Write(bytes, 0, bytes.Length); + } + public static short ReadShort(this Stream stream, bool bigEndian = false) + { + byte[] bytes = stream.ReadBytes(2); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return BitConverter.ToInt16(bytes, 0); + } + public static void WriteUShort(this Stream stream, ushort value, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + stream.Write(bytes, 0, bytes.Length); + } + public static ushort ReadUShort(this Stream stream, bool bigEndian = false) + { + byte[] bytes = stream.ReadBytes(2); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return BitConverter.ToUInt16(bytes, 0); + } + + public static void WriteLong(this Stream stream, long value, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + stream.Write(bytes, 0, bytes.Length); + } + public static long ReadLong(this Stream stream, bool bigEndian = false) + { + byte[] bytes = stream.ReadBytes(8); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return BitConverter.ToInt64(bytes, 0); + } + + public static void WriteULong(this Stream stream, ulong value, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + stream.Write(bytes, 0, bytes.Length); + } + public static ulong ReadULong(this Stream stream, bool bigEndian = false) + { + byte[] bytes = stream.ReadBytes(8); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return BitConverter.ToUInt64(bytes, 0); + } + + public static void WriteFloat(this Stream stream, float value, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + stream.Write(bytes, 0, bytes.Length); + } + public static float ReadFloat(this Stream stream, bool bigEndian = false) + { + byte[] bytes = stream.ReadBytes(4); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return BitConverter.ToSingle(bytes, 0); + } + + public static void WriteDouble(this Stream stream, double value, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(value); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + stream.Write(bytes, 0, bytes.Length); + } + public static double ReadDouble(this Stream stream, bool bigEndian = false) + { + byte[] bytes = stream.ReadBytes(8); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return BitConverter.ToDouble(bytes, 0); + } + + + + + public static byte[] GetBytes(this int v, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(v); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return bytes; + } + public static byte[] GetBytes(this uint v, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(v); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return bytes; + + } + public static int GetInt(this byte[] bytes, bool bigEndian = false) => GetInt(bytes, 0, bigEndian); + public static int GetInt(this byte[] bytes, int offset, bool bigEndian = false) + { + byte[] ib = bytes.Slice(offset, 4).BigEndian(); + return BitConverter.ToInt32(ib, 0); + } + public static uint GetUInt(this byte[] bytes, bool bigEndian = false) => GetUInt(bytes, 0, bigEndian); + public static uint GetUInt(this byte[] bytes, int offset, bool bigEndian = false) + { + byte[] ib = bytes.Slice(offset, 4).BigEndian(); + return BitConverter.ToUInt32(ib, 0); + } + + public static byte[] GetBytes(this short v, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(v); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return bytes; + } + public static byte[] GetBytes(this ushort v, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(v); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return bytes; + } + + public static short GetShort(this byte[] bytes, bool bigEndian = false) => GetShort(bytes, 0, bigEndian); + public static short GetShort(this byte[] bytes, int offset, bool bigEndian = false) + { + byte[] ib = bytes.Slice(offset, 2).BigEndian(); + return BitConverter.ToInt16(ib, 0); + } + public static ushort GetUShort(this byte[] bytes, bool bigEndian = false) => GetUShort(bytes, 0, bigEndian); + public static ushort GetUShort(this byte[] bytes, int offset, bool bigEndian = false) + { + byte[] ib = bytes.Slice(offset, 2).BigEndian(); + return BitConverter.ToUInt16(ib, 0); + } + + public static byte[] GetBytes(this long v, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(v); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return bytes; + } + public static byte[] GetBytes(this ulong v, bool bigEndian = false) + { + byte[] bytes = BitConverter.GetBytes(v); + if (BitConverter.IsLittleEndian == bigEndian) + Array.Reverse(bytes); + return bytes; + } + + + public static T[] Slice(this T[] me, int offset) => Slice(me, offset, me.Length - offset); + public static T[] Slice(this T[] me, ref int offset) => Slice(me, ref offset, me.Length - offset); + public static T[] Slice(this T[] me, int offset, int length) => Slice(me, ref offset, length); + public static T[] Slice(this T[] me, ref int offset, int length) + { + if (offset < 0) + offset = me.Length + offset; + if (length < 0) + length = me.Length - offset + length; + + T[] slice = new T[length]; + Array.Copy(me, offset, slice, 0, length); + offset += length; + return slice; + } + + public static byte[] BytesFromHexString(string hexString) + { + int NumberChars = hexString.Length; + byte[] bytes = new byte[NumberChars / 2]; + for (int i = 0; i < NumberChars; i += 2) + bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); + return bytes; + } + + public static string ToHexString(this byte[] bytes) + { + StringBuilder stringBuilder = new StringBuilder(); + + for (int n = 0; n < bytes.Length; n ++) + { + stringBuilder.AppendFormat("{0:X2}", bytes[n]); + } + + return stringBuilder.ToString(); + } + + public static string HexDump(this byte[] bytes) + { + StringBuilder stringBuilder = new StringBuilder(); + + for (int n = 0; n < bytes.Length; n += 16) + { + int len = bytes.Length - n; + if (len > 16) + len = 16; + + byte[] section = bytes.Slice(n, len); + + for (int i = 0; i < 16; i++) + { + if (i < section.Length) + stringBuilder.AppendFormat("{0:X2} ", section[i]); + else + stringBuilder.Append(" "); + } + + stringBuilder.Append(" "); + + foreach (byte b in section) + { + if (b < 32) + stringBuilder.Append('.'); + else + stringBuilder.Append((char)b); + } + stringBuilder.AppendLine(); + } + + return stringBuilder.ToString(); + } + + public static Decimal ToDecimal(this double v) + { + if (v <= (double)Decimal.MinValue) + return decimal.MinValue; + if (v >= (double)Decimal.MaxValue) + return decimal.MaxValue; + + return new Decimal(v); + } + + public static string GetSimpleQualifiedName(this Type type) => string.Format("{0}, {1}", type.FullName, type.Assembly.GetName().Name); + + } + public static class DateTimeExtensions + { + public static DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + + public static DateTime FromUnixTimeSeconds(double seconds) + { + return EPOCH.AddSeconds(seconds); + } + public static DateTime FromUnixTimeMilliseconds(double milliseconds) + { + return EPOCH.AddMilliseconds(milliseconds); + } + + public static double ToUnixTimeSeconds(this DateTime dateTime) + { + return (dateTime - EPOCH).TotalSeconds; + } + public static double ToUnixTimeMilliseconds(this DateTime dateTime) + { + return (dateTime - EPOCH).TotalMilliseconds; + } + } +} diff --git a/Factory.cs b/Factory.cs new file mode 100644 index 0000000..36d8157 --- /dev/null +++ b/Factory.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ln.type +{ + public delegate T Factory(); + public delegate T Factory(R requester); + +} diff --git a/GeoLocation.cs b/GeoLocation.cs new file mode 100644 index 0000000..85da0c6 --- /dev/null +++ b/GeoLocation.cs @@ -0,0 +1,34 @@ +// /** +// * File: GeoLocation.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +namespace ln.type +{ + public struct GeoLocation + { + public double Latitude; + public double Longitude; + + public GeoLocation(double latitude,double longitude) + { + Latitude = latitude; + Longitude = longitude; + } + + public override string ToString() + { + return String.Format("{0:F}{1}{2:F}{3}", + (Latitude < 0) ? -Latitude : Latitude, + (Latitude < 0) ? 'S':'N', + (Longitude < 0) ? -Longitude : Longitude, + (Longitude < 0) ? 'W' : 'E' + ); + } + } +} diff --git a/IPv6.cs b/IPv6.cs new file mode 100644 index 0000000..e8cd2f4 --- /dev/null +++ b/IPv6.cs @@ -0,0 +1,335 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using ln.type.arithmetics; +using System.Net; + +namespace ln.type +{ + public class IPv6 + { + public static readonly IPv6 ANY = new IPv6(new byte[17]); + public static readonly IPv6 V4Space = Parse("::ffff:0:0/96"); + public static readonly IPv6 Loopback = Parse("::1"); + + readonly UInt16[] value; + readonly UInt32 mask; + + public uint Netmask => mask; + + public IPv6() + { + value = new UInt16[8]; + mask = 0; + } + public IPv6(uint netmask) + { + value = new UInt16[8]; + mask = netmask; + } + public IPv6(IPv6 ip, uint netmask) : this(ip.value, netmask) { } + public IPv6(ushort[] words, uint netmask) + { + if (words.Length > 8) + throw new ArgumentOutOfRangeException(nameof(words)); + + value = words.Slice(0, 8); + mask = netmask; + } + + public IPv6(byte[] bytes,uint netmask) + :this(bytes) + { + mask = netmask; + } + public IPv6(byte[] bytes) + :this() + { + if (bytes.Length == 16) + { + for (int n = 0; n < 8; n++) + { + value[n] = (ushort)((bytes[(n << 1) + 0] << 8) | bytes[(n << 1) + 1]); + } + mask = 128; + } + else if (bytes.Length == 17) + { + for (int n = 0; n < 8; n++) + { + value[n] = (ushort)((bytes[(n << 1) + 0] << 8) | bytes[(n << 1) + 1]); + } + mask = bytes[16]; + } + else if (bytes.Length == 4) + { + value[5] = 0xffff; + value[6] = (ushort)((bytes[0] << 8) | bytes[1]); + value[7] = (ushort)((bytes[2] << 8) | bytes[3]); + mask = 96; + } else + throw new ArgumentOutOfRangeException(nameof(bytes)); + } + + public IPv6 Network + { + get + { + if (mask == 128) + return this; + + ushort[] address = value.Slice(0); + uint steps = mask >> 4; + uint shift = mask & 0x0F; + + address[steps] &= (ushort)(0xFFFF << (int)(16 - shift)); + + for (uint n = steps+1; n < 8; n++) + address[n] = 0; + + return new IPv6(address, mask); + } + } + + public bool Contains(IPv6 ip) + { + if (ip.mask < mask) + return false; + + IPv6 ipNetwork = new IPv6(ip, mask).Network; + return Network.Equals(ipNetwork); + } + + public byte[] ToBytes() + { + byte[] bytes = new byte[16]; + + for (int n = 0; n < 8; n++) + { + bytes[(n << 1) + 1] = (byte)((value[n] >> 0) & 0xff); + bytes[(n << 1) + 0] = (byte)((value[n] >> 8) & 0xff); + } + + return bytes; + } + public byte[] ToCIDRBytes() + { + byte[] bytes = new byte[17]; + + for (int n = 0; n < 8; n++) + { + bytes[(n << 1) + 1] = (byte)((value[n] >> 0) & 0xff); + bytes[(n << 1) + 0] = (byte)((value[n] >> 8) & 0xff); + } + bytes[16] = mask.GetBytes()[0]; + + return bytes; + } + public byte[] ToPackedBytes() + { + byte[] bytes = ToBytes(); + if (V4Space.Contains(this)) + return bytes.Slice(12); + return bytes; + + } + + public IEnumerable Split(int splitWidth) + { + List splitted = new List(); + + if (128 < (mask + splitWidth)) + throw new ArgumentOutOfRangeException(nameof(splitWidth),"cannot split to negative host identfier length"); + + IPv6 ip = new IPv6(value, (uint)(mask + splitWidth)); + ushort[] increment = Words.SHL(new ushort[] { 1, 0, 0, 0, 0, 0, 0, 0 }, (int)(128 - ip.mask)); + + for (int n=0;n<(1< String.Format("{0:x4}", w))); + } + else if (V4Space.Contains(this)) + { + return string.Format("::ffff:{0}.{1}.{2}.{3}", + ((value[6] >> 8) & 0xFF), + ((value[6] >> 0) & 0xFF), + ((value[7] >> 8) & 0xFF), + ((value[7] >> 0) & 0xFF) + ); + } + else + { + int zerolen = 0; + int zeropos = -1; + + for (int n=0;n<8;n++) + { + if (value[n]==0) + { + int m; + for (m = 1; m < (8 - n); m++) + { + if (value[n + m] != 0) + break; + } + if (m > zerolen) + { + zerolen = m; + zeropos = n; + } + } + } + + List words = new List(); + + for (int n = 0; n < 8; n++) + { + if (n == zeropos) + { + if (n == 0) + words.Add(""); + if ((n + zerolen)==8) + words.Add(""); + + words.Add(""); + n += zerolen - 1; + } + else + { + words.Add(String.Format("{0:x}", value[n])); + } + } + + return string.Join(":", words); + } + } + public override string ToString() => ToString(true); + + public String ToCIDR() + { + return String.Format("{0}/{1}", ToString(true), mask); + } + + public static IPv6 Parse(string source) + { + int netmask = 128; + ushort[] address = new ushort[8]; + + int slash = source.IndexOf('/'); + if (slash != -1) + { + netmask = int.Parse(source.Substring(slash + 1)); + source = source.Substring(0, slash); + } + + bool hasColons = source.Contains(':'); + bool hasDots = source.Contains('.'); + + if (!hasColons && hasDots) // IPv4 + { + byte[] v4bytes = source.Split('.').Select((s) => byte.Parse(s)).ToArray(); + if (v4bytes.Length != 4) + throw new FormatException(); + + if (netmask != 128) + netmask += 96; + + address[5] = 0xffff; + address[6] = v4bytes.GetUShort(true); + address[7] = v4bytes.GetUShort(2, true); + } else if (hasColons) + { + string[] words = source.Split(':'); + + if (string.Empty.Equals(words[0])) + words = words.Slice(1); + if (string.Empty.Equals(words[words.Length - 1])) + words = words.Slice(0, words.Length - 1); + + if ((words.Length == 1) && (words[0].Equals(String.Empty))) + if (netmask == 0) + return IPv6.ANY; + + if (words.Length > 8) + throw new FormatException(); + + if (hasDots) + { + byte[] v4bytes = words[words.Length-1].Split('.').Select((s) => byte.Parse(s)).ToArray(); + if (v4bytes.Length != 4) + throw new FormatException(); + + address[5] = 0xffff; + address[6] = v4bytes.GetUShort(true); + address[7] = v4bytes.GetUShort(2, true); + } + else + { + int fill = 8 - words.Length; + int n = 0, m = 0; + while (n < words.Length) + { + if (String.Empty.Equals(words[n])) + { + m += fill; + } + else + { + address[m] = Convert.ToUInt16(words[n], 16); + } + m++; + n++; + } + + } + } + return new IPv6(address, (uint)netmask); + } + + public static IPv6 operator ++(IPv6 ip) => new IPv6(Words.Add(ip.value.BigEndian(), 1).BigEndian(), ip.mask); + public static IPv6 operator --(IPv6 ip) => new IPv6(Words.Del(ip.value.BigEndian(), 1).BigEndian(), ip.mask); + + public static IPv6 operator +(IPv6 ip, int b) => new IPv6(Words.Add(ip.value.BigEndian(), b).BigEndian(), ip.mask); + public static IPv6 operator -(IPv6 ip, int b) => new IPv6(Words.Del(ip.value.BigEndian(), b).BigEndian(), ip.mask); + + public static implicit operator IPAddress(IPv6 ip) => new IPAddress(ip.ToPackedBytes()); + public static implicit operator IPv6(IPAddress ip) => new IPv6(ip.GetAddressBytes()); + + public static implicit operator IPv6(String s) => IPv6.Parse(s); + + public override bool Equals(object obj) + { + if (obj is IPAddress) + obj = (IPv6)obj; + + if (obj is IPv6) + { + return value.SequenceEqual((obj as IPv6).value) && Equals(mask,(obj as IPv6).mask) ; + } + return false; + } + public override int GetHashCode() + { + int hash = 0; + for (int n = 0; n < 8; n++) + hash = (hash << 4) | value[n]; + return hash; + } + + } + +} diff --git a/MAC.cs b/MAC.cs new file mode 100644 index 0000000..c782a32 --- /dev/null +++ b/MAC.cs @@ -0,0 +1,72 @@ +using System; +using System.Globalization; +namespace ln.type +{ + public class MAC : IComparable + { + readonly byte[] mac; + + public byte[] Bytes => mac.Slice(0); + + public MAC() + { + mac = new byte[6]; + } + public MAC(byte[] macBytes) + :this() + { + if (macBytes.Length != 6) + throw new ArgumentOutOfRangeException(nameof(macBytes), "MAC bytes need to be exactly 6 bytes"); + + Array.Copy(macBytes, 0, this.mac, 0, 6); + } + public MAC(string smac) + :this() + { + string[] sbytes = null; + if (smac.Contains(":")) + sbytes = smac.Split(':'); + else + sbytes = smac.Split('-'); + + if (sbytes.Length != 6) + throw new ArgumentException(nameof(smac), "MAC needs 6 bytes"); + + for (int n = 0; n < 6; n++) + mac[n] = Convert.ToByte(sbytes[n], 16); + } + + public override string ToString() + { + return BitConverter.ToString(mac); + } + + public override int GetHashCode() + { + int hash = 0; + foreach (byte mb in mac) + hash = (hash << 16) ^ mb; + return hash; + } + + public override bool Equals(object obj) + { + if (obj is MAC) + { + return mac.AreEqual((obj as MAC).mac); + } + return false; + } + + public int CompareTo(MAC other) + { + for (int n=0;n<6;n++) + { + int d = mac[n] - other.mac[n]; + if (d != 0) + return d; + } + return 0; + } + } +} diff --git a/Promise.cs b/Promise.cs new file mode 100644 index 0000000..c0f767f --- /dev/null +++ b/Promise.cs @@ -0,0 +1,234 @@ +// /** +// * File: Promise.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +namespace ln.type +{ + public delegate void PromiseEvaluator(Action resolve, Action reject); + public delegate void PromiseEvaluator(I value, Action resolve, Action reject); + public delegate void PromiseResolved(T value); + public delegate void PromiseRejected(object error); + + public enum PromiseState { PENDING, RESOLVED, REJECTED } + + public class Promise + { + public event PromiseResolved OnResolve; + public event PromiseRejected OnReject; + + public PromiseState State { get; private set; } = PromiseState.PENDING; + + PromiseEvaluator Evaluator; + + T resolvedValue; + object reason; + + public T Value + { + get + { + if (State != PromiseState.RESOLVED) + throw new InvalidOperationException("promise not (yet) resolved"); + return resolvedValue; + } + } + public object Reason + { + get + { + if (State != PromiseState.REJECTED) + throw new InvalidOperationException("promise not (yet) rejected"); + return reason; + } + } + + private Promise() { } + + public Promise(PromiseEvaluator evaluator) : this(evaluator, true) { } + private Promise(PromiseEvaluator evaluator, bool queueJob) + { + Evaluator = evaluator; + if (queueJob) + ThreadPool.QueueUserWorkItem((state) => evaluator(resolve,reject )); + } + public Promise(Promise parent, Action fin) + { + OnResolve += (value) => fin(); + OnReject += (error) => fin(); + parent.OnResolve += (value) => this.Resolve(value); + parent.OnReject += (error) => this.Reject(error); + } + + protected Promise(PromiseResolved onResolve, PromiseRejected onReject) + { + OnResolve += onResolve; + OnReject += onReject; + } + protected Promise(PromiseRejected onReject) + { + OnReject += onReject; + } + + public Promise Then(PromiseResolved onResolve) => Then(onResolve, (e) => { }); + public Promise Then(PromiseResolved onResolve, PromiseRejected onRejected) => new ChainedPromise(this, (v, res, rej) => { res(v); onResolve(v); }, onRejected); + public Promise Finally(Action action) => new Promise(this, action); + + public Promise Then(PromiseEvaluator evaluator) => new ChainedPromise(this, evaluator, (e)=>{} ); + public Promise Then(PromiseEvaluator evaluator, PromiseRejected rejected) => new ChainedPromise(this, evaluator, rejected); + + + private void resolve(T value) + { + bool resolved; + lock (this) + { + resolved = (State == PromiseState.PENDING); + State = PromiseState.RESOLVED; + resolvedValue = value; + } + if (resolved) + OnResolve?.Invoke(value); + } + private void reject(object reason) + { + bool rejected; + lock (this) + { + rejected = (State == PromiseState.PENDING); + State = PromiseState.REJECTED; + this.reason = reason; + } + if (rejected) + OnReject?.Invoke(reason); + } + + public Promise Resolve(T value) + { + lock (this) + { + if (State != PromiseState.PENDING) + throw new InvalidOperationException("Promise already settled"); + + resolve(value); + } + return this; + } + public Promise Reject(object error) + { + lock (this) + { + if (State != PromiseState.PENDING) + throw new InvalidOperationException("Promise already settled"); + reject(error); + } + return this; + } + + public static Promise All(IEnumerable> promises) + { + Promise[] sources = promises.ToArray(); + T[] results = new T[sources.Length]; + int cresolved = 0; + + Promise promise = new Promise(); + for (int n = 0; n < sources.Length; n++) + { + Promise p = sources[n]; + int nn = n; + + lock (p) + { + switch (p.State) + { + case PromiseState.REJECTED: + return promise.Reject(p.Reason); + case PromiseState.RESOLVED: + cresolved++; + results[nn] = p.Value; + break; + case PromiseState.PENDING: + p.OnResolve += (value) => { + cresolved++; + results[nn] = p.Value; + + if (cresolved == results.Length) + promise.resolve(results); + }; + p.OnReject += (error) => { + promise.Reject(error); + }; + break; + } + } + } + if (cresolved == results.Length) + promise.resolve(results); + return promise; + } + + public static Promise Race(IEnumerable> promises) + { + Promise[] sources = promises.ToArray(); + Promise promise = new Promise(); + lock (promise) + { + for (int n = 0; n < sources.Length; n++) + { + Promise p = sources[n]; + int nn = n; + lock (p) + { + switch (p.State) + { + case PromiseState.REJECTED: + return promise.Reject(p.Reason); + case PromiseState.RESOLVED: + return promise.Resolve(p.Value); + case PromiseState.PENDING: + p.OnResolve += (value) => promise.resolve(value); + p.OnReject += (error) => promise.reject(error); + break; + } + } + } + } + return promise; + } + + class ChainedPromise : Promise + { + public ChainedPromise(Promise parent, PromiseEvaluator evalOnResolve, PromiseRejected onReject) + :base(onReject) + { + parent.OnResolve += (value) => { + evalOnResolve( + value, + (obj) => this.Resolve(obj), + (error) => this.Reject(error) + ); + }; + parent.OnReject += (error) => this.Reject(error); + } + } + + public static implicit operator Promise(T value) => new Promise().Resolve(value); + } + + public class Promise : Promise + { + public Promise(PromiseEvaluator evaluator) + : base(evaluator) + { + } + } +} diff --git a/TypeExtensions.cs b/TypeExtensions.cs new file mode 100644 index 0000000..c33b814 --- /dev/null +++ b/TypeExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Linq; +namespace ln.type +{ + public static class TypeExtensions + { + + public static bool HasGenericInterface(this Type type) => HasGenericInterface(type, typeof(T).GetGenericTypeDefinition()); + public static bool HasGenericInterface(this Type type, Type genericInterfaceType) + { + return type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericInterfaceType); + } + + public static Type GetGenericInterface(this Type type) => GetGenericInterface(type, typeof(T).GetGenericTypeDefinition()); + public static Type GetGenericInterface(this Type type, Type genericInterfaceType) + { + return type.GetInterfaces().First(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericInterfaceType); + } + + } +} diff --git a/URI.cs b/URI.cs new file mode 100644 index 0000000..f50d92c --- /dev/null +++ b/URI.cs @@ -0,0 +1,246 @@ +// /** +// * File: URI.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Text; +namespace ln.type +{ + /** + * Quick and Dirty RFC3986 URI + * + **/ + + public class URI + { + public String Scheme { get; private set; } = String.Empty; + public String Authority { get; private set; } = String.Empty; + + public String[] UserInfo { get; private set; } = new String[0]; + public String Host { get; private set; } = String.Empty; + public String Port { get; private set; } = String.Empty; + + public String Path { get; private set; } = String.Empty; + public String Query { get; private set; } = String.Empty; + public String Fragment { get; private set; } = String.Empty; + + private URI() + { + } + + public URI(String uri) + { + Parse(uri); + ParseAuthority(); + } + public URI(String scheme, String authority, string path) + { + Parse(String.Format("{0}://{1}{2}", scheme, authority, path)); + ParseAuthority(); + } + public URI(String scheme,String authority,string path,string query,string fragment) + { + Scheme = scheme; + Authority = authority; + Path = path; + Query = query; + Fragment = fragment; + ParseAuthority(); + } + + public URI(URI uri, string path) + { + Parse(String.Format("{0}://{1}{2}", uri.Scheme, uri.Authority, path)); + ParseAuthority(); + } + + public URI Follow(String path) + { + if (path.StartsWith("/",StringComparison.InvariantCulture)) + { + return new URI(Scheme, Authority, path); + } else if (Path.EndsWith("/",StringComparison.InvariantCulture) || path.StartsWith("?",StringComparison.InvariantCulture) || path.StartsWith("#", StringComparison.InvariantCulture)) + { + return new URI(Scheme, Authority, String.Format("{0}{1}", Path, path)); + } + else + { + int indSlash = Path.LastIndexOf('/'); + return new URI(Scheme, Authority, String.Format("{0}/{1}",Path.Substring(0,indSlash),path)); + } + } + + + private void Parse(String uri) + { + char[] chUri = uri.ToCharArray(); + int n = 0; + int m = 0; + + // Scheme + + while ((chUri[n] != ':') && ((++n) < chUri.Length)) { }; + + if (n < 2) + throw new FormatException(String.Format("URL malformed: {0}",uri)); + + Scheme = new string(chUri, 0, n); + n++; + + if (n < chUri.Length) + { + if ((chUri.Length - n > 1) && (chUri[n] == '/') && (chUri[n+1] == '/')) + { + // Authority + n += 2; + m = n; + + while ( + (m < chUri.Length) && + (chUri[m] != '/') && + (chUri[m] != '?') && + (chUri[m] != '#') + ) { m++; } + + Authority = new string(chUri, n, (m - n)); + n = m; + } + + // Path + m = n; + while ( + (m < chUri.Length) && + (chUri[m] != '?') && + (chUri[m] != '#') + ) + { m++; } + + Path = new string(chUri, n, (m - n)); + n = m; + + if (n < chUri.Length) + { + if (chUri[n] == '?') + { + n++; + m = n; + while ( + (m < chUri.Length) && + (chUri[m] != '#') + ) + { m++; } + + Query = new string(chUri, n, (m - n)); + n = m; + } + if ((n 0) + { + stringBuilder.Append(UserInfo[0]); + stringBuilder.Append('@'); + } + + stringBuilder.Append(Host); + + if (!String.Empty.Equals(Port)) + { + stringBuilder.Append(':'); + stringBuilder.Append(Port); + } + } + + stringBuilder.Append(Path); + + if (!string.Empty.Equals(Query)) + { + stringBuilder.Append("?"); + stringBuilder.Append(Query); + } + if (!string.Empty.Equals(Fragment)) + { + stringBuilder.Append('#'); + stringBuilder.Append(Fragment); + } + + return stringBuilder.ToString(); + } + + private int GetHashCode(String s) + { + return (s == null) ? -1 : s.GetHashCode(); + } + + public override int GetHashCode() + { + return GetHashCode(Scheme) ^ GetHashCode(Authority) ^ GetHashCode(Path) ^ GetHashCode(Query) ^ GetHashCode(Fragment); + } + + public override bool Equals(object obj) + { + if (obj is URI) + { + URI other = obj as URI; + return Scheme.Equals(other.Scheme) && Authority.Equals(other.Authority) && Path.Equals(other.Path) && Query.Equals(other.Query) && Fragment.Equals(other.Fragment); + } + return false; + } + + } +} diff --git a/arithmetics/Words.cs b/arithmetics/Words.cs new file mode 100644 index 0000000..3d6cabd --- /dev/null +++ b/arithmetics/Words.cs @@ -0,0 +1,123 @@ +using System; +namespace ln.type.arithmetics +{ + public static class Words + { + + public static UInt16[] Add(UInt16[] a, UInt16 b) + { + UInt16[] b2 = new ushort[a.Length]; + b2[0] = b; + return Add(a, b2); + } + public static UInt16[] Add(UInt16[] a, int b) + { + UInt16[] b2 = new ushort[a.Length]; + b2[0] = (ushort)(b & 0xffff); + if (b2.Length > 1) + b2[1] = (ushort)((b >> 16) & 0xffff); + + return Add(a, b2); + } + + public static UInt16[] Add(UInt16[] a, UInt16[] b) + { + UInt16[] result = new ushort[a.Length > b.Length ? a.Length : b.Length]; + int m = 0; + + for (int n = 0; n < result.Length; n++) + { + m += (n < a.Length ? a[n] : 0) + (n < b.Length ? b[n] : 0); + result[n] = (ushort)(m & 0xFFFF); + m >>= 16; + } + + return result; + } + + public static UInt16[] Del(UInt16[] a, UInt16 b) + { + UInt16[] b2 = new ushort[a.Length]; + b2[0] = b; + return Del(a, b2); + } + public static UInt16[] Del(UInt16[] a, int b) + { + UInt16[] b2 = new ushort[a.Length]; + b2[0] = (ushort)(b & 0xffff); + if (b2.Length > 1) + b2[1] = (ushort)((b >> 16) & 0xffff); + + return Del(a, b2); + } + public static UInt16[] Del(UInt16[] a, UInt16[] b) + { + UInt16[] result = new ushort[a.Length > b.Length ? a.Length : b.Length]; + int m = 0; + + for (int n = 0; n < result.Length; n++) + { + m += (n < a.Length ? a[n] : 0) - (n < b.Length ? b[n] : 0); + result[n] = (ushort)(m & 0xFFFF); + m >>= 16; + } + + return result; + } + public static UInt16[] And(UInt16[] a, UInt16[] b) + { + UInt16[] result = new ushort[a.Length > b.Length ? a.Length : b.Length]; + + for (int n = 0; n < result.Length; n++) + { + result[n] = (ushort)((n < a.Length ? a[n] : 0) & (n < b.Length ? b[n] : 0)); + } + + return result; + } + public static UInt16[] Or(UInt16[] a, UInt16[] b) + { + UInt16[] result = new ushort[a.Length > b.Length ? a.Length : b.Length]; + + for (int n = 0; n < result.Length; n++) + { + result[n] = (ushort)((n < a.Length ? a[n] : 0) | (n < b.Length ? b[n] : 0)); + } + + return result; + } + + public static UInt16[] SHL(UInt16[] src,int shift) + { + UInt16[] result = new ushort[src.Length]; + int step = (shift >> 4); + shift &= 0xF; + + uint m = 0; + + for (int n = 0; (n+step) < src.Length; n++) + { + m |= src[n]; + m <<= shift; + + result[n + step] |= (ushort)(m & 0xFFFF); + m >>= 16; + } + + return result; + } + + + + public static ushort[] BigEndian(this ushort[] bytes) + { + if (BitConverter.IsLittleEndian) + { + bytes = bytes.Slice(0); + Array.Reverse(bytes); + } + return bytes; + } + + } +} diff --git a/data/Country.cs b/data/Country.cs new file mode 100644 index 0000000..4ebd2ef --- /dev/null +++ b/data/Country.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ln.type.data +{ + class Country + { + public static Country US = new Country("us", "1", "Vereinigte Staaten von Amerika"); + public static Country DE = new Country("de", "49", "Deutschland"); + public static Country AT = new Country("au", "43", "Österreich"); + public static Country CH = new Country("ch", "41", "Schweiz"); + + public string ISO { get; } + public string PhonePrefix { get; } + public string Name { get; } + + public Country(string iso,string phone,string name) + { + this.ISO = iso.ToUpper(); + this.PhonePrefix = phone; + this.Name = name; + } + + + + } +} diff --git a/ln.type.csproj b/ln.type.csproj new file mode 100644 index 0000000..18c158b --- /dev/null +++ b/ln.type.csproj @@ -0,0 +1,17 @@ + + + + netcoreapp3.1 + true + 0.1.0 + Harald Wolff-Thobaben + l--n.de + 0.0.1.0 + 0.0.1.0 + + + + + + + diff --git a/rpc/RPCCall.cs b/rpc/RPCCall.cs new file mode 100644 index 0000000..fc83f0a --- /dev/null +++ b/rpc/RPCCall.cs @@ -0,0 +1,19 @@ +using System; +namespace ln.type.rpc +{ + public class RPCCall + { + public object Identifier { get; set; } + + public String ModuleName { get; set; } + public string MethodName { get; set; } + + public object[] Parameters { get; set; } + + public RPCCall() + { + Identifier = Guid.NewGuid(); + } + + } +} diff --git a/rpc/RPCContainer.cs b/rpc/RPCContainer.cs new file mode 100644 index 0000000..4bc8a9d --- /dev/null +++ b/rpc/RPCContainer.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; +namespace ln.type.rpc +{ + public class PublishAttribute : Attribute + { + } + + public class RPCContainer + { + Dictionary modules = new Dictionary(); + + Func checkAccessHook; + + public RPCContainer() + { + } + public RPCContainer(Func checkAccessHook) + { + this.checkAccessHook = checkAccessHook; + + } + + public void Add(object moduleInstance) => Add(moduleInstance.GetType().Name, moduleInstance); + public void Add(string moduleName,object moduleInstance) + { + if (modules.ContainsKey(moduleName)) + throw new ArgumentOutOfRangeException(nameof(moduleName), "Module with same name already added"); + + RPCModule rpcModule = new RPCModule(this,moduleName,moduleInstance); + modules.Add(moduleName, rpcModule); + } + + public void Remove(string moduleName) + { + modules.Remove(moduleName); + } + public void Remove(object moduleInstance) + { + foreach (RPCModule module in modules.Values) + { + if (module.ModuleInstance == moduleInstance) + { + modules.Remove(module.Name); + return; + } + } + } + + public RPCResult Invoke(RPCCall call) + { + if ((call.ModuleName != null) && !modules.ContainsKey(call.ModuleName)) + throw new KeyNotFoundException(call.ModuleName); + + RPCModule rpcModule = call.ModuleName != null ? modules[call.ModuleName] : modules[""]; + return rpcModule.Invoke(call); + } + + public class RPCModule + { + public RPCContainer Container { get; } + + public String Name { get; } + public object ModuleInstance { get; } + + public Dictionary methodInfos = new Dictionary(); + + public RPCModule(RPCContainer container,string moduleName,object instance) + { + Container = container; + + Name = moduleName; + ModuleInstance = instance; + + Initialize(ModuleInstance.GetType()); + } + public RPCModule(RPCContainer container,string moduleName,Type type) + { + Container = container; + + Name = moduleName; + ModuleInstance = null; + + Initialize(type); + } + + private void Initialize(Type type) + { + foreach (MethodInfo methodInfo in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)) + { + if (methodInfo.IsStatic || !Object.ReferenceEquals(ModuleInstance,null) ) + { + if (methodInfo.IsPublic || (methodInfo.GetCustomAttribute() != null)) + { + methodInfos.Add(methodInfo.Name, methodInfo); + } + } + } + } + + public RPCResult Invoke(RPCCall call) + { + if (!Name.Equals(call.ModuleName) && (call.ModuleName != null)) + throw new ArgumentOutOfRangeException(nameof(call.ModuleName), "RPC: Invoke called for wrong module"); + + try + { + if (!methodInfos.ContainsKey(call.MethodName)) + throw new KeyNotFoundException(call.MethodName); + + MethodInfo methodInfo = methodInfos[call.MethodName]; + ParameterInfo[] parameterInfos = methodInfo.GetParameters(); + + object[] parameters = new object[parameterInfos.Length]; + for (int n = 0; n < parameters.Length; n++) + { + Type pType = parameterInfos[n].ParameterType; + if (pType.Equals(typeof(Guid))) + { + parameters[n] = Guid.Parse(call.Parameters[n].ToString()); + } else if (pType.IsArray) + { + Type eType = pType.GetElementType(); + object[] src = (object[])call.Parameters[n]; + Array a = Array.CreateInstance(eType, src.Length); + + for (int m=0;m