public static ICarrier CreateCarrier(ReceptorsContainer rsys, string protocol, Action<dynamic> initializeSignal) { ISemanticTypeStruct outprotocol = rsys.SemanticTypeSystem.GetSemanticTypeStruct(protocol); dynamic outsignal = rsys.SemanticTypeSystem.Create(protocol); initializeSignal(outsignal); ICarrier carrier = new Carrier(outprotocol, "", outsignal, null); return carrier; }
/// <summary> /// Return an action representing what to do for a new carrier/protocol. /// </summary> protected Action GetProcessAction(IReceptorInstance from, Carrier carrier, bool stopRecursion, bool isRoot) { // Construct an action... Action action = new Action(() => { // Get the receptors receiving the protocol. List<IReceptorConnection> receptors = GetTargetReceptorsFor(ReceptorFromInstance(from), carrier, isRoot); // For each receptor that is enabled... receptors.ForEach(receptor => { // The action is "ProcessCarrier". // TODO: *** Pass in the carrier, not the carrier's fields!!! *** // ************* A: MOVED HERE ************ NewCarrier.Fire(this, new NewCarrierEventArgs(from, carrier)); Action process = new Action(() => receptor.Receptor.Instance.ProcessCarrier(carrier)); // TODO: This flag is tied in with the visualizer, we should extricate this flag and logic. if (receptor.Receptor.Instance.IsHidden) { // Don't visualize carriers to hidden receptors. process(); } else if (!stopRecursion) { // TODO: This should be handled externally somehow. // Defer the action, such that the visualizer can invoke it when it determines the carrier rendering to the receiving receptor has completed. ISemanticTypeStruct protocol = SemanticTypeSystem.GetSemanticTypeStruct("CarrierAnimation"); dynamic signal = SemanticTypeSystem.Create("CarrierAnimation"); signal.Process = process; signal.From = from; signal.To = receptor.Receptor.Instance; signal.Carrier = carrier; // Simulate coming from the system, as it IS a system message. // Also note that the "stop recursion" flag is set to true on a receptor defining "receives everything" ("*"). CreateCarrier(from, protocol, protocol.DeclTypeName, signal, receptor.Receptor.Instance.GetEnabledReceiveProtocols().Select(rp=>rp.Protocol).Contains("*"), true); } }); }); return action; }
/// <summary> /// Given a carrier, if there are receptors for the carrier's protocol, act upon the carrier immediately. /// If there are no receptors for the protocol, queue the carrier. /// </summary> protected void ProcessReceptors(IReceptorInstance from, Carrier carrier, bool stopRecursion, bool isRoot) { // Get the action that we are supposed to perform on the carrier. Action action = GetProcessAction(from, carrier, stopRecursion, isRoot); IReceptor receptor = ReceptorFromInstance(from); // Some bullet proofing that was revealed in unit testing. if (receptor != null) { List<IReceptorConnection> receptors = GetTargetReceptorsFor(ReceptorFromInstance(from), carrier, isRoot); // If we have any enabled receptor for this carrier (a mapping of carrier to receptor list exists and receptors actually exist in that map)... if (receptors.Count > 0) { // ...perform the action. action(); } else { // ...othwerise, queue up the carrier for when there is a receptor for it. queuedCarriers.Add(new QueuedCarrierAction() { From = ReceptorFromInstance(from), Carrier = carrier, Action = action }); } } else { // The "from" receptor is null, which is an invalid condition occurring during unit testing. // Regardless, queue the carrier. queuedCarriers.Add(new QueuedCarrierAction() { From = null, Carrier = carrier, Action = action }); } }
/// <summary> /// Internal carrier creation. This includes the "stopRecursion" flag to prevent wildcard receptors from receiving ad-infinitum their own emissions. /// </summary> protected ICarrier CreateCarrier(IReceptorInstance from, ISemanticTypeStruct protocol, string protocolPath, dynamic signal, bool stopRecursion, bool isSystemMessage = false, ICarrier parentCarrier = null, bool emitSubElements = true, bool isRoot = true) { Carrier carrier = null; if (from.GetEnabledEmittedProtocols().Any(p => p.Protocol == protocol.DeclTypeName) || isSystemMessage) { carrier = new Carrier(protocol, protocolPath, signal, parentCarrier); // ************ MOVED TO A: ************** // The reason this was moved is so that we fire NewCarrier only for actual receptors with protocols enabled for that receptor. // TODO: However, this means that we no longer queue protocols for which we have no receptors. Not sure if we actually want this particular feature. // NewCarrier.Fire(this, new NewCarrierEventArgs(from, carrier)); // We pass along the stopRecursion flag to prevent wild-card carrier receptor from receiving their own emissions, which would result in a new carrier, // ad-infinitum. ProcessReceptors(from, carrier, stopRecursion, isRoot); } // Recurse into SE's of the protocol and emit carriers for those as well, if a receiver exists. if (!isSystemMessage && emitSubElements) { // The carrier might be null if there's no receiver for the parent carrier. In this case, we need to create a dummy carrier so we have a parent. if (carrier == null) { carrier = new Carrier(protocol, protocolPath, signal, parentCarrier); } CreateCarriersForSemanticElements(from, protocol, protocol.DeclTypeName, signal, stopRecursion, carrier); } return carrier; }
protected void CreateCarrierIfReceiver(IReceptorInstance from, ISemanticTypeStruct protocol, string protocolPath, dynamic signal, ICarrier parentCarrier, bool emitSubElements = true) { if (from.GetEnabledEmittedProtocols().Any(p => p.Protocol == protocol.DeclTypeName)) { if (TargetReceptorExistsFor(ReceptorFromInstance(from), protocol, protocol.DeclTypeName == protocolPath)) { // This call will recurse for us. // CreateCarrier(IReceptorInstance from, ISemanticTypeStruct protocol, string protocolPath, dynamic signal, bool stopRecursion, bool isSystemMessage = false, ICarrier parentCarrier = null) CreateCarrier(from, protocol, protocolPath, signal, false, false, parentCarrier, emitSubElements, protocol.DeclTypeName == protocolPath); } else { if (emitSubElements) { // Recurse into SE's of the protocol and emit carriers for those as well, if a receiver exists. // We do this even if there isn't a target for the top-level receptor. // However, we do create a Carrier instance as the parent so the child can reference it if necessary. Carrier carrier = new Carrier(protocol, protocolPath, signal, parentCarrier); CreateCarriersForSemanticElements(from, protocol, protocolPath, signal, false, carrier); } } } else { if (emitSubElements) { // Create a Carrier instance as the parent so the child can reference it if necessary. Carrier carrier = new Carrier(protocol, protocolPath, signal, parentCarrier); CreateCarriersForSemanticElements(from, protocol, protocolPath, signal, false, carrier); } } }