///// <summary>
        ///// PinkoCalculateExpressionResult
        ///// </summary>
        //public static string Verbose(this PinkoMsgCalculateExpressionResult obj)
        //{
        //    return string.Format("PinkoCalculateExpressionResult: Result: {0} - {1}",
        //                         string.Join(" = ", obj.ResultsTupple.Select(x => string.Format("{0} = {1}", x.OriginalFormula.ExpressionLabel, x.PointSeries.Select(p => p.Verbose())))),
        //                         obj.DataFeedIdentifier
        //                         );
        //}
        /// <summary>
        /// PinkoCalculateExpressionResult from PinkoCalculateExpressionResult
        /// </summary>
        public static PinkoMsgCalculateExpressionResult FromRequest(this PinkoMsgCalculateExpressionResult obj, PinkoMsgCalculateExpression src)
        {
            obj.DataFeedIdentifier = src.DataFeedIdentifier.CopyTo(new PinkoDataFeedIdentifier());
            obj.ResultType = src.ResultType;
            obj.ExpressionFormulas = src.ExpressionFormulas.DeepClone();

            return obj;
        }
Example #2
0
        /// <summary>
        /// Save current expression
        /// </summary>
        public bool SaveExpression(string bucket, string partition, string rowKey, PinkoMsgCalculateExpression expression)
        {
            var key = bucket + partition + rowKey;
            var exists = MockStorage.ContainsKey(key);

            MockStorage[key] = expression;

            return exists;
        }
        /// <summary>
        /// Copy all value
        /// </summary>
        /// <param name="src"></param>
        /// <param name="dest"></param>
        /// <returns>Destination passed in parameter</returns>
        public static PinkoMsgCalculateExpression CopyTo(this PinkoMsgCalculateExpression src, PinkoMsgCalculateExpression dest)
        {
            dest.ExpressionFormulas = src.ExpressionFormulas.DeepClone();
            dest.ExpressionFormulasStr = src.ExpressionFormulasStr;
            dest.MsgAction = src.MsgAction;
            dest.ResultType = src.ResultType;
            src.DataFeedIdentifier.CopyTo(dest.DataFeedIdentifier);

            return dest;
        }
        /// <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;
        }
        public void TestBadType()
        {
            var pinkoContainer = PinkoContainerMock.GetMockContainer();
            var handler = pinkoContainer.Resolve<RoleCalculateExpressionSnapshotHandler>().Register();

            var msgObj = new PinkoMsgCalculateExpression
            {
                ResultType = -99,
                ExpressionFormulas = SampleMockData.GetPinkoUserExpressionFormula(),
                DataFeedIdentifier = { MaketEnvId = PinkoMarketEnvironmentMock.MockMarketEnvId }
            };

            // Listen for outbound messages to monitor outbound queue
            var outboundMsg = handler.ProcessSubscribe(new PinkoServiceMessageEnvelop() { Message = msgObj }, msgObj);

            Assert.IsTrue(outboundMsg.ErrorCode == PinkoErrorCode.FormulaTypeNotSupported);
            Assert.IsTrue(outboundMsg.ErrorDescription == PinkoMessagesText.FormulaNotSupported);
        }
        public void TestCheckFields()
        {
            var pinkoContainer = PinkoContainerMock.GetMockContainer();
            var webRoleConnectManager = pinkoContainer.Resolve<IWebRoleConnectManager>();
            var outboundMessages = pinkoContainer.Resolve<OutbountListener<IBusMessageOutbound>>();
            var handler = pinkoContainer.Resolve<RoleCalculateExpressionSnapshotHandler>().Register();

            var msgObj = new PinkoMsgCalculateExpression
            {
                ResultType = PinkoCalculateExpressionDaoExtensions.ResultDouble,
                ExpressionFormulas = SampleMockData.GetPinkoUserExpressionFormula(3),
                DataFeedIdentifier =
                {
                    MaketEnvId = PinkoMarketEnvironmentMock.MockMarketEnvId,
                    SignalRId = "SignalRId",
                    ClientCtx = "ClientCtx",
                    WebRoleId = "WebRoleId",
                    ClientId = "ClientId"
                }
            };

            // Test formula
            var envelop = new PinkoServiceMessageEnvelop() { Message = msgObj };
            envelop.PinkoProperties[PinkoMessagePropTag.RoleId] = webRoleConnectManager.WebRoleId;

            // Process request
            var outboundMsg = handler.ProcessSubscribe(envelop, msgObj);

            Assert.IsNotNull(outboundMsg);
            Assert.IsTrue(outboundMsg.ErrorCode == PinkoErrorCode.Success);
            Assert.IsTrue(outboundMsg.WebRoleId == msgObj.DataFeedIdentifier.WebRoleId);
            Assert.IsFalse(string.IsNullOrEmpty(outboundMsg.WebRoleId));

            // needs a response role id to route to a specific web role
            Assert.IsFalse(string.IsNullOrEmpty(webRoleConnectManager.WebRoleId));
            Assert.IsTrue(outboundMsg.PinkoProperties[PinkoMessagePropTag.RoleId] == webRoleConnectManager.WebRoleId);

            var resultMsg = (PinkoMsgCalculateExpressionResult)outboundMsg.Message;
            Assert.IsTrue(resultMsg.DataFeedIdentifier.SignalRId.Equals("SignalRId"));
            Assert.IsTrue(resultMsg.DataFeedIdentifier.ClientCtx.Equals("ClientCtx"));
            Assert.IsTrue(resultMsg.DataFeedIdentifier.WebRoleId.Equals("WebRoleId"));
            Assert.IsTrue(resultMsg.DataFeedIdentifier.ClientId.Equals("ClientId"));
            Assert.IsTrue(resultMsg.DataFeedIdentifier.MaketEnvId.Equals(PinkoMarketEnvironmentMock.MockMarketEnvId));
        }
Example #7
0
 /// <summary>
 /// Remove Expression
 /// </summary>
 public bool RemoveExpression(string bucket, string partition, string rowKey, PinkoMsgCalculateExpression expression)
 {
     return true;
 }
        //
        // GET: /PinkoFormProcessor/
        // public HttpResponseMessage GetCalc(PinkoCalculateExpression reqForm)
        public HttpResponseMessage GetCalc(string expressionFormula,
                                            string maketEnvId,
                                            string clientCtx,
                                            string clientId,
                                            string signalRId,
                                            string webRoleId
                                            )
        {
            //return Subscribe(expressionFormula, maketEnvId, clientCtx, clientId, signalRId, webRoleId, "subsid");

            var expMsg = new PinkoMsgCalculateExpression
            {
                MsgAction = PinkoMessageAction.UserSnapshot,
                ExpressionFormulas = PinkoUserExpressionFormulaCommonExtensions.FromUrlParameter(expressionFormula),
                ExpressionFormulasStr = expressionFormula.Replace(" ", string.Empty),
                DataFeedIdentifier =
                {
                    MaketEnvId = maketEnvId,
                    ClientCtx = clientCtx,
                    ClientId = clientId,
                    SignalRId = signalRId,
                    WebRoleId = webRoleId,
                    SubscribtionId = "subscribtionId"
                }
            };

            if (expMsg.ExpressionFormulas.Length == 0)
                return new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "Invalid Pinko formula. The expression is either empty or invalid" };

            var msgEnvelop = PinkoApplication.FactorWebEnvelop(clientCtx, WebRoleConnectManager.WebRoleId, expMsg);

            msgEnvelop.ReplyTo = PinkoConfiguration.PinkoMessageBusToWebRoleCalcResultTopic;
            msgEnvelop.QueueName = PinkoConfiguration.PinkoMessageBusToWorkerSubscriptionManagerAllTopic;

            msgEnvelop.PinkoProperties[PinkoMessagePropTag.RoleId] = WebRoleConnectManager.WebRoleId;
            ServerMessageBus.Publish(msgEnvelop);

            return new HttpResponseMessage(HttpStatusCode.OK);
        }
        /// <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;
        }
        public void TestSubscribeRequestDoubleDouble()
        {
            var pinkoContainer = PinkoContainerMock.GetMockContainer();
            var handler = pinkoContainer.Resolve<RoleCalculateExpressionSnapshotHandler>().Register();

            var msgObj = new PinkoMsgCalculateExpression
            {
                ResultType = PinkoCalculateExpressionDaoExtensions.ResultDoubleSeries,
                ExpressionFormulas = SampleMockData.GetPinkoUserExpressionFormula(3),
                DataFeedIdentifier = { MaketEnvId = PinkoMarketEnvironmentMock.MockMarketEnvId }
            };

            // Test formula
            var outboundMsg = handler.ProcessSubscribe(new PinkoServiceMessageEnvelop() { Message = msgObj }, msgObj);

            Assert.IsTrue(outboundMsg.ErrorCode == PinkoErrorCode.Success);
            var resultMsg = (PinkoMsgCalculateExpressionResult)outboundMsg.Message;

            Assert.IsTrue(resultMsg.ResultType == PinkoCalculateExpressionDaoExtensions.ResultDoubleSeries);
            Assert.IsTrue(resultMsg.ResultsTupples[0].PointSeries[0].PointValue == 0);
        }
        public void TestSubscribeException()
        {
            var pinkoContainer = PinkoContainerMock.GetMockContainer();
            var webRoleConnectManager = pinkoContainer.Resolve<IWebRoleConnectManager>();
            var outboundMessages = pinkoContainer.Resolve<OutbountListener<IBusMessageOutbound>>();
            var handler = pinkoContainer.Resolve<RoleCalculateExpressionSnapshotHandler>().Register();
            var expEngine = pinkoContainer.Resolve<IPinkoExpressionEngine>() as PinkoExpressionEngineMock;

            //var msgObj = SampleMockData.GetPinkoMsgCalculateExpression()[0];
            //msgObj.MsgAction = PinkoMessageAction.UserSnapshot;  // Set to snapshot

            // Test formula
            var msgObj = new PinkoMsgCalculateExpression
                             {
                                 ResultType = PinkoCalculateExpressionDaoExtensions.ResultDouble,
                                 ExpressionFormulas = SampleMockData.GetPinkoUserExpressionFormula(3),
                                 MsgAction = PinkoMessageAction.UserSnapshot,
                                 DataFeedIdentifier = { MaketEnvId = PinkoMarketEnvironmentMock.MockMarketEnvId }
                             };
            var envelop = new PinkoServiceMessageEnvelop() { Message = msgObj, ReplyTo = "UniteTestReplyQueue" };
            envelop.PinkoProperties[PinkoMessagePropTag.RoleId] = webRoleConnectManager.WebRoleId;

            // Test formula - should exception
            expEngine.ExceptionParseAction = () =>
                                          {
                                              throw new Exception("MockException");
                                          };

            // Process request
            handler.PinkoMsgCalculateExpressionReactiveListener.HandlerAction(envelop, msgObj);

            Assert.IsTrue(outboundMessages.OutboundMessages.Count == 1);
            Assert.IsTrue(outboundMessages.OutboundMessages.ElementAt(0).ErrorCode == PinkoErrorCode.UnexpectedException);

            //var resultMsg = (PinkoMsgCalculateExpressionResult)outboundMessages.OutboundMessages.ElementAt(0).Message;
            //Assert.IsTrue(resultMsg.ResultType == PinkoErrorCode.UnexpectedException);
        }
        /// <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;
        }
        public void TestExpressionBuild()
        {
            var msgObj = new PinkoMsgCalculateExpression
            {
                ExpressionFormulas = SampleMockData.GetPinkoUserExpressionFormula(3),
            };

            var expression = msgObj.GetExpression();
            Assert.IsTrue(expression.Reduce() == "{ Lbl_0 = 0.1 * 0.2; Lbl_1 = 1.1 * 1.2; Lbl_2 = 2.1 * 2.2; [  Lbl_0, Lbl_1, Lbl_2 ]  }".Reduce());
        }
 /// <summary>
 /// Was formula changed ? 
 /// </summary>
 /// <param name="dest"></param>
 /// <param name="src"></param>
 /// <returns>
 /// True: formula was changed
 /// False: formula was not changed
 /// </returns>
 public static bool IsFormulaChanged(this PinkoMsgCalculateExpression src, PinkoMsgCalculateExpression dest)
 {
     return src == null ||  false == dest.ExpressionFormulasStr.Equals(src.ExpressionFormulasStr);
 }
 /// <summary>
 /// Checks values are the same by comparing internal values.
 /// </summary>
 /// <param name="dest"> </param>
 /// <param name="src"></param>
 /// <returns>
 /// True: they are equal
 /// False: they not are equal
 /// </returns>
 public static bool IsEqual(this PinkoMsgCalculateExpression dest, PinkoMsgCalculateExpression src)
 {
     return
            dest.ExpressionFormulasStr.Equals(src.ExpressionFormulasStr)
            &&
            dest.DataFeedIdentifier.IsEqual(src.DataFeedIdentifier)
         ;
 }