/// <summary> /// IsEqual - Checks all values to be the same /// </summary> public static bool IsEqual(this PinkoMsgCalculateExpressionResult src, PinkoMsgCalculateExpressionResult dest) { return src.DataFeedIdentifier.IsEqual(dest.DataFeedIdentifier) && src.ExpressionFormulas.IsEqual(dest.ExpressionFormulas) ; }
/// <summary> /// Copy all value /// </summary> /// <param name="src"></param> /// <param name="dest"></param> /// <returns>Destination passed in parameter</returns> public static PinkoMsgCalculateExpressionResult CopyTo(this PinkoMsgCalculateExpression src, PinkoMsgCalculateExpressionResult dest) { src.DataFeedIdentifier.CopyTo(dest.DataFeedIdentifier); dest.ExpressionFormulas = src.ExpressionFormulas.DeepClone(); dest.ResultType = src.ResultType; 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; }
/// <summary> /// Get resulting tuple with envelop and expression /// </summary> public static Tuple<PinkoMsgCalculateExpressionResult, PinkoServiceMessageEnvelop, PinkoMsgCalculateExpression> GetResultTuple() { var expression = GetPinkoMsgCalculateExpression()[0]; var resultMsg = new PinkoMsgCalculateExpressionResult().FromRequest(expression); var envelop = new PinkoServiceMessageEnvelop() { Message = expression }; return new Tuple<PinkoMsgCalculateExpressionResult, PinkoServiceMessageEnvelop, PinkoMsgCalculateExpression>(resultMsg, envelop, expression); }
/// <summary> /// PinkoMsgCalculateExpressionResult list /// </summary> public static List<PinkoMsgCalculateExpressionResult> GetPinkoMsgCalculateExpressionResult(int amt = 100) { return GetPinkoMsgCalculateExpression(amt) .Select(x => { var result = new PinkoMsgCalculateExpressionResult().FromRequest(x); result.ResultsTupples = GetResultsTuppleWrapper().ToArray(); return result; }) .ToList(); }
/// <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 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; }