From 7d9e542ffbfd6ac46006d3f8f12dc13f9a53ffbb Mon Sep 17 00:00:00 2001 From: "U-WALDRENNACH\\haraldwolff" Date: Tue, 17 Nov 2020 23:48:34 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 41 +++++ ByteArrayExtensions.cs | 75 ++++++++ Cast.cs | 103 +++++++++++ Date.cs | 25 +++ DvDt.cs | 41 +++++ Endpoint.cs | 69 ++++++++ Extensions.cs | 394 +++++++++++++++++++++++++++++++++++++++++ Factory.cs | 10 ++ GeoLocation.cs | 34 ++++ IPv6.cs | 335 +++++++++++++++++++++++++++++++++++ MAC.cs | 72 ++++++++ Promise.cs | 234 ++++++++++++++++++++++++ TypeExtensions.cs | 21 +++ URI.cs | 246 +++++++++++++++++++++++++ arithmetics/Words.cs | 123 +++++++++++++ data/Country.cs | 28 +++ ln.type.csproj | 17 ++ rpc/RPCCall.cs | 19 ++ rpc/RPCContainer.cs | 174 ++++++++++++++++++ rpc/RPCResult.cs | 30 ++++ 20 files changed, 2091 insertions(+) create mode 100644 .gitignore create mode 100644 ByteArrayExtensions.cs create mode 100644 Cast.cs create mode 100644 Date.cs create mode 100644 DvDt.cs create mode 100644 Endpoint.cs create mode 100644 Extensions.cs create mode 100644 Factory.cs create mode 100644 GeoLocation.cs create mode 100644 IPv6.cs create mode 100644 MAC.cs create mode 100644 Promise.cs create mode 100644 TypeExtensions.cs create mode 100644 URI.cs create mode 100644 arithmetics/Words.cs create mode 100644 data/Country.cs create mode 100644 ln.type.csproj create mode 100644 rpc/RPCCall.cs create mode 100644 rpc/RPCContainer.cs create mode 100644 rpc/RPCResult.cs 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