public async Task ReceiveLoop(string url, bool autoReconnect, Action <Models.Wlt> onWallet, Action <Models.TrdRec> onTrade, Action <Models.Ord> onOrder, Action <Models.Position> onPosition, Action <Models.WltLog> onWltLog, Action onDisconnected, Action onReconnected, CancellationToken cancellationToken) { try { _ws?.Dispose(); _ws = new ClientWebSocket(); await _ws.ConnectAsync(new Uri(url), cancellationToken); } catch (Exception ex) { throw ex; } await Task.Factory.StartNew(async() => { var buffer = new byte[GlobalDefine.K_MAX_MSG_SIZE]; // 有时消息会很大,比如查询1天的分钟K结果. while (true) { if (cancellationToken.IsCancellationRequested) { Debug.WriteLine($"[NOTE] Trade WebSocket({url}) is Cancelled!"); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); return; } if (_ws.State != WebSocketState.Open) { if (!autoReconnect) { Debug.WriteLine("[WARN] Trade WebSocketState is not Open: " + _ws.State); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); return; } else { Debug.WriteLine($"[INFO] Trade WebSocket reconnecting {url}...."); try { _ws?.Dispose(); _ws = new ClientWebSocket(); await _ws.ConnectAsync(new Uri(url), cancellationToken); if (_ws.State == WebSocketState.Open) { onReconnected?.Invoke(); } continue; } catch (Exception ex) { throw ex; } } } var segment = new ArraySegment <byte>(buffer); var result = await _ws.ReceiveAsync(segment, cancellationToken); if (result.MessageType == WebSocketMessageType.Close) { Debug.WriteLine("[WARN] WebSocketMessageType.Close when recv msg."); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); continue; } int count = result.Count; while (!result.EndOfMessage) { if (count >= buffer.Length) { Debug.WriteLine("[ERROR] InvalidPayloadData."); await _ws.CloseAsync(WebSocketCloseStatus.InvalidPayloadData, "That's too long", cancellationToken); onDisconnected?.Invoke(); continue; } segment = new ArraySegment <byte>(buffer, count, buffer.Length - count); result = await _ws.ReceiveAsync(segment, cancellationToken); if (result.MessageType == WebSocketMessageType.Close) { Debug.WriteLine("[WARN] WebSocketMessageType.Close when continue-recv msg."); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); continue; } count += result.Count; } var rspTxt = Encoding.UTF8.GetString(buffer, 0, count); WsMarketMessageResponse resp = null; try { resp = Helper.MyJsonUnmarshal <WsMarketMessageResponse>(rspTxt); } catch (Exception ex) { Debug.WriteLine("[ERROR] Deserialize Resp err: " + ex.Message); } if (resp == null) { continue; } if (resp?.ReqID?.Length > 0) { if (_request_callback.ContainsKey(resp.ReqID)) { var action = _request_callback[resp.ReqID]; _request_callback.Remove(resp.ReqID); action?.Invoke(resp.Code, resp.Data); } else { Debug.WriteLine("[WARN] ignore non-exists-reqid resp << " + rspTxt); } } else if (resp?.Subj?.Length > 0) { if (resp.Subj == "onWallet") { var msg = Helper.MyJsonSafeToObj <Models.Wlt>(resp.Data); if (msg != null) { onWallet?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == "onTrade") { var msg = Helper.MyJsonSafeToObj <Models.TrdRec>(resp.Data); if (msg != null) { onTrade?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == "onOrder") { var msg = Helper.MyJsonSafeToObj <Models.Ord>(resp.Data); if (msg != null) { onOrder?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == "onPosition") { // {"subj":"onPosition","data":{"ADLIdx":-0.1733476102,"AId":"112508701","FeeEst":0.000000201,"Lever":0,"MI":0,"MMnF":0.0000013399,"MgnISO":0,"PId":"01CZ54KHZ9VAGCNPDWHS2XQREC","PrzBr":5.3328399195,"PrzIni":3732.57,"PrzLiq":5.3594841359,"ROE":-0.0002480831,"RPNL":-0.0000002009,"Sym":"BTC.BTC","Sz":1,"UId":"1125087","UPNL":-0.0000000665,"Val":-0.0002679119,"WId":"112508701BTC"}} var msg = Helper.MyJsonSafeToObj <Models.Position>(resp.Data); if (msg != null) { onPosition?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == "onWltLog") { var msg = Helper.MyJsonSafeToObj <Models.WltLog>(resp.Data); if (msg != null) { onWltLog?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else { Debug.WriteLine("[WANR]: unknown subj: " + rspTxt); } } else { Debug.WriteLine("[ERROR] invalid msg from trade-ws-server: " + rspTxt); } } }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
public async Task ReceiveLoop(string url, bool autoReconnect, Action <Models.MktTradeItem> onMktTradeItem, Action <Models.MktOrderItem> onMktOrderItem, Action <Models.MktOrder20Result> onMktOrder20Result, Action <Models.MktInstrumentTick> onMktInstrumentTick, Action <Models.MktCompositeIndexTick> onMktCompositeIndexTick, Action <Models.MktKLineItem> onMktKLineItem, Action onDisconnected, Action onReconnected, CancellationToken cancellationToken) { try { _ws?.Dispose(); _ws = new ClientWebSocket(); await _ws.ConnectAsync(new Uri(url), cancellationToken); }catch (Exception ex) { throw ex; } await Task.Factory.StartNew(async() => { var buffer = new byte[GlobalDefine.K_MAX_MSG_SIZE]; // 有时消息会很大,比如查询1天的分钟K结果. while (true) { if (cancellationToken.IsCancellationRequested) { Debug.WriteLine($"[NOTE] Market WebSocket({url}) is Cancelled!"); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); return; } if (_ws.State != WebSocketState.Open) { if (!autoReconnect) { Debug.WriteLine("[WARN] Market WebSocketState is not Open: " + _ws.State); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); return; } else { Debug.WriteLine($"[INFO] Market WebSocket reconnecting {url}...."); try { _ws?.Dispose(); _ws = new ClientWebSocket(); await _ws.ConnectAsync(new Uri(url), cancellationToken); if (_ws.State == WebSocketState.Open) { onReconnected?.Invoke(); } continue; } catch (Exception ex) { throw ex; } } } var segment = new ArraySegment <byte>(buffer); var result = await _ws.ReceiveAsync(segment, cancellationToken); if (result.MessageType == WebSocketMessageType.Close) { Debug.WriteLine("[WARN] WebSocketMessageType.Close when recv msg."); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); continue; } int count = result.Count; while (!result.EndOfMessage) { if (count >= buffer.Length) { Debug.WriteLine("[ERROR] InvalidPayloadData."); await _ws.CloseAsync(WebSocketCloseStatus.InvalidPayloadData, "That's too long", cancellationToken); onDisconnected?.Invoke(); continue; } segment = new ArraySegment <byte>(buffer, count, buffer.Length - count); result = await _ws.ReceiveAsync(segment, cancellationToken); if (result.MessageType == WebSocketMessageType.Close) { Debug.WriteLine("[WARN] WebSocketMessageType.Close when continue-recv msg."); await _ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, cancellationToken); onDisconnected?.Invoke(); continue; } count += result.Count; } var rspTxt = Encoding.UTF8.GetString(buffer, 0, count); WsMarketMessageResponse resp = null; try { resp = Helper.MyJsonUnmarshal <WsMarketMessageResponse>(rspTxt); } catch (Exception ex) { Debug.WriteLine("[ERROR] Deserialize Resp err: " + ex.Message); } if (resp == null) { continue; } if (resp?.ReqID?.Length > 0) { if (_request_callback.ContainsKey(resp.ReqID)) { var action = _request_callback[resp.ReqID]; _request_callback.Remove(resp.ReqID); action?.Invoke(resp.Code, resp.Data); } else { Debug.WriteLine("[WARN] ignore non-exists-reqid resp << " + rspTxt); } } else if (resp?.Subj?.Length > 0) { if (resp.Subj == K_SUBJ_TRADE) { var msg = Helper.MyJsonSafeToObj <Models.MktTradeItem>(resp.Data); if (msg != null) { onMktTradeItem?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == K_SUBJ_ORDERL2) { var msg = Helper.MyJsonSafeToObj <Models.MktOrderItem>(resp.Data); if (msg != null) { //if (msg.At == 0) // Debug.WriteLine($"[NOTE] {msg.Sym} orderl2 begin..."); //else if(msg.At==1) // Debug.WriteLine($"[NOTE] {msg.Sym} orderl2 end."); onMktOrderItem?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == K_SUBJ_ORDER20) { var msg = Helper.MyJsonSafeToObj <Models.MktOrder20Result>(resp.Data); if (msg != null) { onMktOrder20Result?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == K_SUBJ_TICK) { var msg = Helper.MyJsonSafeToObj <Models.MktInstrumentTick>(resp.Data); if (msg != null) { onMktInstrumentTick?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == K_SUBJ_INDEX) { var msg = Helper.MyJsonSafeToObj <Models.MktCompositeIndexTick>(resp.Data); if (msg != null) { onMktCompositeIndexTick?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == K_SUBJ_KLINE) { var msg = Helper.MyJsonSafeToObj <Models.MktKLineItem>(resp.Data); if (msg != null) { onMktKLineItem?.Invoke(msg); } else { Debug.WriteLine("[WARN] invalid resp << " + rspTxt); } } else if (resp.Subj == K_SUBJ_NOTIF) { // 系统广播消息 // TODO Debug.WriteLine("[NOTE] ignore notify msg << " + rspTxt); } else { Debug.WriteLine("[WANR]: unknown subj: " + rspTxt); } } else { Debug.WriteLine("[ERROR] invalid msg from market-ws-server: " + rspTxt); } } }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); }