/// <summary> /// pickup a letter sent from remote postoffice /// </summary> /// <param name="letter"></param> /// <returns>replies emit by the mailboxes in this postoffice</returns> private EMLetter OnIncomingLetter(EMLetter letter) { ClientMailBox mailBox; var replies = new List <EMLetter>(1); var routeInfo = MailRouteInfo.Parse(letter.Recipient)[0]; foreach (var entityName in routeInfo.EntityNames) { rwlsDictName2MailBox.EnterReadLock(); if (dictName2MailBox.TryGetValue(entityName, out mailBox)) { // pass } else // report an error { PostOfficeEvent?.Invoke(this, new PostOfficeEventArgs(PostOfficeEventType.Error, $"unable to pickup letter: {this.User.Name}'s postoffice has registered a receiver named '{entityName}', but the corresponding instance if not found.")); } rwlsDictName2MailBox.ExitReadLock(); // dispatch letter to target mailbox var reply = mailBox?.Receive(letter); if (reply != null) { replies.Add(reply); } } return(replies.Count == 0 ? null : replies[0]); // one reply for 'Get' }
public List <MailRouteInfo> RouteRecipient(ILetter letter, IEnumerable <IServerUser> serverUsers) { var allRecipientInfos = new List <MailRouteInfo>(); var sInfo = MailRouteInfo.Parse(letter.Sender)[0]; foreach (var rInfo in MailRouteInfo.Parse(letter.Recipient)) { if (rInfo.UserName.ToLower() == "all") // to all, broadcast { foreach (var sUser in serverUsers) { if (sUser.Name != sInfo.UserName && // sender is not included sUser.IsOnline) // online user only { allRecipientInfos.Add(new MailRouteInfo(sUser.Name, rInfo.EntityNames)); } } } else { allRecipientInfos.Add(rInfo); } } return(allRecipientInfos); }
/// <summary> /// send a letter to the remote entity and wait for reply, the reply message will not be pass to the 'Pickup' method of 'receiver', /// <para>its content will be passed to the invoking position as return value</para> /// </summary> /// <param name="recipient">target entity route information, there should be only 1 entity in the recipient route info. e.g. entityA@Mary</param> /// <param name="title"></param> /// <param name="content"></param> /// <param name="timeout">unit: ms</param> /// <returns></returns> public ILetter Get(string recipient, string title, object content = null, int timeout = int.MaxValue) { if (MailRouteInfo.Parse(recipient).Count > 1) { throw new Exception("'Get' letter should not have multiple recipients."); } var letter = new EMLetter(recipient, MailAdress, title, content, StatusCode.Get, timeout); return(postoffice.Transfer(letter)); }
/// <summary> /// an interface which is used to send letter to the reomote postoffices /// </summary> /// <param name="letter"></param> internal EMLetter Transfer(EMLetter letter) { var routeInfos = MailRouteInfo.Parse(letter.Recipient); if (routeInfos == null) { throw new Exception($"cannot deliver letter '{letter.Title}', the '{nameof(letter.Recipient)}' of which is not in a valid format."); } var teleRouteInfos = new List <MailRouteInfo>(routeInfos.Count); MailRouteInfo localRouteInfo = null; foreach (var info in routeInfos) // find letters sent to local host { if (info.UserName == "localhost") { localRouteInfo = info; // only one } else { teleRouteInfos.Add(info); } } if (teleRouteInfos.Count != routeInfos.Count) // the route information has been changed { letter.Recipient = MailRouteInfo.ToLiteral(teleRouteInfos); // new tele-recipient info } letter.UpdateDDL(this.Now); // tele transmission if (letter.Recipient != "") { // send to tele-entity if (letter.HasFlag(Messages.StatusCode.Get)) { return(this.transceiver.Get(letter)); // Get } else { this.transceiver.Post(letter); // Post } } // local transmission if (localRouteInfo != null) { var copy = new EMLetter(letter); copy.Recipient = localRouteInfo.ToLiteral(); if (letter.HasFlag(Messages.StatusCode.Get)) { return(this.LocalGet(copy)); // Get } else { this.LocalGet(copy); // Post } } return(null); }