/// <summary>
        /// Process real time data subscription
        /// </summary>
        public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgPing pinkoMsgPing)
        {
            var response = (IBusMessageOutbound)envelop;

            pinkoMsgPing.ResponderMachine = PinkoApplication.MachineName;
            pinkoMsgPing.ResponderDateTime = DateTime.Now;

            response.Message = pinkoMsgPing;

            return response;
        }
        /// <summary>
        /// Process real time data subscription
        /// </summary>
        public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgCalculateExpression expression)
        {
            var response = (IBusMessageOutbound)envelop;
            var marketEnv = PinkoMarketEnvManager.GetMarketEnv(expression.DataFeedIdentifier.MaketEnvId);
            var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression);

            response.Message = resultMsg;
            response.WebRoleId = expression.DataFeedIdentifier.WebRoleId;

            var finalFormExp = expression.GetExpression();

            Trace.TraceInformation("Calculating: {0}", expression.Verbose());

            //
            // Typed expressions supported are double and double[]
            //
            switch (resultMsg.ResultType)
            {
                // Single double result
                case PinkoCalculateExpressionDaoExtensions.ResultDouble:
                    {
                        var complExp = PinkoExpressionEngine.ParseAndCompile<double[]>(finalFormExp);
                        var results = PinkoExpressionEngine.Invoke(marketEnv, complExp);

                        if (null != results)
                            resultMsg.ResultsTupples = expression.ExpressionFormulas.GetTupleResult(results);
                    }
                    break;

                // 2-dim double[][]
                case PinkoCalculateExpressionDaoExtensions.ResultDoubleSeries:
                    {
                        var complExp = PinkoExpressionEngine.ParseAndCompile<double[][]>(finalFormExp);
                        var results = PinkoExpressionEngine.Invoke(marketEnv, complExp);

                        if (null != results)
                            resultMsg.ResultsTupples = expression.ExpressionFormulas.GetTupleResult(results);
                    }
                    break;

                default:
                    {
                        resultMsg.ResultType = PinkoErrorCode.FormulaTypeNotSupported;
                        response.ErrorCode = PinkoErrorCode.FormulaTypeNotSupported;
                        response.ErrorDescription = PinkoMessagesText.FormulaNotSupported;
                        response.ErrorSystem = PinkoMessagesText.FormulaNotSupported;
                    }
                    break;
            }

            return response;
        }
        /// <summary>
        /// Find clients subscriptions that timed out and remove them
        /// </summary>
        public IBusMessageOutbound ProcessTimedOutClients(IBusMessageInbound envelop, PinkoMsgClientTimeout clientTimeout)
        {
            using (CalculatingMutex.LockDisposible())
            {
                Trace.TraceInformation("Client Timeout. Unsubscribing: {0}", clientTimeout.DataFeedIdentifier.Verbose());
                SubscribersDouble.RemoveIdentifier(clientTimeout.DataFeedIdentifier);
            }

            return null;
        }
        /// <summary>
        /// Process real time data subscription
        /// </summary>
        public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgCalculateExpression expression)
        {
            var response = (IBusMessageOutbound)envelop;
            var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression);

            response.Message = resultMsg;
            response.WebRoleId = expression.DataFeedIdentifier.WebRoleId;

            // Wait for calculation to end before processing standard request.
            // Avoid have to lock while performing parallel calculations.
            //
            // WARNING: Subscriber collection are NOT thread safe
            //
            using (CalculatingMutex.LockDisposible())
            {
                switch (expression.MsgAction)
                {
                    case PinkoMessageAction.ManagerSubscription:
                        {
                            //
                            // Typed expressions supported are double and double[]
                            //
                            switch (resultMsg.ResultType)
                            {
                                // Single double result
                                case PinkoCalculateExpressionDaoExtensions.ResultDouble:
                                    {
                                        SubscribersDouble.UpdateSubscriber(resultMsg, () => PinkoExpressionEngine.ParseAndCompile<double[]>(expression.GetExpression()));
                                    }
                                    break;

                                // 2-dim double[][]
                                case PinkoCalculateExpressionDaoExtensions.ResultDoubleSeries:
                                    {
                                        SubscribersDoubleDouble.UpdateSubscriber(resultMsg, () => PinkoExpressionEngine.ParseAndCompile<double[][]>(expression.GetExpression()));
                                    }
                                    break;

                                // Invalid result type
                                default:
                                    {
                                        resultMsg.ResultType = PinkoErrorCode.FormulaTypeNotSupported;
                                        response.ErrorCode = PinkoErrorCode.FormulaTypeNotSupported;
                                        response.ErrorDescription = PinkoMessagesText.FormulaNotSupported;
                                        response.ErrorSystem = PinkoMessagesText.FormulaNotSupported;
                                    }
                                    break;
                            }
                        }
                        break;

                    //case PinkoMessageAction.ReconnectSubscribe:
                    //    {
                    //        // TODO: Add unsubscribe
                    //    }
                    //    break;

                    default:
                        {
                            resultMsg.ResultType = PinkoErrorCode.ActionNotSupported;
                            response.ErrorCode = PinkoErrorCode.ActionNotSupported;
                            response.ErrorDescription = PinkoMessagesText.ActionNotSupported;
                            response.ErrorSystem = PinkoMessagesText.ActionNotSupported;
                        }
                        break;
                }
            }

            return response;
        }
 /// <summary>
 /// Process real time data subscription
 /// </summary>
 public IBusMessageOutbound ProcessConnectionChange(IBusMessageInbound envelop, PinkoMsgClientConnect clientConnect)
 {
     using (CalculatingMutex.LockDisposible())
     {
         Trace.TraceInformation("Client Timeout: {0}", clientConnect.DataFeedIdentifier.Verbose());
         SubscribersDouble.UpdateIdentifier(clientConnect.DataFeedIdentifier);
     }
     return null;
 }
예제 #6
0
 /// <summary>
 /// Publish into proper typed bus. Here we look the proper typed bus.
 /// </summary>
 /// <param name="busMessageInbound"></param>
 public void Publish(IBusMessageInbound busMessageInbound)
 {
     _cachedBusPublisher[busMessageInbound.ContentType].Publish(busMessageInbound);
 }
        /// <summary>
        /// Process real time data subscription
        /// </summary>
        public IBusMessageOutbound ProcessSubscribe(IBusMessageInbound envelop, PinkoMsgCalculateExpression expression)
        {
            var response = (IBusMessageOutbound)envelop;
            var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression);

            response.Message = resultMsg;
            response.WebRoleId = expression.DataFeedIdentifier.WebRoleId;

            PinkoMsgCalculateExpression updatedExpMsg = null;
            var isNew = false;

            //  - Do check for current existence
            //  - look for Id changes.
            var clientSubscription =
                ClientSubscriptions.ReplaceCondition(expression.DataFeedIdentifier.SubscribtionId,
                                                     // only replace if null, or expressions are not equal.
                                                     x => (isNew = (null == x)) || !x.CalcExpression.IsEqual(expression),
                                                     x =>
                                                     {
                                                         // create new Runtime ids if formula was changed
                                                         if (null == x || x.CalcExpression.IsFormulaChanged(expression))
                                                             foreach (var formula in expression.ExpressionFormulas)
                                                                 formula.RuntimeId = Interlocked.Increment(ref _runtimeIdSequenceStart);

                                                         return new ClientSubscription() {CalcExpression = expression};
                                                     });

            if (clientSubscription.IsNotNull())
                updatedExpMsg = clientSubscription.CalcExpression;

            // Expression was either replaced, or added
            if (updatedExpMsg.IsNotNull())
            {
                // Update Runtime storage
                PinkoStorage.SaveExpression(PinkoStorageCode.SubsribeBucketName, HandlerPartitionId, expression.DataFeedIdentifier.SubscribtionId, expression);

                // Broadcast to Calc engines that a change happened. They need to update their ids.
                expression.MsgAction = PinkoMessageAction.ManagerSubscription;
                var outboundEnvelop = new PinkoServiceMessageEnvelop()
                {
                    WebRoleId = updatedExpMsg.DataFeedIdentifier.WebRoleId,
                    Message = updatedExpMsg,
                    ReplyTo = envelop.ReplyTo, // string.Empty,  //PinkoConfiguration.PinkoMessageBusToWebRoleCalcResultTopic,
                    //                               New Calc Engine                                             Subscription update to specific role
                    QueueName = isNew ? PinkoConfiguration.PinkoMessageBusToCalcEngineQueue : PinkoConfiguration.PinkoMessageBusToWorkerCalcEngineTopic
                };

                // publish
                TopicPublisher.Publish(outboundEnvelop);

                // do not reply.  The Calc engine will repond to client.
                return null;
            }

            //
            // Unsubscribe
            //  -   remove from storage
            //  -   Tell the calc engines to unsubscribe

            // Calc Engine monitor
            //  -   Monitor calc engines heart beat
            //  -   If failed, the re-subscribe the client

            // Monitor siblings
            //  -   If sibling missing, the take over its subscriptions
            //  -   Load from storage and re-subscribe the client formulas

            return response;
        }
        /// <summary>
        /// Process PinkoMsgClientPing
        /// </summary>
        public IBusMessageOutbound ProcessPinkoMsgClientPing(IBusMessageInbound envelop, PinkoMsgClientPing pinkoMsgClientPing)
        {
            var subs = ClientSubscriptions[pinkoMsgClientPing.DataFeedIdentifier.SubscribtionId];

            // Reset date to latest
            if (subs.IsNotNull() && subs.LastPing < pinkoMsgClientPing.PingTime)
                subs.LastPing = pinkoMsgClientPing.PingTime;

            return null;
        }
        /// <summary>
        /// Process real time data subscription
        /// </summary>
        public IBusMessageOutbound ProcessConnectionChange(IBusMessageInbound envelop, PinkoMsgClientConnect clientConnect)
        {
            ClientSubscriptions.ReplaceCondition(clientConnect.DataFeedIdentifier.SubscribtionId,
                                                 x => null != x && !x.CalcExpression.DataFeedIdentifier.IsEqual(clientConnect.DataFeedIdentifier),
                                                 x =>
                                                     {
                                                         var itemClone = x.CalcExpression.DeepClone();

                                                         itemClone.DataFeedIdentifier = itemClone.DataFeedIdentifier.PartialClone(clientConnect.DataFeedIdentifier);

                                                         // Replace with new change
                                                         return new ClientSubscription {CalcExpression = itemClone};
                                                     });
            return null;
        }