Ejemplo n.º 1
0
        protected override IEnumerable <Chat> GetOnceASecond(ChannelInfo channel, DateTime time)
        {
            List <Chat> ret = new List <Chat>();

            int jkId = jkIdResolver.Resolve(channel.NetworkId, channel.ServiceId);

            if (jkId == 0)
            {
                //対応するjkidがなかった
                lastJkId = 0;
                return(ret);
            }

            if (lastJkId == jkId && baseTime != 0)
            {
                lock (chats)
                {
                    //再生時刻のchatをretに入れる
                    int vpos = (int)(new DateTimeOffset(time).ToUnixTimeSeconds() - baseTime) * 100;//time.KindはLocalじゃないとダメよ

                    foreach (var chat in chats.Where(chat => vpos <= chat.Vpos && chat.Vpos < vpos + 100).Select(chat => chat.Chat))
                    {
                        ret.Add(chat);
                    }
                    chats.RemoveAll(chat => chat.Vpos < vpos + 100);
                }
            }

            //10秒に一回かチャンネルが変わったら取得
            if ((time - lastGetTime).Duration().TotalSeconds < 10 && lastJkId == jkId)
            {
                return(ret);//取得しないなら帰る
            }
            //取得処理
            if (chatCollectTask != null && !chatCollectTask.IsCompleted)
            {
                return(ret);//まだ前回の取得が終わってないなら帰る(普通は終わってるはず)
            }
            try
            {
                chatCollectTask?.Wait();
            }
            catch (AggregateException e) when(e.InnerException is ServerErrorException)
            {
                throw new ChatCollectException("コメントサーバーからエラーが返されました。", e);
            }
            catch (AggregateException e) when(e.InnerException is HttpRequestException)
            {
                throw new ChatCollectException("コメントサーバーとの通信でエラーが発生しました。このエラーはサーバー混雑時にも起こり得ます。", e);
            }

            //シークとかしてなければ前回取得分以降のコメ取得、そうでなければ250個分取得
            int resFrom;

            lock (chats)
            {
                if (chats.Count > 0 && (time - lastGetTime).Duration().TotalSeconds < 15 && lastJkId == jkId)
                {
                    resFrom = chats[chats.Count - 1].Chat.Number + 1;
                }
                else
                {
                    resFrom = -250;
                    chats.Clear();
                }
            }

            chatCollectTask = collectChat(jkId, time.AddSeconds(1), time.AddSeconds(15), resFrom);

            lastJkId    = jkId;
            lastGetTime = time;

            return(ret);
        }
        public IEnumerable <Chat> GetChats(ChannelInfo channel, DateTime time)
        {
            if (chatCollectTask != null && chatCollectTask.IsFaulted)
            {
                //非同期部分で例外発生
                throw new ChatCollectException($"ニコニコ実況でエラーが発生しました: {chatCollectTask.Exception.ToString()}", chatCollectTask.Exception);
            }

            int jkId = jkIdResolver.Resolve(channel.NetworkId, channel.ServiceId);

            if (jkId == 0)
            {
                lastJkId = 0;
                return(new Chat[0]);
            }

            //非同期部分で集めたデータからチャットを生成
            var ret = new List <Chat>();

            lock (parser)
            {
                while (parser.DataAvailable())
                {
                    var tag           = parser.Pop();
                    var chatTag       = tag as NiconicoUtils.ChatNiconicoCommentXmlTag;
                    var threadTag     = tag as NiconicoUtils.ThreadNiconicoCommentXmlTag;
                    var chatResultTag = tag as NiconicoUtils.ChatResultNiconicoCommentXmlTag;
                    if (chatTag != null)
                    {
                        var chat = NiconicoUtils.ChatNiconicoCommentXmlTagToChat.Convert(chatTag);
                        ret.Add(chat);
                        lastResNum = chat.Number;
                    }
                    else if (threadTag != null)
                    {
                        lastThreadTag = threadTag;
                    }
                    else if (chatResultTag != null)
                    {
                        postingResult?.TrySetResult(chatResultTag.Status);
                    }
                }
            }

            if (lastJkId == jkId)
            {
                return(ret);
            }

            //選択番組に変更があった場合
            lastJkId = jkId;
            lock (parser)
                parser.Reset();
            try
            {
                cancel?.Cancel();
                try
                {
                    chatCollectTask?.Wait();
                }
                //Waitからの例外が、タスクがキャンセルされたことによるものなら無視
                catch (AggregateException e) when(e.InnerExceptions.All(innerE => innerE is OperationCanceledException))
                {
                }
                cancel          = new CancellationTokenSource();
                chatCollectTask = collectChat(jkId, cancel.Token);
            }
            catch (ChatReceivingException e)
            {
                throw new ChatCollectException($"ニコニコ実況でエラーが発生しました: {e.ToString()}", e);
            }
            return(ret);
        }