public static void InvokeTransformChange(string tree, TransformSpec ts) => OnTransformChange?.Invoke(tree, ts);
public static void InvokeMarkerTransform(string marker, TransformSpec ts) => OnMarkerTransform?.Invoke(marker, ts);
public List <KeyValuePair <string, string> > Morph(object args) { // Transform the args into a bag of key-value strings. var outputArgs = new List <KeyValuePair <string, string> >(); if (args != null) { if (!_noImplicitTransforms) { // given the type, fetch the implicit transforms for that type and put it in the implicitTransforms variable. Type argType = args.GetType(); TransformSpec implicitTransforms; // First check the one-element cache _firstImplicitTransformsEntry ImplicitTransformEntry cacheEntry = _firstImplicitTransformsEntry; if (cacheEntry != null && cacheEntry.Type == argType) { implicitTransforms = cacheEntry.Transforms; // Yeah we hit the cache. } else if (cacheEntry == null) { // _firstImplicitTransformsEntry is empty, we should fill it. // Note that it is OK that two threads may race and both call MakeImplicitTransforms on their own // (that is we don't expect exactly once initialization of _firstImplicitTransformsEntry) implicitTransforms = MakeImplicitTransforms(argType); Interlocked.CompareExchange(ref _firstImplicitTransformsEntry, new ImplicitTransformEntry() { Type = argType, Transforms = implicitTransforms }, null); } else { // This should only happen when you are wildcarding your events (reasonably rare). // In that case you will probably need many types // Note currently we don't limit the cache size, but it is limited by the number of // distinct types of objects passed to DiagnosticSource.Write. if (_implicitTransformsTable == null) { Interlocked.CompareExchange(ref _implicitTransformsTable, new ConcurrentDictionary <Type, TransformSpec>(1, 8), null); } implicitTransforms = _implicitTransformsTable.GetOrAdd(argType, type => MakeImplicitTransforms(type)); } // implicitTransformas now fetched from cache or constructed, use it to Fetch all the implicit fields. if (implicitTransforms != null) { for (TransformSpec serializableArg = implicitTransforms; serializableArg != null; serializableArg = serializableArg.Next) { outputArgs.Add(serializableArg.Morph(args)); } } } if (_explicitTransforms != null) { for (var explicitTransform = _explicitTransforms; explicitTransform != null; explicitTransform = explicitTransform.Next) { var keyValue = explicitTransform.Morph(args); if (keyValue.Value != null) { outputArgs.Add(keyValue); } } } } return(outputArgs); }
/// <summary> /// Creates one FilterAndTransform specification from filterAndPayloadSpec starting at 'startIdx' and ending just before 'endIdx'. /// This FilterAndTransform will subscribe to DiagnosticSources specified by the specification and forward them to 'eventSource. /// For convenience, the 'Next' field is set to the 'next' parameter, so you can easily form linked lists. /// </summary> public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx, DiagnosticSourceEventSource eventSource, FilterAndTransform next) { Debug.Assert(filterAndPayloadSpec != null && startIdx >= 0 && startIdx <= endIdx && endIdx <= filterAndPayloadSpec.Length); Next = next; _eventSource = eventSource; string listenerNameFilter = null; // Means WildCard. string eventNameFilter = null; // Means WildCard. string activityName = null; var startTransformIdx = startIdx; var endEventNameIdx = endIdx; var colonIdx = filterAndPayloadSpec.IndexOf(':', startIdx, endIdx - startIdx); if (0 <= colonIdx) { endEventNameIdx = colonIdx; startTransformIdx = colonIdx + 1; } // Parse the Source/Event name into listenerNameFilter and eventNameFilter var slashIdx = filterAndPayloadSpec.IndexOf('/', startIdx, endEventNameIdx - startIdx); if (0 <= slashIdx) { listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, slashIdx - startIdx); var atIdx = filterAndPayloadSpec.IndexOf('@', slashIdx + 1, endEventNameIdx - slashIdx - 1); if (0 <= atIdx) { activityName = filterAndPayloadSpec.Substring(atIdx + 1, endEventNameIdx - atIdx - 1); eventNameFilter = filterAndPayloadSpec.Substring(slashIdx + 1, atIdx - slashIdx - 1); } else { eventNameFilter = filterAndPayloadSpec.Substring(slashIdx + 1, endEventNameIdx - slashIdx - 1); } } else if (startIdx < endEventNameIdx) { listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, endEventNameIdx - startIdx); } _eventSource.Message("DiagnosticSource: Enabling '" + (listenerNameFilter ?? "*") + "/" + (eventNameFilter ?? "*") + "'"); // If the transform spec begins with a - it means you don't want implicit transforms. if (startTransformIdx < endIdx && filterAndPayloadSpec[startTransformIdx] == '-') { _eventSource.Message("DiagnosticSource: suppressing implicit transforms."); _noImplicitTransforms = true; startTransformIdx++; } // Parse all the explicit transforms, if present if (startTransformIdx < endIdx) { for (;;) { int specStartIdx = startTransformIdx; int semiColonIdx = filterAndPayloadSpec.LastIndexOf(';', endIdx - 1, endIdx - startTransformIdx); if (0 <= semiColonIdx) { specStartIdx = semiColonIdx + 1; } // Ignore empty specifications. if (specStartIdx < endIdx) { if (_eventSource.IsEnabled(EventLevel.Informational, Keywords.Messages)) { _eventSource.Message("DiagnosticSource: Parsing Explicit Transform '" + filterAndPayloadSpec.Substring(specStartIdx, endIdx - specStartIdx) + "'"); } _explicitTransforms = new TransformSpec(filterAndPayloadSpec, specStartIdx, endIdx, _explicitTransforms); } if (startTransformIdx == specStartIdx) { break; } endIdx = semiColonIdx; } } Action <string, string, IEnumerable <KeyValuePair <string, string> > > writeEvent = null; if (activityName != null && activityName.Contains("Activity")) { MethodInfo writeEventMethodInfo = typeof(DiagnosticSourceEventSource).GetTypeInfo().GetDeclaredMethod(activityName); if (writeEventMethodInfo != null) { // This looks up the activityName (which needs to be a name of an event on DiagnosticSourceEventSource // like Activity1Start and returns that method). This allows us to have a number of them and this code // just works. try { writeEvent = (Action <string, string, IEnumerable <KeyValuePair <string, string> > >) writeEventMethodInfo.CreateDelegate(typeof(Action <string, string, IEnumerable <KeyValuePair <string, string> > >), _eventSource); } catch (Exception) { } } if (writeEvent == null) { _eventSource.Message("DiagnosticSource: Could not find Event to log Activity " + activityName); } } if (writeEvent == null) { #if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT writeEvent = _eventSource.Event; #else writeEvent = delegate(string sourceName, string eventName, IEnumerable <KeyValuePair <string, string> > arguments) { _eventSource.EventJson(sourceName, eventName, ToJson(arguments)); }; #endif } // Set up a subscription that watches for the given Diagnostic Sources and events which will call back // to the EventSource. _diagnosticsListenersSubscription = DiagnosticListener.AllListeners.Subscribe(new CallbackObserver <DiagnosticListener>(delegate(DiagnosticListener newListener) { if (listenerNameFilter == null || listenerNameFilter == newListener.Name) { _eventSource.NewDiagnosticListener(newListener.Name); Predicate <string> eventNameFilterPredicate = null; if (eventNameFilter != null) { eventNameFilterPredicate = (string eventName) => eventNameFilter == eventName; } var subscription = newListener.Subscribe(new CallbackObserver <KeyValuePair <string, object> >(delegate(KeyValuePair <string, object> evnt) { // The filter given to the DiagnosticSource may not work if users don't is 'IsEnabled' as expected. // Thus we look for any events that may have snuck through and filter them out before forwarding. if (eventNameFilter != null && eventNameFilter != evnt.Key) { return; } var outputArgs = this.Morph(evnt.Value); var eventName = evnt.Key; writeEvent(newListener.Name, eventName, outputArgs); }), eventNameFilterPredicate); _liveSubscriptions = new Subscriptions(subscription, _liveSubscriptions); } })); }
/// <summary> /// Creates one FilterAndTransform specification from filterAndPayloadSpec starting at 'startIdx' and ending just before 'endIdx'. /// This FilterAndTransform will subscribe to DiagnosticSources specified by the specification and forward them to 'eventSource. /// For convenience, the 'Next' field is set to the 'next' parameter, so you can easily form linked lists. /// </summary> public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx, DiagnosticSourceEventSource eventSource, FilterAndTransform next) { #if DEBUG string spec = filterAndPayloadSpec.Substring(startIdx, endIdx - startIdx); #endif Next = next; _eventSource = eventSource; string listenerNameFilter = null; // Means WildCard. string eventNameFilter = null; // Means WildCard. var startTransformIdx = startIdx; var endEventNameIdx = endIdx; var colonIdx = filterAndPayloadSpec.IndexOf(':', startIdx, endIdx - startIdx); if (0 <= colonIdx) { endEventNameIdx = colonIdx; startTransformIdx = colonIdx + 1; } // Parse the Source/Event name into listenerNameFilter and eventNameFilter var slashIdx = filterAndPayloadSpec.IndexOf('/', startIdx, endEventNameIdx - startIdx); if (0 <= slashIdx) { listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, slashIdx - startIdx); eventNameFilter = filterAndPayloadSpec.Substring(slashIdx + 1, endEventNameIdx - slashIdx - 1); } else if (startIdx < endEventNameIdx) { listenerNameFilter = filterAndPayloadSpec.Substring(startIdx, endEventNameIdx - startIdx); } _eventSource.Message("DiagnosticSource: Enabling '" + (listenerNameFilter ?? "*") + "/" + (eventNameFilter ?? "*") + "'"); // If the transform spec begins with a - it means you don't want implicit transforms. if (startTransformIdx < endIdx && filterAndPayloadSpec[startTransformIdx] == '-') { _eventSource.Message("DiagnosticSource: suppressing implicit transforms."); _noImplicitTransforms = true; startTransformIdx++; } // Parse all the explicit transforms, if present if (startTransformIdx < endIdx) { for (;;) { int specStartIdx = startTransformIdx; int semiColonIdx = filterAndPayloadSpec.LastIndexOf(';', endIdx - 1, endIdx - startTransformIdx); if (0 <= semiColonIdx) { specStartIdx = semiColonIdx + 1; } // Ignore empty specifications. if (specStartIdx < endIdx) { if (_eventSource.IsEnabled(EventLevel.Informational, Keywords.Messages)) { _eventSource.Message("DiagnosticSource: Parsing Explicit Transform '" + filterAndPayloadSpec.Substring(specStartIdx, endIdx - specStartIdx) + "'"); } _explicitTransforms = new TransformSpec(filterAndPayloadSpec, specStartIdx, endIdx, _explicitTransforms); } if (startTransformIdx == specStartIdx) { break; } endIdx = semiColonIdx; } } // Set up a subscription that watches for the given Diagnostic Sources and events which will call back // to the EventSource. _diagnosticsListenersSubscription = DiagnosticListener.AllListeners.Subscribe(new CallbackObserver <DiagnosticListener>(delegate(DiagnosticListener newListener) { if (listenerNameFilter == null || listenerNameFilter == newListener.Name) { Predicate <string> eventNameFilterPredicate = null; if (eventNameFilter != null) { eventNameFilterPredicate = (string eventName) => eventNameFilter == eventName; } var subscription = newListener.Subscribe(new CallbackObserver <KeyValuePair <string, object> >(delegate(KeyValuePair <string, object> evnt) { // The filter given to the DiagnosticSource may not work if users don't is 'IsEnabled' as expected. // Thus we look for any events that may have snuck through and filter them out before forwarding. if (eventNameFilter != null && eventNameFilter != evnt.Key) { return; } var outputArgs = this.Morph(evnt.Value); #if !NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT _eventSource.Event(newListener.Name, evnt.Key, outputArgs); #else _eventSource.EventJson(newListener.Name, evnt.Key, ToJson(outputArgs)); #endif }), eventNameFilterPredicate); _liveSubscriptions = new Subscriptions(subscription, _liveSubscriptions); } })); }
void Update() { bool doTryConnect = true; doTryConnect = doTryConnect && !connected && UriString != ""; if (cws != null) { doTryConnect = doTryConnect && (cws.State == WebSocketState.Closed || cws.State == WebSocketState.Aborted); } if (doTryConnect) { connected = true; cws = null; TryConnect(); } CKARNetworkState state; while (stateQueue.Dequeue(out state)) { EventManager.InvokeNetworkStateChange(state); } string msgString; while (queue.Dequeue(out msgString)) { Debug.Log(msgString); if (msgString.Contains("\"type\": \"transform\"")) { WebsocketJsonTransform msg = JsonUtility.FromJson <WebsocketJsonTransform>(msgString); TransformSpec ts = new TransformSpec(msg.position, msg.scale, msg.rotation); if (msg.tree.Contains("marker")) { EventManager.InvokeMarkerTransform(msg.tree, ts); } else if (msg.tree.Contains("master")) { EventManager.InvokeMasterTransform(ts); } else { lsysController.DispatchTransform(msg.tree, ts); } } else if (msgString.Contains("\"type\": \"shape\"")) { WebsocketJsonShape msg = JsonUtility.FromJson <WebsocketJsonShape>(msgString); lsysController.DispatchShape(msg.tree, msg.shape); } else if (msgString.Contains("\"type\": \"value\"")) { WebsocketJsonValue msg = JsonUtility.FromJson <WebsocketJsonValue>(msgString); string[] keys = msg.key.Split(','); foreach (string key in keys) { ValueStore.Set(key, msg.payload); // will also invoke event } } else { WebsocketJsonMessage msg = JsonUtility.FromJson <WebsocketJsonMessage>(msgString); if (msg.type == "lsys") { lsysController.Dispatch(msg.payload); } if (msg.type == "console") { EventManager.InvokeConsole(msg.payload); } if (msg.type == "consoleStatus") { EventManager.InvokeConsoleStatus(msg.payload); } if (msg.type == "view") { EventManager.InvokeViewChange(msg.payload); } if (msg.type == "serverEvent") { if (msg.payload == "endMarkerConfig") { EventManager.InvokeServerEventEndMarkerConfig(); } } } } }
public void DispatchTransform(string key, TransformSpec ts) { GetLSystem(key).TransformSpec = ts; EventManager.InvokeTransformChange(key, ts); }