///// <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; }
/// <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)); }
/// <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) ; }