Initial Commit

master
U-WALDRENNACH\haraldwolff 2020-11-17 23:48:34 +01:00
commit 7d9e542ffb
20 changed files with 2091 additions and 0 deletions

41
.gitignore vendored 100644
View File

@ -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

View File

@ -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;
}
}
}

103
Cast.cs 100644
View File

@ -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<T>(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;
}
}
}

25
Date.cs 100644
View File

@ -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();
}
}

41
DvDt.cs 100644
View File

@ -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;
}
}
}
}

69
Endpoint.cs 100644
View File

@ -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);
}
}

394
Extensions.cs 100644
View File

@ -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<T>(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<T>(this T[] me, IEnumerable<T> other)
{
HashSet<T> elements = new HashSet<T>(me);
foreach (T e in other)
elements.Add(e);
return elements.ToArray();
}
public static T[] Remove<T>(this T[] me, IEnumerable<T> remove)
{
HashSet<T> elements = new HashSet<T>(me);
foreach (T e in remove)
elements.Remove(e);
return elements.ToArray();
}
public static bool AreEqual<T>(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<T>(this T[] me, int offset) => Slice(me, offset, me.Length - offset);
public static T[] Slice<T>(this T[] me, ref int offset) => Slice(me, ref offset, me.Length - offset);
public static T[] Slice<T>(this T[] me, int offset, int length) => Slice(me, ref offset, length);
public static T[] Slice<T>(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;
}
}
}

10
Factory.cs 100644
View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ln.type
{
public delegate T Factory<T>();
public delegate T Factory<T,R>(R requester);
}

34
GeoLocation.cs 100644
View File

@ -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'
);
}
}
}

335
IPv6.cs 100644
View File

@ -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<IPv6> Split(int splitWidth)
{
List<IPv6> splitted = new List<IPv6>();
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<<splitWidth);n++)
{
splitted.Add(ip);
ip = new IPv6(Words.Add(ip.value.BigEndian(), increment).BigEndian(), ip.mask);
}
return splitted;
}
public string ToString(bool shorten)
{
if (!shorten)
{
return string.Join(":", value.Select((w) => 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<string> words = new List<string>();
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;
}
}
}

72
MAC.cs 100644
View File

@ -0,0 +1,72 @@
using System;
using System.Globalization;
namespace ln.type
{
public class MAC : IComparable<MAC>
{
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;
}
}
}

234
Promise.cs 100644
View File

@ -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<T>(Action<T> resolve, Action<object> reject);
public delegate void PromiseEvaluator<I,O>(I value, Action<O> resolve, Action<object> reject);
public delegate void PromiseResolved<T>(T value);
public delegate void PromiseRejected(object error);
public enum PromiseState { PENDING, RESOLVED, REJECTED }
public class Promise<T>
{
public event PromiseResolved<T> OnResolve;
public event PromiseRejected OnReject;
public PromiseState State { get; private set; } = PromiseState.PENDING;
PromiseEvaluator<T> 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<T> evaluator) : this(evaluator, true) { }
private Promise(PromiseEvaluator<T> evaluator, bool queueJob)
{
Evaluator = evaluator;
if (queueJob)
ThreadPool.QueueUserWorkItem((state) => evaluator(resolve,reject ));
}
public Promise(Promise<T> parent, Action fin)
{
OnResolve += (value) => fin();
OnReject += (error) => fin();
parent.OnResolve += (value) => this.Resolve(value);
parent.OnReject += (error) => this.Reject(error);
}
protected Promise(PromiseResolved<T> onResolve, PromiseRejected onReject)
{
OnResolve += onResolve;
OnReject += onReject;
}
protected Promise(PromiseRejected onReject)
{
OnReject += onReject;
}
public Promise<T> Then(PromiseResolved<T> onResolve) => Then(onResolve, (e) => { });
public Promise<T> Then(PromiseResolved<T> onResolve, PromiseRejected onRejected) => new ChainedPromise<T>(this, (v, res, rej) => { res(v); onResolve(v); }, onRejected);
public Promise<T> Finally(Action action) => new Promise<T>(this, action);
public Promise<S> Then<S>(PromiseEvaluator<T, S> evaluator) => new ChainedPromise<S>(this, evaluator, (e)=>{} );
public Promise<S> Then<S>(PromiseEvaluator<T, S> evaluator, PromiseRejected rejected) => new ChainedPromise<S>(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<T> Resolve(T value)
{
lock (this)
{
if (State != PromiseState.PENDING)
throw new InvalidOperationException("Promise already settled");
resolve(value);
}
return this;
}
public Promise<T> Reject(object error)
{
lock (this)
{
if (State != PromiseState.PENDING)
throw new InvalidOperationException("Promise already settled");
reject(error);
}
return this;
}
public static Promise<T[]> All(IEnumerable<Promise<T>> promises)
{
Promise<T>[] sources = promises.ToArray();
T[] results = new T[sources.Length];
int cresolved = 0;
Promise<T[]> promise = new Promise<T[]>();
for (int n = 0; n < sources.Length; n++)
{
Promise<T> 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<T> Race(IEnumerable<Promise<T>> promises)
{
Promise<T>[] sources = promises.ToArray();
Promise<T> promise = new Promise<T>();
lock (promise)
{
for (int n = 0; n < sources.Length; n++)
{
Promise<T> 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<O> : Promise<O>
{
public ChainedPromise(Promise<T> parent, PromiseEvaluator<T,O> 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>(T value) => new Promise<T>().Resolve(value);
}
public class Promise : Promise<Object>
{
public Promise(PromiseEvaluator<object> evaluator)
: base(evaluator)
{
}
}
}

21
TypeExtensions.cs 100644
View File

@ -0,0 +1,21 @@
using System;
using System.Linq;
namespace ln.type
{
public static class TypeExtensions
{
public static bool HasGenericInterface<T>(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<T>(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);
}
}
}

246
URI.cs 100644
View File

@ -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<chUri.Length) && (chUri[n] == '#'))
{
n++;
m = n;
while (
(m < chUri.Length) &&
(chUri[m] != '#')
)
{ m++; }
Fragment = new string(chUri, n, (m - n));
n = m;
}
if (n < chUri.Length)
throw new FormatException(String.Format("Malformed URI: {0}", uri));
}
}
}
private void ParseAuthority()
{
int indAt = Authority.IndexOf('@');
if (indAt != -1)
{
UserInfo = Authority.Substring(0, indAt).Split(':');
}
indAt++;
int indPort = Authority.IndexOf(':', indAt);
if (indPort != -1)
{
Host = Authority.Substring(indAt, indPort - indAt);
Port = Authority.Substring(indPort + 1);
}
else
{
Host = Authority.Substring(indAt);
}
}
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(Scheme);
stringBuilder.Append(':');
if (!String.Empty.Equals(Authority))
{
stringBuilder.Append("//");
if (UserInfo.Length > 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;
}
}
}

View File

@ -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;
}
}
}

28
data/Country.cs 100644
View File

@ -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;
}
}
}

17
ln.type.csproj 100644
View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>0.1.0</Version>
<Authors>Harald Wolff-Thobaben</Authors>
<Company>l--n.de</Company>
<AssemblyVersion>0.0.1.0</AssemblyVersion>
<FileVersion>0.0.1.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Runtime" Version="4.3.1" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
</ItemGroup>
</Project>

19
rpc/RPCCall.cs 100644
View File

@ -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();
}
}
}

174
rpc/RPCContainer.cs 100644
View File

@ -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<string, RPCModule> modules = new Dictionary<string, RPCModule>();
Func<RPCContainer, RPCModule, MethodInfo, bool> checkAccessHook;
public RPCContainer()
{
}
public RPCContainer(Func<RPCContainer, RPCModule, MethodInfo, bool> 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<string, MethodInfo> methodInfos = new Dictionary<string, MethodInfo>();
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<PublishAttribute>() != 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<src.Length;m++)
{
a.SetValue(Convert.ChangeType(src[m], eType), m);
}
parameters[n] = a;
}
else
{
parameters[n] = ImplicitCast(parameterInfos[n].ParameterType, call.Parameters[n]);
if (parameters[n] == null)
parameters[n] = Convert.ChangeType(call.Parameters[n], parameterInfos[n].ParameterType);
}
}
object result = null;
if ((Container.checkAccessHook == null) || Container.checkAccessHook(Container,this,methodInfo))
result = methodInfo.Invoke(ModuleInstance, parameters);
return new RPCResult(call, result);
} catch (Exception e)
{
return new RPCResult(call, e);
}
}
public object ImplicitCast(Type targetType,object value)
{
foreach (MethodInfo methodInfo in targetType.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())))
{
return methodInfo.Invoke(null, new object[] { value });
}
}
}
return null;
}
}
}
}

30
rpc/RPCResult.cs 100644
View File

@ -0,0 +1,30 @@
using System;
namespace ln.type.rpc
{
public class RPCResult
{
public object Identifier { get; set; }
public object Result { get; set; }
public String ErrorText { get; set; }
public Exception Exception { get; set; }
public RPCResult(RPCCall call)
{
Identifier = call.Identifier;
}
public RPCResult(RPCCall call,object result)
{
Identifier = call.Identifier;
Result = result;
}
public RPCResult(RPCCall call,Exception e)
{
Identifier = call.Identifier;
Exception = e;
ErrorText = e.ToString();
}
}
}