/// <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); }
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); }