/// <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' }
EMLetter IMailTransceiver.Get(EMLetter letter) { letter.SetEnvelope(GetEnvelope()); var reply = Request(StatusCode.Letter, letter, letter.GetTTL(server.Now)); return(reply as EMLetter); }
void IMailTransceiver.Post(EMLetter letter) { CheckLogin(); letter.SetEnvelope(GetEnvelope()); this.AsyncRequest(StatusCode.Letter, letter, letter.GetTTL(this.Now)); }
/// <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)); }
EMLetter IMailTransceiver.Get(EMLetter letter) // dispatch the local letter to server { CheckLogin(); letter.SetEnvelope(GetEnvelope()); var reply = Request(StatusCode.Letter, letter, letter.GetTTL(this.Now)); if (reply.HasFlag(StatusCode.Denied)) { throw new EOCException((reply as EMText).Text); } return(reply as EMLetter); }
private EMLetter Dispatch(EMLetter letter, MailRouteInfo recipient) { var copy = new EMLetter(letter); copy.Recipient = recipient.ToLiteral(); this.dispatcherMutex.WaitOne(); if (this.dispatcher == null) { throw new Exception($"unable to dispatch letter '{letter.Title}' to '{letter.Recipient}', the dispatcher was offline."); } var result = this.dispatcher?.Get(copy); // Deactivate() may cause null dispatcher this.dispatcherMutex.ReleaseMutex(); return(result); }
/// <summary> /// push the letter into this postoffice for transfering to remote computer /// </summary> /// <param name="letter"></param> /// <param name="senderInfo"></param> /// <param name="recipientInfo"></param> internal EMLetter Push(EMLetter letter, MailRouteInfo recipientInfo) { if (IsActivated) // postoffice is activated { List <string> offlineEntities; lock (this.registeredReceiverEntityNames) { offlineEntities = recipientInfo.EntityNames.Except(registeredReceiverEntityNames).ToList(); } if (letter.HasFlag(StatusCode.Post)) // Post { if (offlineEntities.Count < recipientInfo.EntityNames.Count) // if any entity is online { this.Dispatch(letter, recipientInfo); } return(null); } else // Get { if (offlineEntities.Count > 0) { throw new Exception($"faild to send letter '{letter.Title}', entity(ies) '{string.Join(", ", offlineEntities)}@{recipientInfo.UserName}' is/are offline."); } return(this.Dispatch(letter, recipientInfo)); } } else // postoffice is not activated { if (letter.HasFlag(StatusCode.Post)) { // pass return(null); } else // Get { throw new Exception($"unable to '{letter.GetLetterType()}' letter '{letter.Title}', target user '{recipientInfo.UserName}' is offline."); } } }
/// <summary> /// an interface provided to 'ClientPostOffice' /// </summary> /// <param name="letter"></param> /// <returns></returns> internal EMLetter Receive(EMLetter letter) { if (letter.HasFlag(StatusCode.Post)) { ThreadPool.QueueUserWorkItem(o => // async mode { var result = this.Pickup(letter); if (result != null) { this.Reply(letter, result.Title, result.Content, result.Timeout); // async reply } }); return(null); } else // Get { return(this.Pickup(letter)); } }
/// <summary> /// push the letter into corresponding postoffice /// </summary> /// <param name="letter"></param> /// <returns>error message, null if there is no error</returns> internal EMLetter Deliver(EMLetter letter) { // routing rwlsDictName2User.EnterReadLock(); var allRecipientInfos = this.router.RouteRecipient(letter, this.dictName2User.Values); rwlsDictName2User.ExitReadLock(); allRecipientInfos = MailRouteInfo.Format(allRecipientInfos); var notExistsUserRouteInfos = allRecipientInfos.Where(info => !this.Contains(info.UserName)).ToList(); if (letter.HasFlag(StatusCode.Get)) { // check recipient if (allRecipientInfos.Count > 1) { throw new Exception($"letter of type '{nameof(StatusCode.Get)}' should not have multiple recipients."); } } if (notExistsUserRouteInfos.Count > 0) { throw new Exception($"user '{string.Join("; ", notExistsUserRouteInfos.Select(info => info.UserName).ToArray())}' not exists,faild to send letter"); // operation failed } foreach (var rInfo in allRecipientInfos) { var recipientOpr = this.GetUser(rInfo.UserName); var result = recipientOpr.PostOffice.Push(letter, rInfo); if (letter.HasFlag(StatusCode.Get)) { return(result); // Get } } return(null); // Post, SafePost }
private EMLetter Pickup(EMLetter letter) { LetterContent feedback; try { feedback = receiver.Pickup(letter); } catch (Exception ex) // exception report { feedback = new LetterContent("error", ex.Message, TransmissionMode.Post); } if (feedback == null) { return(null); } var fbLetter = new EMLetter(letter.Sender, this.MailAdress, feedback, letter.GetTTL(this.Now)); fbLetter.SetEnvelope(new Envelope(letter.ID)); return(fbLetter); }
/// <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); }
EMLetter IMailTransceiver.Get(EMLetter letter) { // ingore timeout return(client.ProcessRequest(letter)); // send to client through memory }
void IMailTransceiver.Post(EMLetter letter) { ThreadPool.QueueUserWorkItem(o => this.client.ProcessRequest(letter)); }
/// <summary> /// the letter will be delivered to local machine if the 'username' part of recipient is set to 'localhost' /// </summary> /// <param name="recipient"></param> /// <param name="title"></param> /// <param name="content"></param> /// <param name="letterType"></param> private void Send(string recipient, string title, object content, StatusCode letterType, int timeout) { var letter = new EMLetter(recipient, MailAdress, title, content, letterType, timeout); postoffice.Transfer(letter); }
internal void AsyncProcessRequest(EMLetter letter) { this.IncomingLetterEvent?.Invoke(letter); }
internal EMLetter ProcessRequest(EMLetter letter) // client receiving { return(this.IncomingLetterEvent?.Invoke(letter)); }
public EMLetter ProcessRequest(EMLetter letter) // letter request only { return(this.User.MailCenter.Deliver(letter)); }
/// <summary> /// 'Get' localhost /// </summary> /// <param name="letter"></param> /// <returns></returns> private EMLetter LocalGet(EMLetter letter) { return(this.OnIncomingLetter(letter)); }
void IMailTransceiver.Post(EMLetter letter) { letter.SetEnvelope(GetEnvelope()); this.AsyncRequest(StatusCode.Letter, letter, letter.GetTTL(server.Now)); }
private void OnTransmissionError(EMLetter letter, string errorMessage) { this.PostOfficeEvent?.Invoke(this, new PostOfficeEventArgs(PostOfficeEventType.Error, $"letter '{letter.Title}' encountered a transmission error: {errorMessage}")); }
EMLetter IMailTransceiver.Get(EMLetter letter) // client send, send to server through memory { // ingore timeout return(this.serverLoginAgentSimulator.ProcessRequest(letter)); }
/// <summary> /// 'Post' a letter to localhost /// </summary> /// <param name="letter"></param> private void LocalPost(EMLetter letter) { ThreadPool.QueueUserWorkItem(o => this.OnIncomingLetter(letter), letter); }
void IMailTransceiver.Post(EMLetter letter) { ThreadPool.QueueUserWorkItem(o => this.serverLoginAgentSimulator.ProcessRequest(letter)); }