| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- using Muchinfo.MTPClient.Data.Enums;
- using Muchinfo.MTPClient.Data.Model;
- using Muchinfo.MTPClient.Infrastructure.Cache;
- using Muchinfo.MTPClient.Infrastructure.EntityHelpers;
- using Muchinfo.MTPClient.Infrastructure.Helpers;
- using Muchinfo.MTPClient.Infrastructure.Utilities;
- using Muchinfo.MTPClient.NetworkCore;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Threading;
- using System.Timers;
- using Timer = System.Timers.Timer;
- namespace Muchinfo.MTPClient.Infrastructure.LinkProxy.TCP
- {
- /// <summary>
- /// 业务代理连接
- /// </summary>
- public class QuoteTcpLinkProxy : IDisposable
- {
- public string _host; ////主机地址
- public int _port; ////通信端口号
- private TCPManager _tcpManager;
- private Timer _timer;
- private bool _isGetGoodsInfo; ////是否从行情服务获取商品信息
- private readonly object _lock = new object();
- private bool _subscribeFlag = true;
- private bool _queryDayQuote = true;
- private const int c_AccountId = 2;
- private const string c_checkToken = "2_TOKEN_NEKOT_"; ///2_TOKEN_NEKOT_
- public TCPConnectState TcpConnectState
- {
- get { return (_tcpManager == null) ? TCPConnectState.Closed : _tcpManager.tcpConnectState; }
- }
- /// <summary>
- /// 创建业务连接
- /// </summary>
- /// <param name="isGetGoods">是否获取商品信息</param>
- public QuoteTcpLinkProxy(string host, int port, bool isGetGoods = false)
- {
- _isGetGoodsInfo = isGetGoods;
- _host = host;
- _port = port;
- _tcpManager = new TCPManager(DatagramType.Datagram40, new QuoteTcpCallback(this));
- LogInfoHelper.WriteInfo("开始连接行情服务..");
- _tcpManager.Connect(_host, _port, ConnectSuccess, ConnectFail);
- var interval = GetSyncDayQuoteInterval();
- _timer = new Timer(interval);
- _timer.Elapsed += Timer_Elapsed;
- }
- #region Private Methods
- /// <summary>
- /// Handles the Elapsed event of the Timer control.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">The <see cref="ElapsedEventArgs"/> instance containing the event data.</param>
- private void Timer_Elapsed(object sender, ElapsedEventArgs e)
- {
- QueryDayQuote();
- }
- /// <summary>
- /// 获取同步盘面间隔,默认10分钟
- /// </summary>
- /// <returns>System.Int32.</returns>
- private int GetSyncDayQuoteInterval()
- {
- int interval = 10;
- try
- {
- var value = ApplicationParameter.DayQuoteInterval;
- if (value <= 0)
- {
- interval = 10;
- }
- }
- catch
- {
- interval = 10;
- }
- ////单位:分钟
- return interval * 1000 * 60;
- }
- /// <summary>
- /// 连接失败
- /// </summary>
- /// <param name="errorCode">错误码</param>
- /// <param name="desc">连接描述</param>
- private void ConnectFail(int errorCode, string desc)
- {
- //停止同步盘面定时器,Subscribe()成功后会启动
- StopSyncTimer();
- _tcpManager.ReconnectWithDisconnFirst(); //行情连接不上进需重连
- //todo:通知连接失败
- LogInfoHelper.WriteInfo("行情服务连接失败![" + errorCode + "] " + desc);
- MessengerHelper.DefaultSend(false, MessengerTokens.QuoteCheckTokenSuccess);
- }
- /// <summary>
- /// 连接成功
- /// </summary>
- private void ConnectSuccess()
- {
- if (!_isGetGoodsInfo)
- {
- LogInfoHelper.WriteInfo("行情服务连接成功!, 开始订阅商品.");
- _subscribeFlag = true;
- //连接成功订阅商品
- Subscribe();
- }
- else
- {
- LogInfoHelper.WriteInfo(" 行情服务令牌校验.");
- ////取时间
- CheckedToken();
- }
- }
- #endregion
- #region Public Methods
- /// <summary>
- /// 发送消息,
- /// </summary>
- /// <param name="package">消息内容</param>
- /// <param name="successAction">成功回复</param>
- /// <param name="failAction">错误回复</param>
- public void SendPackage(TCPPackage40 package, Action<TCPPackage40> successAction, Action<int, string> failAction)
- {
- if (_tcpManager == null || TcpConnectState != TCPConnectState.Connected) return;
- _tcpManager.SendMessage(package, successAction, failAction);
- }
- /// <summary>
- /// 通知通信组件开始发送心跳的方法
- /// </summary>
- public void StartSendBeat()
- {
- if (_tcpManager == null) return;
- _tcpManager.StartSendBeats();
- }
- /// <summary>
- /// 组包并订阅
- /// </summary>
- public void Subscribe()
- {
- Subscribe(GetAvailableList(CacheManager.CacheGoodsBaseInfos));
- }
- /// <summary>
- /// 断线(开市)清盘
- /// </summary>
- public void ClearQuote()
- {
- ///先清盘
- foreach (var goods in CacheManager.CacheGoodsBaseInfos)
- {
- if (_isGetGoodsInfo && goods.ContainsGoodsSrc == (int)GoodsFromScr.Brown) ////行情商品清盘
- {
- goods.ClearQuote();
- }
- else if (!_isGetGoodsInfo && (goods.ContainsGoodsSrc & (int)GoodsFromScr.Trade) > 0) ////交易商品清盘
- {
- goods.ClearQuote();
- }
- }
- }
- /// <summary>
- /// 组包并订阅
- /// </summary>
- /// <param name="list">The list.</param>
- public void Subscribe(List<QuoteGoods> list)
- {
- if (_subscribeFlag)
- {
- _subscribeFlag = false;
- try
- {
- if (null == list || !list.Any())
- {
- list = new List<QuoteGoods>()
- {
- new QuoteGoods("250", "99999999", "99999999", QuoteCategoryType.PreciousMetal)
- };
- LogInfoHelper.WriteInfo("调用Subscribe() 订阅QuoteGoods列表为空,发送不存在商品进行取消订阅!");
- }
- TCPPackage40 gram = new TCPPackage40
- {
- Tag = (byte) Datagram40TagPrimaryFunction.Trade,
- Tag2 = (byte) Datagram40TagPrimaryFunction.Reserve //随便填值
- };
- var accountId = _isGetGoodsInfo ? c_AccountId : UserManager.CurrentTradeAccount.LoginID;
- var token = _isGetGoodsInfo ? c_checkToken : UserManager.CurrentTradeAccount.Token;
- byte[] bytes = list.GetSubscribeBytesV2(accountId, token);
- //LogInfoHelper.WriteInfo("Login:" + BitConverter.ToString(bytes));
- gram.SetData(bytes);
- SendPackage(gram, LogInCallback, ExceptionCallback);
- }
- catch (Exception e)
- {
- LogInfoHelper.WriteInfo("调用Subscribe() catch:" + e.Message);
- }
- finally
- {
- _subscribeFlag = true;
- }
- }
- }
- /// <summary>
- /// 行情链路令牌校检
- /// </summary>
- public void CheckedToken()
- {
- if (!_isGetGoodsInfo) ////交易链路不校检
- return;
- ////行情链路校检Token取服务器时间
- try
- {
- TCPPackage40 gram = new TCPPackage40
- {
- Tag = (byte)Datagram40TagPrimaryFunction.QuoteChekedToken,
- Tag2 = (byte)Datagram40TagPrimaryFunction.Reserve //随便填值
- };
- byte[] bytes = QuoteDatagramHelper.QuoteCheckToken( c_AccountId, c_checkToken);
- gram.SetData(bytes);
- SendPackage(gram, CheckedSuccess, CheckedTokenError);
- }
- catch (Exception e)
- {
- _subscribeFlag = true;
- LogInfoHelper.WriteInfo("调用CheckedToken() catch:" + e.Message);
- }
- }
- public void CheckedSuccess(TCPPackage40 package)
- {
- try
- {
- var bytes = package.GetData();
- var count = GetReturnCode(bytes);
- //>=0: Goods个数; <0: 错误码(-1:报文解析失败,-2:Token校验失败,-3:订阅商品不合法)
- LogInfoHelper.WriteInfo("行情链路令牌校检, 返回码:" + count);
- if (count >= 0)
- {
- byte[] block = new byte[4];
- Array.Copy(bytes, 4, block, 0, 4);
- var servrTime = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(block, 0));
- ApplicationParameter.SetSystemTime(servrTime);
- MessengerHelper.DefaultSend(true, MessengerTokens.QuoteCheckTokenSuccess);
- }
- else
- {
- MessengerHelper.DefaultSend(false, MessengerTokens.QuoteCheckTokenSuccess);
- }
- }
- catch (Exception ex)
- {
- LogInfoHelper.WriteInfo("查询QueryDayQuote解析失败" + ex.ToString());
- }
- }
- /// <summary>
- /// Checked
- /// </summary>
- /// <param name="errorId"></param>
- /// <param name="message"></param>
- private void CheckedTokenError(int errorId, string message)
- {
- MessengerHelper.DefaultSend(false, MessengerTokens.QuoteCheckTokenSuccess);
- LogInfoHelper.WriteInfo("调用CheckedToken() " + errorId + ":" + message);
- }
- /// <summary>
- /// Queries the day quote.
- /// </summary>
- public void QueryDayQuote()
- {
- QueryDayQuote(GetAvailableList(CacheManager.CacheGoodsBaseInfos));
- }
- /// <summary>
- /// Gets the available list.
- /// </summary>
- /// <param name="list">The list.</param>
- /// <returns>IEnumerable{QuoteGoods}.</returns>
- private List<QuoteGoods> GetAvailableList(List<QuoteGoods> list)
- {
- //if (list == null || !list.Any()) return null;
- //////交易商品
- //if (!_isGetGoodsInfo)
- //{
- // list = list.Where((item) => (item.ContainsGoodsSrc & (int)GoodsFromScr.trade) > 0).ToList();
- //}
- //else
- //{
- // ////行情商品
- // list = list.Where((item) => (item.ContainsGoodsSrc == (int)GoodsFromScr.Brown)).ToList();
- //}
- //////商城、发售商品不需要订阅和查询盘面
- ////var result = list.Where(z => z.GoodsParameters != null && z.TradeMode != eTradeMode.TRADEMODE_SALE && z.TradeMode != eTradeMode.TRADEMODE_MALL);
- //var result = list.Where(z => z.GoodsParameters != null);
- //if (result == null || !result.Any()) return null;
- //return result.ToList();
- //订阅持仓商品+当前分类标签显示的商品+当前交易面板的商品 -- dyp
- var lst = new List<int>();
- if(UserManager.CurrentGoodsId >0) lst.Add(UserManager.CurrentGoodsId);
- var pList = UserManager.GetHoldSummaries(UserManager.CurrentTradeAccount.FundsAccountId);
- if (pList != null && pList.Any()) lst.AddRange(pList.Select(z => (int)z.GoodsId).ToList());
- if (UserManager.CurrentGoodsIds != null && UserManager.CurrentGoodsIds.Any()) lst.AddRange(UserManager.CurrentGoodsIds);
- var goodses = CacheManager.CacheGoodsBaseInfos.Where(z => lst.Contains((int)z.GoodsId)) ?? new List<QuoteGoods>();
- return goodses.ToList();
- }
- /// <summary>
- /// 盘面查询申请
- /// </summary>
- /// <param name="list">The list.</param>
- public void QueryDayQuote(List<QuoteGoods> list)
- {
- lock (_lock)
- {
- if (_queryDayQuote)
- {
- if (list == null || !list.Any()) return;
- try
- {
- _queryDayQuote = false;
- TCPPackage40 gram = new TCPPackage40
- {
- Tag = (byte)Datagram40TagPrimaryFunction.Query,
- Tag2 = (byte)Datagram40TagPrimaryFunction.Reserve, //随便填值
- };
- var accountId = _isGetGoodsInfo ? c_AccountId : UserManager.CurrentTradeAccount.LoginID;
- var token = _isGetGoodsInfo ? c_checkToken : UserManager.CurrentTradeAccount.Token;
- byte[] bytes = list.ToList()
- .GetSubscribeBytesV2(accountId, token);
- gram.SetData(bytes);
- SendPackage(gram, QueryDayQuoteCallback, QueryDayQuoteExceptionCallback);
- LogInfoHelper.WriteInfo("行情取盘面 数量:" + list.Count);
- }
- catch
- {
- _queryDayQuote = true;
- }
- }
- }
- }
- /// <summary>
- /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
- /// </summary>
- public void Dispose()
- {
- if (_timer != null)
- {
- _timer.Stop();
- _timer = null;
- }
- if (_tcpManager != null)
- {
- _tcpManager.Disconnect();
- _tcpManager = null;
- }
- }
- #endregion
- #region SendCallbacks
- /// <summary>
- /// Logs the in callback.
- /// </summary>
- /// <param name="package">The package.</param>
- private void LogInCallback(TCPPackage40 package)
- {
- try
- {
- var bytes = package.GetData();
- var count = GetReturnCode(bytes);
- //>=0: Goods个数; <0: 错误码(-1:报文解析失败,-2:Token校验失败,-3:订阅商品不合法)
- LogInfoHelper.WriteInfo("行情订阅成功回调, 返回码:" + count);
- if (count == -2)
- {
- //Token校验失败, 不处理,等待交易链路回应
- //MessengerHelper.DefaultSend(false, MessengerTokens.UserOfflineNoticeToken);
- var random = new Random();
- var second = random.Next(5000, 10000);
- Thread.Sleep(second);
- }
- else if (count >= 0)
- {
- //订阅成功,发送盘面查询请求
- QueryDayQuote();
- if (_timer == null) return;
- _timer.Stop();
- _timer.Start();
- }
- }
- catch
- {
- }
- finally
- {
- _subscribeFlag = true;
- StartSendBeat();
- LogInfoHelper.WriteInfo("行情订阅成功回调,启动发送心跳包!");
- }
- }
- /// <summary>
- /// Exceptions the callback.
- /// </summary>
- /// <param name="errorId">The error identifier.</param>
- /// <param name="message">The message.</param>
- private void ExceptionCallback(int errorId, string message)
- {
- _subscribeFlag = true;
- LogInfoHelper.WriteInfo("行情订阅出错:" + errorId + " " + message);
- }
- /// <summary>
- /// Queries the day quote callback.
- /// </summary>
- /// <param name="package">The package.</param>
- private void QueryDayQuoteCallback(TCPPackage40 package)
- {
- try
- {
- var bytes = package.GetData();
- var count = GetReturnCode(bytes);
- //// >=0: 返回记录数目; <0: 错误码(-1:报文解析失败,-2:Token校验失败,-3:订阅商品不合法)
- LogInfoHelper.WriteInfo("查询QueryDayQuote成功,返回:" + count);
- if (count == -2)
- {
- ////Token校验失败, 返回登录界面
- LogInfoHelper.WriteInfo("查询QueryDayQuote 失败返回 -2");
- //MessengerHelper.DefaultSend(RestartType.QuoteCheckedFail, MessengerTokens.UserOfflineNoticeToken);
- }
- else if (count >= 0)
- {
- ////查询成功,更新数据
- if (bytes.Length < 4) return;
- ////前四位为count,数据体从4位开始
- var length = bytes.Length - 4;
- var goodsData = bytes.Skip(4).Take(length).ToArray();
- var quoteTiks = goodsData.ToQuoteTiks(true);
- quoteTiks.UpdateQuoteGoodses();
- }
- }
- catch (Exception ex)
- {
- LogInfoHelper.WriteInfo("查询QueryDayQuote解析失败" + ex.ToString());
- }
- finally
- {
- _queryDayQuote = true;
- }
- }
- /// <summary>
- /// Exceptions the callback.
- /// </summary>
- /// <param name="errorId">The error identifier.</param>
- /// <param name="message">The message.</param>
- private void QueryDayQuoteExceptionCallback(int errorId, string message)
- {
- _queryDayQuote = true;
- LogInfoHelper.WriteInfo("盘面查询请求失败:" + message + "[" + errorId + "]");
- }
- /// <summary>
- /// Gets the return code.
- /// </summary>
- /// <param name="bytes">The bytes.</param>
- /// <returns>System.Int32.</returns>
- private int GetReturnCode(byte[] bytes)
- {
- /* 查询返回结构体
- * 查询通用回应(包括订阅、盘面查询等)
- typedef struct tagQUERY_COMMON_REQ {
- int32_t iCount; // >=0: 返回记录数目; <0: 错误码(-1:报文解析失败,-2:Token校验失败,-3:订阅商品不合法)
- void* pRecords; // 根据请求类别分别指向不同的结果集(GOODS/QUERY_HISTROY_RSP/...)
- } QUERY_COMMON_REQ;
- */
- //// >=0: 返回记录数目; <0: 错误码(-1:报文解析失败,-2:Token校验失败,-3:订阅商品不合法)
- if (bytes == null || bytes.Length < 4) return -1;
- var returnCodeBytes = bytes.Take(4).ToArray();
- return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(returnCodeBytes, 0));
- }
- /// <summary>
- /// 停止同步盘面定时器,Subscribe()成功后会启动
- /// </summary>
- public void StopSyncTimer()
- {
- if (_timer != null) _timer.Stop();
- }
- /// <summary>
- /// 设置断线重连标志
- /// </summary>
- public void SetReconnectFlag(bool flag)
- {
- if (null != _tcpManager) _tcpManager.SetReconnectFlag(flag);
- }
- #endregion
- }
- }
|