//-------------------------------------------------------------------------------------------------------------------------------------- public bool RemoveEventHandler <T>(EventCb <T> cb) { //null check if (cb == null) { return(false); } //Get route var evType = typeof(T); lock (_ActiveRoutes) { var allRoutesForType = _ActiveRoutes.TryGetOrDefault(evType); //check if handlers are registered for this event type if (allRoutesForType == null) { DebugEx.Assert("no such event found registered"); return(false); } //Remove from route var removed = allRoutesForType.RemoveWhere(h => Object.Equals(h.Cb, cb)) > 0; //check if this event type has any other handlers, otherwise remove the type as well if (allRoutesForType.Count == 0) { _ActiveRoutes.Remove(evType); } //return if something has been removed or not return(removed); } }
//----------------------------------------------------------------------------------------------------------------------------------------------------- public static bool TryAdd <TKey, TValue>(this IDictionary <TKey, TValue> dictionary, TKey key, TValue value, bool overwrite = false) { DebugEx.Assert(key != null, "Null key used in dictionary access"); if (dictionary == null || key == null) { return(false); } try { if (dictionary.ContainsKey(key) == false) { dictionary.Add(key, value); return(true); } else { if (!overwrite) { return(false); } else { dictionary[key] = value; return(true); } } } catch { return(false); } }
//------------------------------------------------------------------------------------------------------------------------ #endregion #region Functions //------------------------------------------------------------------------------------------------------------------------ public void Start() { DebugEx.Assert(this.RequestHandler != null, $"You cannot start a {nameof(RequestQueueConsumer)} class without first having set a handler"); lock (RequestQueue) { if (_IsAlive) { return; } //set alive flag _IsAlive = true; //start heartbeat #if UNIVERSAL heartbeat = Task.Factory.StartNew((Action)HeartBeatEntryPoint, TaskCreationOptions.LongRunning); heartbeat.Start(); #else heartbeat = new Thread(HeartBeatEntryPoint); heartbeat.Name = "RQC heartbeat"; heartbeat.IsBackground = true; heartbeat.Start(); #endif } }
//---------------------------------------------------------------------------------------------------------------------------------------------- public static T GetRandomItem <T>(T[] source, out int Index, Func <int, bool> filter = null, int MaxRetries = 10) { Index = -1; DebugEx.Assert(source != null, "Null source detected"); DebugEx.Assert(source != null && source.Length > 0, "Source has no elements"); if (source == null || source.Length == 0) { return(default(T)); } else { lock (objRandom) { lock (objRandom) Index = objRandom.Next(0, (source.Length - 1 + 1)); //filter and retry if (filter != null) { while (!filter(Index)) { if (MaxRetries <= 0) { Index = -1; return(default(T)); } MaxRetries--; lock (objRandom) Index = objRandom.Next(0, (source.Length - 1 + 1)); } } return(source[Index]); } } }
//-------------------------------------------------------------------------------------------------------------------------------------- public bool AddEventHandler <T>(EventCb <T> cb, int priority, bool receiveDerivedTypeEvents = true) { //null check if (cb == null) { DebugEx.Assert("Cannot give Null callback for YEventRouter"); return(false); } //Get or create route var evType = typeof(T); SortedSetTS <EvHandler> allRoutesForType; lock (_ActiveRoutes) { allRoutesForType = _ActiveRoutes.TryGetOrDefault(evType); if (allRoutesForType == null) { allRoutesForType = _ActiveRoutes[evType] = new SortedSetTS <EvHandler>(s_EvHandlerCmp); } //add to route return(allRoutesForType.Add(new EvHandler() { Cb = cb, Priority = priority, ReceiveDerivedTypeEvents = receiveDerivedTypeEvents, RunAsync = false })); } }
//----------------------------------------------------------------------------------------------------------------------------------------------------- public virtual void ForceAdd(TKey key, TValue value) { DebugEx.Assert(key != null, "Null key used in dictionary access"); if (key == null) { return; } //perform operation lock (locker) { IncreaseRevision(); if (InternalObject == null) { InternalObject = new Dictionary <TKey, TValue>(); InternalObject.Add(key, value); } else if (InternalObject.ContainsKey(key) == false) { InternalObject.Add(key, value); } else { InternalObject[key] = value; } } }
//------------------------------------------------------------------------------------------------------------------------ public virtual bool Remove(TKey key) { DebugEx.Assert(key != null, "Null key used in dictionary access"); if (key == null) { return(false); } //perform operation lock (locker) { if (InternalObject != null && InternalObject.Remove(key)) { IncreaseRevision(); if (InternalObject.Count == 0) { InternalObject = null; } return(true); } else { return(false); } } }
public static IEnumerable <Assembly> GetAssemblies() { #if NETFX lock (_assemblyCache) { if (_assemblyCache.Length == 0 || entriesCount != EntryAssemblies.Count) { //mark for cache invalidation entriesCount = EntryAssemblies.Count; //declares var visitedAssemblies = new HashSet <Assembly>(); var visitedAssemblyNames = new HashSet <string>(); var stack = new Stack <Assembly>(); //initialize DebugEx.Assert(EntryAssemblies.Count > 0, "EntryAssemblies are empty"); foreach (var entry in EntryAssemblies) { stack.Push(entry); visitedAssemblies.Add(entry); try { visitedAssemblyNames.Add(entry.FullName); } catch { } } //consume stack do { var asm = stack.Pop(); foreach (var reference in asm.GetReferencedAssemblies()) { try { if (!visitedAssemblyNames.Contains(reference.FullName)) { var assembly = Assembly.Load(reference); if (assembly != null) { stack.Push(assembly); visitedAssemblies.Add(assembly); try { visitedAssemblyNames.Add(reference.FullName); } catch { } } } } catch { } } }while (stack.Count > 0); //cache them _assemblyCache = visitedAssemblies.ToArray(); } //return cached assemblies return(_assemblyCache); } #elif UNIVERSAL return(EntryAssemblies); #endif }
//---------------------------------------------------------------------------------------------------------------------------------------------- static void errorHandler(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) { DebugEx.Assert(args.ErrorContext.Error, "JSON deserialization error, Path=" + args.ErrorContext.Path); //mark error as handled if (args != null && args.ErrorContext != null) { args.ErrorContext.Handled = true; } }
//---------------------------------------------------------------------------------------------------------------------------------------------- #if NETFX public static int GetPort(this EndPoint endpoint) { if (endpoint is IPEndPoint) { return(((IPEndPoint)endpoint).Port); } else { DebugEx.Assert("Could not parse endpoint"); return(-1); } }
//---------------------------------------------------------------------------------------------------------------------------------------------- #if NETFX public static IPAddress GetIPAddress(this EndPoint endpoint) { if (endpoint is IPEndPoint) { return(((IPEndPoint)endpoint).Address); } else { DebugEx.Assert("Could not parse endpoint"); return(default(IPAddress)); } }
public static Task RunSafe(Action action, bool AssertException = true) { return(Task.Run(() => { try { action(); } catch (Exception ex) { if (AssertException) { DebugEx.Assert(ex); } } })); }
public static readonly string Platform = "UWP"; //Universal Windows Platform #endif static EnvironmentEx() { #if NETFX //find home user path UserHomePath = IsRunningOnUnix ? Environment.GetEnvironmentVariable("HOME") : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); //check if (string.IsNullOrWhiteSpace(UserHomePath)) { DebugEx.Assert("Could not find use home path"); UserHomePath = string.Empty; } #endif }
//----------------------------------------------------------------------------------------------------------------------------------------------------- public static TValue TryGetOrDefaultReadOnly <TKey, TValue>(this IReadOnlyDictionary <TKey, TValue> dictionary, TKey Key, TValue Default = default(TValue)) { TValue val; DebugEx.Assert(Key != null, "Null key used in dictionary access"); if (dictionary != null && Key != null && dictionary.TryGetValue(Key, out val)) { return(val); } else { return(Default); } }
//----------------------------------------------------------------------------------------------------------------------------------------------------- public static TValueOut TryGetOrDefault <TKey, TValue, TValueOut>(this IDictionary <TKey, TValue> dictionary, TKey Key, Func <TValue, TValueOut> Transform, TValueOut Default = default(TValueOut)) { TValue val; DebugEx.Assert(Key != null, "Null key used in dictionary access"); if (dictionary != null && Key != null && dictionary.TryGetValue(Key, out val)) { return(Transform(val)); } else { return(Default); } }
public static Task <T> RunSafe <T>(Func <T> action, bool AssertException = true, T Default = default(T)) { return(Task.Run(() => { try { return action(); } catch (Exception ex) { if (AssertException) { DebugEx.Assert(ex); } return Default; } })); }
public static T GetRandomItem <T>(T[] source, out int Index) { Index = -1; DebugEx.Assert(source != null, "Null source detected"); DebugEx.Assert(source != null && source.Length > 0, "Source has no elements"); if (source == null || source.Length == 0) { return(default(T)); } else { lock (objRandom) Index = objRandom.Next(0, (source.Length - 1 + 1)); return(source[Index]); } }
//------------------------------------------------------------------------------------------------------------------------ public void Enqueue(T req) { lock (RequestQueue) { //flooding check if (RequestQueue.Count >= MaxQueuedRequests) { if (FloodingProtection == FloodingProtectionMethods.DropRequest) { return; } else if (FloodingProtection == FloodingProtectionMethods.BlockRequestThread) { Interlocked.Increment(ref floodLockerWaiting); //spin until thread can enqueue request while (true) { lock (floodLocker) { Monitor.Exit(RequestQueue); Monitor.Wait(floodLocker); } Monitor.Enter(RequestQueue); if (RequestQueue.Count < MaxQueuedRequests) { break; } } Interlocked.Decrement(ref floodLockerWaiting); } else { DebugEx.Assert("Unkown flooding protection"); return; } } //enqueue RequestQueue.Enqueue(req); //pulse heartbeat Monitor.Pulse(RequestQueue); } }
//------------------------------------------------------------------------------------------------------------------------ public virtual bool ContainsKey(TKey key) { DebugEx.Assert(key != null, "Null key used in dictionary access"); if (key == null) { return(false); } //perform operation lock (locker) if (InternalObject == null) { return(false); } else { return(InternalObject.ContainsKey(key)); } }
public static Task RunSafe(Action action, string Message = "TaskEx.RunSafe exception caught", bool AssertException = true) { if (action == null) { return(null); } else { return(Task.Run(() => { try { action(); } catch (Exception ex) { if (AssertException) { DebugEx.Assert(ex, Message); } } })); } }
//----------------------------------------------------------------------------------------------------------------------------------------------------- public static void ForceAdd <TKey, TValue>(this IDictionary <TKey, TValue> dictionary, TKey key, TValue value) { DebugEx.Assert(key != null, "Null key used in dictionary access"); if (dictionary == null || key == null) { return; } try { if (dictionary.ContainsKey(key) == false) { dictionary.Add(key, value); } else { dictionary[key] = value; } } catch { } }
//---------------------------------------------------------------------------------------------------------------------------------------------- public static byte[] ReadToEnd <T>(this T stream) where T : Stream { //find remaining length var len = (stream.Length - stream.Position); if (len <= 0) { DebugEx.Assert(len >= 0, "Negative length detected"); return(new byte[0]); } //read var buffer = new byte[len]; var offset = 0; while (offset < len) { offset += stream.Read(buffer, offset, (int)(len - offset)); } return(buffer); }
//---------------------------------------------------------------------------------------------------------------------------------------------- public static Delegate CreateDelegate(this MethodInfo mi, object Target) { DebugEx.Assert(mi != null, "Could not create delegate"); try { if (mi == null) { return(null); } Type delegateType; var typeArgs = mi.GetParameters() .Select(p => p.ParameterType) .ToList(); //create delegate type delegateType = System.Linq.Expressions.Expression.GetDelegateType ( mi.GetParameters() .Select(p => p.ParameterType) .Concat(new Type[] { mi.ReturnType }) .ToArray() ); #if NETFX // creates a binded delegate if target is supplied var result = (Target == null | mi.IsStatic) ? Delegate.CreateDelegate(delegateType, mi) : Delegate.CreateDelegate(delegateType, Target, mi); #elif UNIVERSAL var result = (Target == null | mi.IsStatic) ? mi.CreateDelegate(delegateType, null) : mi.CreateDelegate(delegateType, Target); #endif return(result); } catch// (Exception ex) { return(null); } }
static JsonSerializerSettings createSettings(bool AllowExtendedTypes, bool HtmlEscape, HashSet <Type> AllowedTypes) { #if UNIVERSAL DebugEx.Assert(AllowedTypes == null, "AllowedTypes are not supported yet"); #endif return(new JsonSerializerSettings() { TypeNameHandling = AllowExtendedTypes ? TypeNameHandling.Auto : Newtonsoft.Json.TypeNameHandling.None, #if NETFX TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple, #endif StringEscapeHandling = HtmlEscape ? StringEscapeHandling.EscapeHtml : StringEscapeHandling.Default, Formatting = Formatting.None, MissingMemberHandling = MissingMemberHandling.Ignore, FloatParseHandling = FloatParseHandling.Double, FloatFormatHandling = FloatFormatHandling.String, Culture = System.Globalization.CultureInfo.InvariantCulture, MaxDepth = MaxDepth, AllowedTypes = AllowedTypes, }); }
//------------------------------------------------------------------------------------------------------------------------ public bool OnMessageReceived(T wrapper_msg, object payload) { //check if this is a response, in which case unblock pending request if (wrapper_msg.IsResponse) { int syncId = wrapper_msg.SyncId; DebugEx.Assert(syncId != 0, "IsResponse flag without valid syncId not allowed"); if (syncId == 0) { return(false); } DebugEx.TraceLog("MsgSync: got " + payload.GetType() + ", syncid: " + wrapper_msg.SyncId); //find waiter RpcWaiter w = null; lock (RpcPending) if (RpcPending.TryGetValue(syncId, out w)) { RpcPending.Remove(syncId); } //remove if found //set result and wake if (w != null) { lock (w) { w.Response = payload; Monitor.Pulse(w); return(true); } } else { DebugEx.TraceError("Could not find MsgSync waiter from " + payload.GetType() + " with syncId=" + syncId); } } return(false); }
//------------------------------------------------------------------------------------------------------------------------ public static bool Convert(object value, Type ToType, out object result) { result = null; //try convert try { //get value type var fromType = value == null ? typeof(object) : value.GetType(); //nothing to do? if (fromType == ToType) { result = value; return(true); } //are both single values? if ((!fromType.IsArray && !ToType.IsArray) || (value == null)) { if (SingleValueConvert(value, ToType, out result)) { return(true); } else if (value is string && value != null && (value as string).Contains(ArraySeparator)) { //we may be able to convert this string if we split it by the separator and pick the first element var elems = (value as string).Split(ArraySeparator); return(SingleValueConvert(elems[0], ToType, out result)); } else { return(false); } } //get parameters var src_arr = (value as Array); var src_length = src_arr == null ? 0 : src_arr.Length; var ToTypeElement = ToType.IsArray ? ToType.GetElementType() : ToType; //zero length array? if (fromType.IsArray && src_length == 0) { //create a zero-length result array result = Array.CreateInstance(ToTypeElement, 0); return(true); } //is source only an array? if (fromType.IsArray && !ToType.IsArray) { //if target is string then we can join them up into a nice string, else just pick the first value if (ToType == typeof(string)) { //build result string by joining up elements string res = ""; for (int n = 0; n < src_length; n++) { object v; if (SingleValueConvert(src_arr.GetValue(n), ToTypeElement, out v) == false) { return(false); } res += v.ToStringInvariant() + ArraySeparator; } result = res; return(true); } else { return(SingleValueConvert(src_arr.GetValue(0), ToType, out result)); } } //is only destination an array? else if (!fromType.IsArray && ToType.IsArray) { //if source is string try to split it into elements if (fromType == typeof(string)) { //split using separator var elems = (value as string).Split(ArraySeparator); //create result array var dst_arr = Array.CreateInstance(ToTypeElement, elems.Length); for (int n = 0; n < elems.Length; n++) { object v; if (SingleValueConvert(elems[n], ToTypeElement, out v) == false) { return(false); } dst_arr.SetValue(v, n); } result = dst_arr; return(true); } else { //create a zero-length result array var dst_arr = Array.CreateInstance(ToTypeElement, 1); object v; if (SingleValueConvert(value, ToTypeElement, out v) == false) { return(false); } dst_arr.SetValue(v, 0); result = dst_arr; return(true); } } //are both arrays? else if (fromType.IsArray && ToType.IsArray) { //create result array var dst_arr = Array.CreateInstance(ToTypeElement, src_length); //fill with a per-element convert for (int n = 0; n < src_length; n++) { object v; if (SingleValueConvert(src_arr.GetValue(n), ToTypeElement, out v) == false) { return(false); } dst_arr.SetValue(v, n); } result = dst_arr; return(true); } else { DebugEx.Assert("Should not be here (Convert from=" + fromType + ", to=" + ToType + ")"); return(false); } } catch { result = null; return(false); } //pokemon exception handler }
//------------------------------------------------------------------------------------------------------------------------ #endregion #region Constructors //------------------------------------------------------------------------------------------------------------------------ public RequestQueueConsumer(RequestHandlerDelegate RequestHandler) { this.RequestHandler = RequestHandler; DebugEx.Assert(RequestHandler != null, "RequestHandler cannot be null"); }
//------------------------------------------------------------------------------------------------------------------------ void HeartBeatEntryPoint() { //spin while (_IsAlive) { T req; //pulse any waiting floodlocker lock (floodLocker) Monitor.Pulse(floodLocker); //check pending requests.. if none the sleep the good sleep lock (RequestQueue) { //wait for pulse in nothign in queue if (RequestQueue.Count == 0 || _IsPaused) { Monitor.Wait(RequestQueue); } //double check (in case we woken up without items in queue) if (RequestQueue.Count == 0 || _IsPaused) { continue; } //dequeue req = RequestQueue.Peek(); //sleepy time if (SpinSleepPeriod > 0) { Thread.Sleep(SpinSleepPeriod); } } //handle it try { _RetryLastItem = false; //execute callback RequestHandler(req); //execute callback if (!_RetryLastItem) { //consume it lock (RequestQueue) if (RequestQueue.Count > 0 && (req == null || req.Equals(RequestQueue.Peek()))) { RequestQueue.Dequeue(); } } } catch (Exception ex) { DebugEx.Assert(ex, "Unhandled exception caught. Thrown by RequestHandler()"); //consume it (eg. drop request) lock (RequestQueue) if (RequestQueue.Count > 0) { RequestQueue.Dequeue(); } } } }
//------------------------------------------------------------------------------------------------------------------------ public virtual Trsp SendRequest <Trsp>(T wrapper_msg, object request, TimeSpan?timeout = null, bool auto_json = false) { //null check if (wrapper_msg == null) { DebugEx.Assert("Null wrapper detected"); return(default(Trsp)); } try { //create synchronization id var syncId = GetNewSyncId(); //create waiter var w = new RpcWaiter(); lock (RpcPending) RpcPending.Add(syncId, w); //create wrapper message try { wrapper_msg.IsRequest = true; wrapper_msg.SyncId = syncId; wrapper_msg.Payload = request?.ToJSON(); } catch (Exception ex) { DebugEx.Assert(ex, "msg wrapper create failed"); return(default(Trsp)); } //Send request and wait for response bool failed = false; lock (w) { DebugEx.TraceLog("MsgSync: sending " + request?.GetType() + ", syncid: " + wrapper_msg.SyncId); PublishFunc?.Invoke(wrapper_msg, request); //wait for response #if DEBUG Monitor.Wait(w); #else if (timeout.HasValue) { if (timeout.Value == TimeSpan.Zero) { Monitor.Wait(w); //if explicitly zero timespan, wait forever } else { Monitor.Wait(w, timeout.Value); } } else { //if no value given, wait for default msec Monitor.Wait(w, DefaultRPCTimeout); } #endif if (w.Response == null) { failed = true; } } if (failed) { lock (RpcPending) RpcPending.Remove(syncId); //remove if failed to receive within time limit } //give response back if (w.Response != null) { if (w.Response is string && auto_json) { var rsp_str = w.Response as string; if ((rsp_str.StartsWith("{") && rsp_str.EndsWith("}")) || (rsp_str.StartsWith("[") && rsp_str.EndsWith("]"))) { return((Trsp)rsp_str.FromJSON(type: typeof(Trsp))); } } else { return((Trsp)w.Response); } } return(default(Trsp)); } catch (Exception ex) { DebugEx.TraceErrorException(ex); return(default(Trsp)); } }
//------------------------------------------------------------------------------------------------------------------------ public static Type GetType(string name, bool DeFriendlify = true) { //sanity check if (string.IsNullOrWhiteSpace(name)) { return(null); } //find type Type result = null; lock (cache) if (cache.TryGetValue(name, out result) == false) { try { //resolve type result = Type.GetType(name); //If null go for fallback mechanisms if (result == null) { //This is now in fallback. do not keep lock since what follows are expensive operations Monitor.Exit(cache); try { //if not found and not fully qualified search in all assemblies if (result == null) { string strippedName; //process name (strip assembly and recersivly extract generic types) if (name.Contains('[')) { var lefovers = name.RightOf("["); var generics = new List <string>(); int i = 0; int start = 0; for (int n = 0; n < lefovers.Length; n++) { var c = lefovers[n]; if (c == '[') { if (i == 0) { start = n + 1; } i++; } else if (c == ']') { i--; if (i == 0) { generics.Add(lefovers.Substring(start, n - start)); start = n + 1; } } } //get types for each generic var genericsTypes = new List <Type>(); foreach (var entry in generics) { var gt = GetType(entry); if (gt == null) { return(null); } genericsTypes.Add(gt); } //process found generics recursively strippedName = name.LeftOf("`") + "`" + generics.Count + "[" + string.Join(", ", genericsTypes.Select(t => "[" + t.AssemblyQualifiedName + "]")) + "]"; //try a fast re-check of processed name result = Type.GetType(strippedName); } else { strippedName = name.LeftOf(","); } //search assemblies if (result == null) { foreach (var entry in GetAssemblies()) { result = entry.GetType(strippedName); if (result != null) { break; } } } } //Try to find friendly named types if (result == null && DeFriendlify) { try { result = Type.GetType(Extensions.DeFriendlifyName(name)); } catch (Exception ex) { DebugEx.Assert(ex, "DeFriendlifyName failed"); } } } catch (Exception ex) { DebugEx.Assert(ex, "Caught unhandled exception during type resolve"); } finally { Monitor.Enter(cache); } //re-aquire lock before continuing } } catch (Exception ex) { DebugEx.Assert(ex, "Unhandled excpetion while trying to resolve type"); } //cache it cache.ForceAdd(name, result); } //done and done return(result); }