private byte[] SerializeSelection(ActorSelectionMessage sel) { SelectionEnvelope.Builder builder = SelectionEnvelope.CreateBuilder(); var message = sel.Message; Serializer serializer = system.Serialization.FindSerializerFor(message); builder .SetEnclosedMessage(ByteString.CopyFrom(serializer.ToBinary(message))) .SetSerializerId(serializer.Identifier); var serializer2 = serializer as SerializerWithStringManifest; if (serializer2 != null) { var manifest = serializer2.Manifest(message); if (!string.IsNullOrEmpty(manifest)) { builder.SetMessageManifest(ByteString.CopyFromUtf8(manifest)); } } else { if (serializer.IncludeManifest) builder.SetMessageManifest(ByteString.CopyFromUtf8(message.GetType().AssemblyQualifiedName)); } foreach (SelectionPathElement element in sel.Elements) { element.Match() .With<SelectChildName>(m => builder.AddPattern(BuildPattern(m.Name, PatternType.CHILD_NAME))) .With<SelectChildPattern>( m => builder.AddPattern(BuildPattern(m.PatternStr, PatternType.CHILD_PATTERN))) .With<SelectParent>(m => builder.AddPattern(BuildPattern(null, PatternType.PARENT))); } return builder.Build().ToByteArray(); }
/// <summary> /// INTERNAL API /// Convenience method used by remoting when receiving <see cref="ActorSelectionMessage" /> from a remote /// actor. /// </summary> /// <param name="anchor">TBD</param> /// <param name="sender">TBD</param> /// <param name="sel">TBD</param> internal static void DeliverSelection(IInternalActorRef anchor, IActorRef sender, ActorSelectionMessage sel) { if (sel.Elements.IsNullOrEmpty()) { anchor.Tell(sel.Message, sender); } else { var iter = sel.Elements.Iterator(); Action <IInternalActorRef> rec = null; rec = @ref => @ref.Match() .With <ActorRefWithCell>(refWithCell => { var emptyRef = new EmptyLocalActorRef(refWithCell.Provider, anchor.Path / sel.Elements.Select(el => el.ToString()), refWithCell.Underlying.System.EventStream); iter.Next() .Match() .With <SelectParent>(_ => { var parent = @ref.Parent; if (iter.IsEmpty()) { parent.Tell(sel.Message, sender); } else { rec(parent); } }) .With <SelectChildName>(name => { var child = refWithCell.GetSingleChild(name.Name); if (child is Nobody) { // don't send to emptyRef after wildcard fan-out if (!sel.WildCardFanOut) { emptyRef.Tell(sel, sender); } } else if (iter.IsEmpty()) { child.Tell(sel.Message, sender); } else { rec(child); } }) .With <SelectChildPattern>(p => { // fan-out when there is a wildcard var children = refWithCell.Children; var matchingChildren = children .Where(c => c.Path.Name.Like(p.PatternStr)) .ToList(); if (iter.IsEmpty()) { if (matchingChildren.Count == 0 && !sel.WildCardFanOut) { emptyRef.Tell(sel, sender); } else { matchingChildren.ForEach(child => child.Tell(sel.Message, sender)); } } else { // don't send to emptyRef after wildcard fan-out if (matchingChildren.Count == 0 && !sel.WildCardFanOut) { emptyRef.Tell(sel, sender); } else { var m = new ActorSelectionMessage(sel.Message, iter.ToVector().ToArray(), sel.WildCardFanOut || matchingChildren.Count > 1); matchingChildren.ForEach(child => DeliverSelection(child as IInternalActorRef, sender, m)); } } }); }) // foreign ref, continue by sending ActorSelectionMessage to it with remaining elements .Default(_ => @ref.Tell(new ActorSelectionMessage(sel.Message, iter.ToVector().ToArray()), sender)); rec(anchor); } }
/// <summary> /// Receives the selection. /// </summary> /// <param name="m">The m.</param> private void ReceiveSelection(ActorSelectionMessage m) { var selection = new ActorSelection(Self, m.Elements.ToArray()); selection.Tell(m.Message, Sender); }
/// <summary> /// INTERNAL API /// /// Convenience method used by remoting when receiving <see cref="ActorSelectionMessage"/> from a remote /// actor. /// </summary> internal static void DeliverSelection(InternalActorRef anchor, ActorRef sender, ActorSelectionMessage sel) { var actorSelection = new ActorSelection(anchor, sel.Elements); actorSelection.Tell(sel.Message, sender); }
/// <summary> /// INTERNAL API /// Convenience method used by remoting when receiving <see cref="ActorSelectionMessage" /> from a remote /// actor. /// </summary> /// <param name="anchor">TBD</param> /// <param name="sender">TBD</param> /// <param name="sel">TBD</param> internal static void DeliverSelection(IInternalActorRef anchor, IActorRef sender, ActorSelectionMessage sel) { if (sel.Elements.IsNullOrEmpty()) { anchor.Tell(sel.Message, sender); } else { var iter = sel.Elements.Iterator(); void Rec(IInternalActorRef actorRef) { if (actorRef is ActorRefWithCell refWithCell) { var emptyRef = new EmptyLocalActorRef( provider: refWithCell.Provider, path: anchor.Path / sel.Elements.Select(el => el.ToString()), eventStream: refWithCell.Underlying.System.EventStream); switch (iter.Next()) { case SelectParent _: var parent = actorRef.Parent; if (iter.IsEmpty()) { parent.Tell(sel.Message, sender); } else { Rec(parent); } break; case SelectChildName name: var child = refWithCell.GetSingleChild(name.Name); if (child is Nobody) { // don't send to emptyRef after wildcard fan-out if (!sel.WildCardFanOut) { emptyRef.Tell(sel, sender); } } else if (iter.IsEmpty()) { child.Tell(sel.Message, sender); } else { Rec(child); } break; case SelectChildPattern pattern: // fan-out when there is a wildcard var matchingChildren = refWithCell.Children .Where(c => c.Path.Name.Like(pattern.PatternStr)) .ToList(); if (iter.IsEmpty()) { if (matchingChildren.Count == 0 && !sel.WildCardFanOut) { emptyRef.Tell(sel, sender); } else { for (var i = 0; i < matchingChildren.Count; i++) { matchingChildren[i].Tell(sel.Message, sender); } } } else { // don't send to emptyRef after wildcard fan-out if (matchingChildren.Count == 0 && !sel.WildCardFanOut) { emptyRef.Tell(sel, sender); } else { var message = new ActorSelectionMessage( message: sel.Message, elements: iter.ToVector().ToArray(), wildCardFanOut: sel.WildCardFanOut || matchingChildren.Count > 1); for (var i = 0; i < matchingChildren.Count; i++) { DeliverSelection(matchingChildren[i] as IInternalActorRef, sender, message); } } } break; } } else { // foreign ref, continue by sending ActorSelectionMessage to it with remaining elements actorRef.Tell(new ActorSelectionMessage(sel.Message, iter.ToVector().ToArray()), sender); } } Rec(anchor); } }
/// <summary> /// INTERNAL API /// Convenience method used by remoting when receiving <see cref="ActorSelectionMessage" /> from a remote /// actor. /// </summary> internal static void DeliverSelection(IInternalActorRef anchor, IActorRef sender, ActorSelectionMessage sel) { if (sel.Elements.IsNullOrEmpty()) { anchor.Tell(sel.Message, sender); } else { var iter = sel.Elements.Iterator(); Action<IInternalActorRef> rec = null; rec = @ref => @ref.Match() .With<ActorRefWithCell>(refWithCell => { var emptyRef = new EmptyLocalActorRef(refWithCell.Provider, anchor.Path/sel.Elements.Select(el => el.ToString()), refWithCell.Underlying.System.EventStream); iter.Next() .Match() .With<SelectParent>(_ => { var parent = @ref.Parent; if (iter.IsEmpty()) parent.Tell(sel.Message, sender); else rec(parent); }) .With<SelectChildName>(name => { var child = refWithCell.GetSingleChild(name.Name); if (child is Nobody) { if (!sel.WildCardFanOut) emptyRef.Tell(sel, sender); } else if (iter.IsEmpty()) { child.Tell(sel.Message, sender); } else { rec(child); } }) .With<SelectChildPattern>(p => { var children = refWithCell.Children; var matchingChildren = children .Where(c => c.Path.Name.Like(p.PatternStr)) .ToList(); if (iter.IsEmpty()) { if(matchingChildren.Count ==0 && !sel.WildCardFanOut) emptyRef.Tell(sel, sender); else matchingChildren.ForEach(child => child.Tell(sel.Message, sender)); } else { if (matchingChildren.Count == 0 && !sel.WildCardFanOut) emptyRef.Tell(sel, sender); else { var m = new ActorSelectionMessage(sel.Message, iter.ToVector().ToArray(), sel.WildCardFanOut || matchingChildren.Count > 1); matchingChildren.ForEach(child => DeliverSelection(child as IInternalActorRef, sender, m)); } } }); }) .Default(_ => @ref.Tell(new ActorSelectionMessage(sel.Message, iter.ToVector().ToArray()), sender)); rec(anchor); } }