private void userStream_StatusArrived(string line)
{
this._lastUserstreamDataReceived = DateTime.Now;
if (string.IsNullOrEmpty(line)) return;
if (line.First() != '{' || line.Last() != '}')
{
MyCommon.TraceOut("Invalid JSON (StatusArrived):" + Environment.NewLine + line);
return;
}
var isDm = false;
try
{
using (var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(line), XmlDictionaryReaderQuotas.Max))
{
var xElm = XElement.Load(jsonReader);
if (xElm.Element("friends") != null)
{
Debug.WriteLine("friends");
return;
}
else if (xElm.Element("delete") != null)
{
Debug.WriteLine("delete");
Int64 id;
XElement idElm;
if ((idElm = xElm.Element("delete").Element("direct_message")?.Element("id")) != null)
{
id = 0;
long.TryParse(idElm.Value, out id);
this.PostDeleted?.Invoke(this, new PostDeletedEventArgs(id));
}
else if ((idElm = xElm.Element("delete").Element("status")?.Element("id")) != null)
{
id = 0;
long.TryParse(idElm.Value, out id);
this.PostDeleted?.Invoke(this, new PostDeletedEventArgs(id));
}
else
{
MyCommon.TraceOut("delete:" + line);
return;
}
for (int i = this.StoredEvent.Count - 1; i >= 0; i--)
{
var sEvt = this.StoredEvent[i];
if (sEvt.Id == id && (sEvt.Event == "favorite" || sEvt.Event == "unfavorite"))
{
this.StoredEvent.RemoveAt(i);
}
}
return;
}
else if (xElm.Element("limit") != null)
{
Debug.WriteLine(line);
return;
}
else if (xElm.Element("event") != null)
{
Debug.WriteLine("event: " + xElm.Element("event").Value);
CreateEventFromJson(line);
return;
}
else if (xElm.Element("direct_message") != null)
{
Debug.WriteLine("direct_message");
isDm = true;
}
else if (xElm.Element("retweeted_status") != null)
{
var sourceUserId = xElm.XPathSelectElement("/user/id_str").Value;
var targetUserId = xElm.XPathSelectElement("/retweeted_status/user/id_str").Value;
// 自分に関係しないリツイートの場合は無視する
var selfUserId = this.UserId.ToString();
if (sourceUserId == selfUserId || targetUserId == selfUserId)
{
// 公式 RT をイベントとしても扱う
var evt = CreateEventFromRetweet(xElm);
if (evt != null)
{
this.StoredEvent.Insert(0, evt);
this.UserStreamEventReceived?.Invoke(this, new UserStreamEventReceivedEventArgs(evt));
}
}
// 従来通り公式 RT の表示も行うため return しない
}
else if (xElm.Element("scrub_geo") != null)
{
try
{
TabInformations.GetInstance().ScrubGeoReserve(long.Parse(xElm.Element("scrub_geo").Element("user_id").Value),
long.Parse(xElm.Element("scrub_geo").Element("up_to_status_id").Value));
}
catch(Exception)
{
MyCommon.TraceOut("scrub_geo:" + line);
}
return;
}
}
if (isDm)
{
try
{
var message = TwitterStreamEventDirectMessage.ParseJson(line).DirectMessage;
this.CreateDirectMessagesFromJson(new[] { message }, MyCommon.WORKERTYPE.UserStream, false);
}
catch (SerializationException ex)
{
throw TwitterApiException.CreateFromException(ex, line);
}
}
else
{
try
{
var status = TwitterStatusCompat.ParseJson(line);
this.CreatePostsFromJson(new[] { status.Normalize() }, MyCommon.WORKERTYPE.UserStream, null, false);
}
catch (SerializationException ex)
{
throw TwitterApiException.CreateFromException(ex, line);
}
}
}
catch (WebApiException ex)
{
MyCommon.TraceOut(ex);
return;
}
catch(NullReferenceException)
{
MyCommon.TraceOut("NullRef StatusArrived: " + line);
}
this.NewPostFromStream?.Invoke(this, EventArgs.Empty);
}