internal static void Log(int id, string message, Exception exception = null) { if (exception == null) { LogOutput?.Invoke(null, message); } else { ExceptionHappened?.Invoke(null, exception, message); } }
private async Task <bool> ConnectAsync() { if (this.IsDanmakuConnected) { return(true); } try { var(token, host, port) = await this.bililiveAPI.GetDanmuConf(this.RoomId); LogOutput?.Invoke(this, $"连接弹幕服务器 {host}:{port} {(string.IsNullOrWhiteSpace(token) ? "无" : "有")} token"); this.dmClient = this.funcTcpClient(); await this.dmClient.ConnectAsync(host, port).ConfigureAwait(false); this.dmNetStream = this.dmClient.GetStream(); this.dmReceiveMessageLoopThread = new Thread(this.ReceiveMessageLoop) { Name = "ReceiveMessageLoop " + this.RoomId, IsBackground = true }; this.dmReceiveMessageLoopThread.Start(); var hello = JsonConvert.SerializeObject(new { uid = 0, roomid = this.RoomId, protover = 2, platform = "web", clientver = "1.11.0", type = 2, key = token, }, Formatting.None); this.SendSocketData(7, hello); this.SendSocketData(2); return(true); } catch (Exception ex) { this.dmError = ex; ExceptionHappened?.Invoke(this, ex, "连接弹幕服务器错误"); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.IsDanmakuConnected))); return(false); } }
public StreamMonitor(int roomId, Func <TcpClient> funcTcpClient) { this.funcTcpClient = funcTcpClient; this.bililiveAPI = new BililiveAPI(null); this.RoomId = roomId; ReceivedDanmaku += this.Receiver_ReceivedDanmaku; RoomInfoUpdated += this.StreamMonitor_RoomInfoUpdated; this.dmTokenSource = new CancellationTokenSource(); Repeat.Interval(TimeSpan.FromSeconds(30), () => { if (this.dmNetStream != null && this.dmNetStream.CanWrite) { try { this.SendSocketData(2); } catch (Exception) { } } }, this.dmTokenSource.Token); this.httpTimer = new Timer(5 * 1000) { Enabled = false, AutoReset = true, SynchronizingObject = null, Site = null }; this.httpTimer.Elapsed += (sender, e) => { try { this.Check(TriggerType.HttpApi); } catch (Exception ex) { ExceptionHappened?.Invoke(this, ex, "检测开播状态失败"); } }; }
private void ReceiveMessageLoop() { LogOutput?.Invoke(this, "ReceiveMessageLoop Started"); try { var stableBuffer = new byte[16]; var buffer = new byte[4096]; while (this.IsDanmakuConnected) { this.dmNetStream.ReadB(stableBuffer, 0, 16); Parse2Protocol(stableBuffer, out DanmakuProtocol protocol); if (protocol.PacketLength < 16) { throw new NotSupportedException("协议失败: (L:" + protocol.PacketLength + ")"); } var payloadlength = protocol.PacketLength - 16; if (payloadlength == 0) { continue;//没有内容了 } if (buffer.Length < payloadlength) // 不够长再申请 { buffer = new byte[payloadlength]; } this.dmNetStream.ReadB(buffer, 0, payloadlength); if (protocol.Version == 2 && protocol.Action == 5) // 处理deflate消息 { // Skip 0x78 0xDA using (DeflateStream deflate = new DeflateStream(new MemoryStream(buffer, 2, payloadlength - 2), CompressionMode.Decompress)) { while (deflate.Read(stableBuffer, 0, 16) > 0) { Parse2Protocol(stableBuffer, out protocol); payloadlength = protocol.PacketLength - 16; if (payloadlength == 0) { continue; // 没有内容了 } if (buffer.Length < payloadlength) // 不够长再申请 { buffer = new byte[payloadlength]; } deflate.Read(buffer, 0, payloadlength); ProcessDanmaku(protocol.Action, buffer, payloadlength); } } } else { ProcessDanmaku(protocol.Action, buffer, payloadlength); } void ProcessDanmaku(int action, byte[] local_buffer, int length) { switch (action) { case 3: // var viewer = BitConverter.ToUInt32(local_buffer.Take(4).Reverse().ToArray(), 0); //观众人数 break; case 5: //playerCommand var json = Encoding.UTF8.GetString(local_buffer, 0, length); try { ReceivedDanmaku?.Invoke(this, new ReceivedDanmakuArgs() { Danmaku = new DanmakuModel(json) }); } catch (Exception ex) { ExceptionHappened?.Invoke(this, ex, "处理弹幕出错"); } break; default: break; } } } } catch (Exception ex) { this.dmError = ex; // logger.Error(ex); ExceptionHappened?.Invoke(this, ex, "连接断开"); this.dmClient?.Close(); this.dmNetStream = null; if (!(this.dmTokenSource?.IsCancellationRequested ?? true)) { ExceptionHappened?.Invoke(this, ex, "弹幕连接被断开,将尝试重连"); Task.Run(async() => { await Task.Delay(500); await this.ConnectWithRetryAsync(); }); } } finally { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.IsDanmakuConnected))); } }