Пример #1
0
        /// <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);
        }
Пример #3
0
        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));
        }
Пример #5
0
        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));
            }
        }
Пример #9
0
        /// <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);
        }
Пример #11
0
        /// <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);
        }
Пример #15
0
 internal void AsyncProcessRequest(EMLetter letter)
 {
     this.IncomingLetterEvent?.Invoke(letter);
 }
Пример #16
0
 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));
 }
Пример #18
0
 /// <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));
        }
Пример #20
0
 private void OnTransmissionError(EMLetter letter, string errorMessage)
 {
     this.PostOfficeEvent?.Invoke(this, new PostOfficeEventArgs(PostOfficeEventType.Error, $"letter '{letter.Title}' encountered a transmission error: {errorMessage}"));
 }
Пример #21
0
 EMLetter IMailTransceiver.Get(EMLetter letter)  // client send, send to server through memory
 {
     // ingore timeout
     return(this.serverLoginAgentSimulator.ProcessRequest(letter));
 }
Пример #22
0
 /// <summary>
 /// 'Post' a letter to localhost
 /// </summary>
 /// <param name="letter"></param>
 private void LocalPost(EMLetter letter)
 {
     ThreadPool.QueueUserWorkItem(o => this.OnIncomingLetter(letter), letter);
 }
Пример #23
0
 void IMailTransceiver.Post(EMLetter letter)
 {
     ThreadPool.QueueUserWorkItem(o => this.serverLoginAgentSimulator.ProcessRequest(letter));
 }