/// <summary> /// コメント送信時に呼ばれます。 /// </summary> internal void OnCommentSentRoom(CommentRoom sender, PostComment comment) { this.CommentSent.SafeRaiseEvent( this, new CommentRoomSentEventArgs( sender.Index, sender.RoomLabel, comment)); // 未送信のコメント数が変わった可能性があります。 this.RaisePropertyChanged("LeaveCommentCount"); }
/// <summary> /// 放送主コメントを送信します。 /// </summary> public void SendOwnerComment(string text, string mail) { var comment = new PostComment() { Text = text, Mail = mail, StartDate = DateTime.Now, }; SendOwnerComment(comment); }
/// <summary> /// メッセージキューからメッセージを一つ削除します。 /// </summary> private void RemoveMessage(PostComment comment) { using (new DebugLock(SyncRoot)) { if (!this.postCommentList.Any()) { return; } this.postCommentList.Remove(comment); } }
/// <summary> /// コメント投稿用の文字列を作成します。 /// </summary> private XElement BuildCommentString(PostComment comment) { var postkey = GetPostKey(); if (string.IsNullOrEmpty(postkey)) { Log.Error(this, "postkeyの取得に失敗しました。"); ClearMessage(); AddPostMessageWait(TimeSpan.FromSeconds(5.0)); return(null); } var playerStatus = this.commentClient.PlayerStatus; // 前回と同じ内容のコメントは投稿できないので、必要に応じて // 0幅文字を追加しています。 // // 0幅文字についてはここを参考にしました。 // http://nicowiki.com/空白・特殊記号.html var text = comment.Text + ((this.lastPostText != null && this.lastPostText == comment.Text) ? "\u200E" : ""); // エラー時は同じ内容のコメントを何度も投稿することがあり、 // 同じコメントの連続投稿規則にひっかっかってしまう可能性があるため、 // 投稿内容をエラー回数によって少し変えています。 text += new string('\u200C', this.postTryCount); // vposには放送開始からの経過時間を10ms単位で設定します。 var elapse = DateTime.Now - playerStatus.Stream.BaseTime; // 投稿するメッセージを作成します。 var elem = new XElement("chat", new XAttribute("thread", this.ThreadId), new XAttribute("ticket", this.ticket), new XAttribute("vpos", (int)elapse.TotalMilliseconds / 10), new XAttribute("postkey", postkey), new XAttribute("user_id", playerStatus.User.UserId), new XAttribute("mail", comment.Mail), new XAttribute("premium", (playerStatus.User.IsPremium ? "1" : "0")), new XAttribute("locale", "jp"), text); return(elem); }
/// <summary> /// メッセージをメッセージキューに追加します。 /// </summary> private void EnqueueOwnerComment(PostComment comment) { if (comment == null) { return; } lock (this.ownerCommentList) { this.ownerCommentList.Add(comment); // 投稿可能時刻が早い順にソートします。 // List.Sortは安定なソートでないためこうしています。 this.ownerCommentList = this.ownerCommentList.OrderBy( cm => cm.StartDate).ToList(); } }
/// <summary> /// メッセージをメッセージキューに追加します。 /// </summary> private void AddMessage(PostComment comment) { if (comment == null) { return; } using (new DebugLock(SyncRoot)) { this.postCommentList.Add(comment); // 投稿可能時刻が早い順にソートします。 // List.Sortは安定なソートでないためこうしています。 this.postCommentList = this.postCommentList.OrderBy( cm => cm.StartDate).ToList(); } }
/// <summary> /// コメント投稿成功時に送られます。 /// </summary> private void OnSendCommentSuccess() { var tmpComment = this.sendingComment; using (new DebugLock(SyncRoot)) { // 送信したメッセージをキューから削除します。 RemoveMessage(this.sendingComment); this.postTryCount = 0; this.sendingComment = null; } // メッセージを削除した後に、イベントを呼びます。 // LeaveCommentCountの数を調整するためです。 this.commentClient.OnCommentSentRoom( this, tmpComment); }
/// <summary> /// コメントを非同期で送信します。 /// </summary> public void SendComment(string text, string mail, DateTime startTime) { if (string.IsNullOrEmpty(text)) { return; } var comment = new PostComment() { Text = text, Mail = mail, StartDate = startTime, }; AddMessage(comment); // 別スレッド上で投稿します。 //UpdateSendComment(); }
/// <summary> /// コメントの投稿が可能かどうか調べます。 /// </summary> private bool CanSendComment(PostComment comment) { using (new DebugLock(SyncRoot)) { var now = DateTime.Now; // 投稿可能時刻に達していない場合は、コメントは投稿できません。 if (now < comment.StartDate) { return(false); } // 前回の投稿から規定時間以上経っていない場合は、エラーとなります。 if (now - this.lastPostTime < this.waitForPostTime) { return(false); } return(true); } }
/// <summary> /// 何らかの理由で接続が切断されたときに呼ばれます。 /// </summary> private void NotifyDisconnected(DisconnectReason reason) { using (new DebugLock(SyncRoot)) { if (this.socket != null) { this.socket.Close(); this.socket = null; } this.isDisconnecting = false; this.sendingComment = null; this.postKey = null; this.postTryCount = 0; this.receivedBuffer.SetLength(0); ClearMessage(); } this.commentClient.OnDisconnectedRoom(this, reason); Log.Debug(this, "コメントルームから切断されました。(理由={0})", reason); }
/// <summary> /// コメント投稿失敗時に呼ばれます。 /// </summary> private void OnSendCommentError(ChatResultStatus?status) { // もう一度投稿してみます。 using (new DebugLock(SyncRoot)) { Log.Error(this, "chat_resultから失敗報告が来ました。(status={0}, Text={1})", (status == null ? "不明" : status.ToString()), (this.sendingComment == null ? "" : this.sendingComment.Text)); // エラーコードによる個別のエラー処理を行います。 switch (status) { case ChatResultStatus.NormalError: // 原因) // ・同じ内容のコメントを投稿した // ・連続アクセスエラー // 対策) // エラーカウントなどを使い次の投稿時にはコメントの内容を // 変えるため、上の理由の場合は特にすることはありません。 // 連続アクセス時も、対応した長期休憩コードが別途あるため、 // 特になにもする必要がありません。 break; case ChatResultStatus.Error2: // 原因) // ・分かりません>< break; case ChatResultStatus.Error3: // 原因) // ・分かりません>< break; case ChatResultStatus.PostKey: // 原因) // ・postkeyの値が不正。 // 対策) // キャッシュされているpostkeyの値を初期化し、 // 次の投稿時には新しいpostkeyを取得するようにしています。 this.postKey = null; break; default: break; } // コメントの投稿に3回以上連続で失敗した場合は、 // アクセス多寡などの理由と判断し長い休憩時間を入れます。 if (this.postTryCount > 2) { AddPostMessageWait(AccessDeniedWaitTime); this.postTryCount = 0; // 送信に失敗したコメントも削除します。 RemoveMessage(this.sendingComment); } else { this.postTryCount += 1; } // 投稿中のコメントをnullにし、新しいコメントを // 投稿出来るようにします。 this.sendingComment = null; } }
/// <summary> /// もしメッセージがあれば、非同期のメッセージ送信処理を行います。 /// </summary> public void UpdateSendComment() { try { XElement elem; byte[] sendData; using (new DebugLock(SyncRoot)) { if (!IsConnected || IsDisconnecting) { //Log.ErrorMessage(this, // "コネクションは切断されています。"); return; } // 投稿用コメントを取得します。 var comment = GetMessage(); if (comment == null || !CanSendComment(comment)) { return; } // コメント送信中でかつ、対応するchat_resultが返って来ていない場合、 // そのコメントは無視します。 if (this.sendingComment != null) { Log.Error(this, "対応するchar_resultが返って来ませんでした(Text = {0})", this.sendingComment.Text); // 次のメッセージを送ってしまいます。 this.sendingComment = null; } elem = BuildCommentString(comment); sendData = Encoding.UTF8.GetBytes(elem.ToString() + "\0"); // コメントの投稿時刻などを設定します。 // エラー処理に必要になります。 this.lastPostText = elem.Value; this.sendingComment = comment; SetPostMessageWait(DateTime.Now, MinimumWaitTimeForPost); } // コメントの投稿処理を開始します。 this.socket.BeginSend( sendData, 0, sendData.Length, SocketFlags.None, SendCommentDone, null); Log.Trace(this, "メッセージの送信処理を開始しました。(Text = {0})", elem.Value); } catch (Exception ex) { Log.ErrorException(this, ex, "メッセージの非同期送信に失敗しました。"); using (new DebugLock(SyncRoot)) { this.sendingComment = null; } } }