/// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public async Task <DisconnectReason> ReceiveAsync(string vid, BrowserType browserType)
        {
            _disconnectReason = DisconnectReason.Unknown;
            string liveChatHtml = await GetLiveChatHtml(vid);

            string ytInitialData;

            try
            {
                ytInitialData = Tools.ExtractYtInitialDataFromLiveChatHtml(liveChatHtml);
            }
            catch (ParseException ex)
            {
                _logger.LogException(ex, "live_chatからのytInitialDataの抜き出しに失敗", liveChatHtml);
                return(DisconnectReason.YtInitialDataNotFound);
            }
            IContinuation      initialContinuation;
            List <CommentData> initialCommentData;

            try
            {
                (initialContinuation, initialCommentData) = Tools.ParseYtInitialData(ytInitialData);
            }
            catch (YouTubeLiveServerErrorException ex)
            {
                _logger.LogException(ex, "サーバエラー", $"ytInitialData={ytInitialData},vid={vid}");
                return(DisconnectReason.ServerError);
            }
            catch (ContinuationNotExistsException)
            {
                //放送終了
                return(DisconnectReason.Finished);
            }
            catch (ChatUnavailableException)
            {
                //SendInfo("この配信ではチャットが無効になっているようです", InfoType.Error);
                return(DisconnectReason.ChatUnavailable);
            }
            catch (Exception ex)
            {
                _logger.LogException(ex, "未知の例外", $"ytInitialData={ytInitialData},vid={vid}");
                return(DisconnectReason.Unknown);
            }

            Connected?.Invoke(this, EventArgs.Empty);

            //直近の過去コメントを送る。
            foreach (var data in initialCommentData)
            {
                if (_receivedCommentIds.Contains(data.Id))
                {
                    continue;
                }
                else
                {
                    _receivedCommentIds.Add(data.Id);
                }
                var messageContext = CreateMessageContext(data, true);
                MessageReceived?.Invoke(this, messageContext);
            }
            //コメント投稿に必要なものの準備
            PrepareForPostingComments(liveChatHtml, ytInitialData);

            var  tasks             = new List <Task>();
            Task activeCounterTask = null;
            IActiveCounter <string> activeCounter = null;

            if (_options.IsActiveCountEnabled)
            {
                activeCounter = new ActiveCounter <string>()
                {
                    CountIntervalSec = _options.ActiveCountIntervalSec,
                    MeasureSpanMin   = _options.ActiveMeasureSpanMin,
                };
                activeCounter.Updated += (s, e) =>
                {
                    MetadataUpdated?.Invoke(this, new Metadata {
                        Active = e.ToString()
                    });
                };
                activeCounterTask = activeCounter.Start();
                tasks.Add(activeCounterTask);
            }

            IMetadataProvider metaProvider = null;
            var metaTask = CreateMetadataReceivingTask(ref metaProvider, browserType, vid, liveChatHtml);

            if (metaTask != null)
            {
                tasks.Add(metaTask);
            }

            _chatProvider = new ChatProvider(_server, _logger);
            _chatProvider.ActionsReceived += (s, e) =>
            {
                foreach (var action in e)
                {
                    if (_receivedCommentIds.Contains(action.Id))
                    {
                        continue;
                    }
                    else
                    {
                        activeCounter?.Add(action.Id);
                        _receivedCommentIds.Add(action.Id);
                    }

                    var messageContext = CreateMessageContext(action, false);
                    MessageReceived?.Invoke(this, messageContext);
                }
            };
            _chatProvider.InfoReceived += (s, e) =>
            {
                SendInfo(e.Comment, e.Type);
            };
            var chatTask = _chatProvider.ReceiveAsync(vid, initialContinuation, _cc);

            tasks.Add(chatTask);

            _disconnectReason = DisconnectReason.Finished;
            while (tasks.Count > 0)
            {
                var t = await Task.WhenAny(tasks);

                if (t == metaTask)
                {
                    try
                    {
                        await metaTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex, "metaTaskが終了した原因");
                    }
                    //metaTask内でParseExceptionもしくはDisconnect()
                    //metaTaskは終わっても良い。
                    tasks.Remove(metaTask);
                    metaProvider = null;
                }
                else if (t == activeCounterTask)
                {
                    try
                    {
                        await activeCounterTask;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex, "activeCounterTaskが終了した原因");
                    }
                    tasks.Remove(activeCounterTask);
                    activeCounter = null;
                }
                else //chatTask
                {
                    tasks.Remove(chatTask);
                    try
                    {
                        await chatTask;
                    }
                    catch (ReloadException ex)
                    {
                        _logger.LogException(ex, "", $"vid={vid}");
                        _disconnectReason = DisconnectReason.Reload;
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException(ex);
                        _disconnectReason = DisconnectReason.Unknown;
                    }
                    _chatProvider = null;

                    //chatTaskが終わったらmetaTaskも終了させる
                    metaProvider?.Disconnect();
                    if (metaTask != null)
                    {
                        try
                        {
                            await metaTask;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogException(ex, "metaTaskが終了した原因");
                        }
                        tasks.Remove(metaTask);
                    }
                    metaProvider = null;

                    activeCounter?.Stop();
                    if (activeCounterTask != null)
                    {
                        try
                        {
                            await activeCounterTask;
                        }
                        catch (Exception ex)
                        {
                            _logger.LogException(ex, "activeCounterTaskが終了した原因");
                        }
                        tasks.Remove(activeCounterTask);
                    }
                    activeCounter = null;
                }
            }
            return(_disconnectReason);
        }
Example #2
0
            bool TrashScreen(Trash trash)
            {
                Element[] trashToPrint = new Element[trash.Length * 3 + 2];
                Book      currBook;
                string    str;

                for (int i = 0; i < trash.Length; ++i)
                {
                    if (trash[i].stored is Book)
                    {
                        currBook                = trash[i].stored as Book;
                        str                     = Validator.ValidStr(currBook.shortTitle, 16) + " | ";
                        str                    += Validator.ValidStr(currBook.autherName, 16) + " | ";
                        str                    += Validator.ValidStr(currBook.price.ToString(), 7);
                        trashToPrint[i * 3]     = new ActiveStaticElement(str, new Coord(5, (short)(i + 5)));
                        trashToPrint[i * 3 + 1] = new ActiveCounter("-----", new Coord(53, (short)(i + 5)), new Coord(1, 0), ref trash[i].cnt, 1, 255, "   ");
                        trashToPrint[i * 3 + 2] = new ActiveStaticElement("X", new Coord(62, (short)(i + 5)));
                    }
                }
                str  = Validator.ValidStr("Title", 16) + " | ";
                str += Validator.ValidStr("Auther name", 16) + " | ";
                str += Validator.ValidStr("Price", 7) + " | ";
                str += Validator.ValidStr("Cnt", 5) + " | ";
                str += Validator.ValidStr("Del", 5);
                trashToPrint[trash.Length * 3] = new StaticElement(str, new Coord(5, 4));
                if (trash.Length != 0)
                {
                    string buyBtn = "_____\n|Buy|\n-----";
                    trashToPrint[trash.Length * 3 + 1] = new ActiveStaticElement(buyBtn, new Coord((short)(str.Length / 2 - buyBtn.Length / 2), (short)(trash.Length + 6)));
                }
                else
                {
                    trashToPrint[trash.Length * 3 + 1] = null;
                }
                byte choose;
                ActiveElementDraw trashWindow = new ActiveElementDraw(head, trashToPrint);
                NextWindow        nextWindow  = null;

                trashWindow.InitStatic();
                while (true)
                {
                    trashWindow.Print();
                    choose = trashWindow.Input(InbisibleInput());
                    if (choose == 255)
                    {
                        continue;
                    }

                    switch (choose)
                    {
                    //Main
                    case 0:
                        goto TRASH_SCREEN_RETURN;

                    //Find
                    case 1:
                        nextWindow = new NextWindow(BooksListByName);
                        goto TRASH_SCREEN_RETURN;

                    //Register/Login    Logout
                    case 2:
                        nextWindow = new NextWindow(ClickOnLoginBtn);
                        goto TRASH_SCREEN_RETURN;

                    default:

                        choose -= 13;
                        if (choose == trash.Length * 3 + 1)
                        {
                            TrashObj[] deliver = shop.Buy();
                            trashWindow.ClearScreen();
                            bool accept = AcceptBeforeDeliver(deliver);
                            trashWindow.InitStatic();
                            if (accept)
                            {
                                if (shop.IsLogOn())
                                {
                                    ;                            //Послать юзеру
                                }
                                else
                                {
                                    ;                            //Открить окно ввода адреса
                                }
                            }
                            else
                            {
                                foreach (var i in deliver)
                                {
                                    if (i.cnt != 0 && i.stored != null)
                                    {
                                        shop.GetClientTrash().Add(i);
                                        for (int j = 0; j < i.cnt; ++j)
                                        {
                                            shop.GetCargo().Add(i.stored);
                                        }
                                    }
                                }
                            }
                            goto TRASH_SCREEN_RETURN;
                        }
                        else if (choose % 3 == 0)
                        {
                            trashWindow.ClearScreen();
                            BookInfoScreen(((Book)trash[choose / 3].stored), false);
                            trashWindow.InitStatic();
                        }
                        else if (choose % 3 == 2)
                        {
                            trash.Delete(((Book)trash[choose / 3].stored));
                            trashWindow.ClearScreen();
                            TrashScreen(trash);
                            goto TRASH_SCREEN_RETURN;
                        }
                        break;
                    }
                }

TRASH_SCREEN_RETURN:
                trashWindow.ClearScreen();
                if (nextWindow != null)
                {
                    nextWindow.Invoke();
                }
                return(true);
            }