Beispiel #1
0
 internal static void Log(int id, string message, Exception exception = null)
 {
     if (exception == null)
     {
         LogOutput?.Invoke(null, message);
     }
     else
     {
         ExceptionHappened?.Invoke(null, exception, message);
     }
 }
Beispiel #2
0
        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);
            }
        }
Beispiel #3
0
        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, "检测开播状态失败");
                }
            };
        }
Beispiel #4
0
        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)));
            }
        }