Skip to content

Instantly share code, notes, and snippets.

@mashiro
Created August 16, 2011 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mashiro/1149370 to your computer and use it in GitHub Desktop.
Save mashiro/1149370 to your computer and use it in GitHub Desktop.
いろいろいじってあって diff とれなかった
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading;
using Misuzilla.Applications.TwitterIrcGateway.AddIns.Console;
using System.Runtime.Serialization.Json;
namespace Misuzilla.Applications.TwitterIrcGateway.AddIns.UserStream
{
public class UserStreamAddIn : AddInBase
{
private HashSet<String> _friendIds;
private Thread _workerThread;
private Boolean _isRunning;
private HttpWebRequest _webRequest;
public UserStreamConfig Config { get; set; }
public override void Initialize()
{
// XXX:
ServicePointManager.DefaultConnectionLimit = 1000;
ServicePointManager.MaxServicePoints = 0;
CurrentSession.AddInsLoadCompleted += (sender, e) =>
{
CurrentSession.AddInManager.GetAddIn<ConsoleAddIn>().RegisterContext<UserStreamContext>();
Config = CurrentSession.AddInManager.GetConfig<UserStreamConfig>();
Setup(Config.Enabled);
};
}
public override void Uninitialize()
{
Setup(false);
}
internal void Setup(Boolean isStart)
{
if (_workerThread != null)
{
_isRunning = false;
if (_webRequest != null)
{
_webRequest.Abort();
_webRequest = null;
}
_workerThread.Abort();
_workerThread.Join(200);
_workerThread = null;
}
if (isStart)
{
_friendIds = new HashSet<String>();
_workerThread = new Thread(WorkerProcedureEntry);
_workerThread.Start();
_isRunning = true;
}
}
private void WorkerProcedureEntry()
{
while (true)
{
try
{
WorkerProcedure();
}
catch (ThreadAbortException)
{
_isRunning = false;
// rethrow
}
catch (Exception e)
{
//CurrentSession.SendServerErrorMessage("UserStream: " + e.ToString());
}
if (!Config.AutoRestart)
break;
// 適当に 60 秒待機
Thread.Sleep(60 * 1000);
}
_isRunning = false;
}
private void WorkerProcedure()
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(_Status));
DataContractJsonSerializer serializer2 = new DataContractJsonSerializer(typeof(_FriendsObject));
DataContractJsonSerializer serializer3 = new DataContractJsonSerializer(typeof(_EventObject));
_webRequest = CurrentSession.TwitterService.OAuthClient.CreateRequest(
new Uri("https://userstream.twitter.com/2/user.json"),
TwitterOAuth.HttpMethod.GET);
_webRequest.ServicePoint.ConnectionLimit = 1000;
_webRequest.Timeout = 30 * 1000;
using (var response = _webRequest.GetResponse())
using (var stream = response.GetResponseStream())
{
StreamReader sr = new StreamReader(stream, Encoding.UTF8);
Boolean isFirstLine = true;
while (!sr.EndOfStream && _isRunning)
{
var line = sr.ReadLine();
if (String.IsNullOrEmpty(line))
continue;
_Status statusJson = null;
try
{
// XXX: これはてぬき
if (isFirstLine)
{
isFirstLine = false;
_FriendsObject streamObject =
serializer2.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(line))) as
_FriendsObject;
if (streamObject != null && streamObject.Friends != null)
{
_friendIds.UnionWith(streamObject.Friends);
}
}
else if (line.IndexOf("\"event\":") > -1)
{
_EventObject eventObj =
serializer3.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(line))) as _EventObject;
if (eventObj.Event == "follow" && Int64.Parse(eventObj.Source.Id) == CurrentSession.TwitterUser.Id)
_friendIds.Add(eventObj.Target.Id);
}
else
{
statusJson =
serializer.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(line))) as _Status;
}
}
catch
{
//CurrentSession.SendServerErrorMessage("UserStream(Deserialize): " + line);
continue;
}
if (statusJson == null || statusJson.Id == 0)
continue;
if (Config.IsThroughMyPostFromUserStream && (Int64.Parse(statusJson.User.Id) == CurrentSession.TwitterUser.Id))
continue;
Status status = statusJson.ToStatus();
Boolean friendCheckRequired = false;
if (Config.AllAtMode ||
(String.IsNullOrEmpty(statusJson.InReplyToUserId)) ||
(String.IsNullOrEmpty(statusJson.InReplyToUserId) && _friendIds.Contains(statusJson.InReplyToUserId)))
{
CurrentSession.TwitterService.ProcessStatus(status,
(s) => CurrentSession.ProcessTimelineStatus(s, ref friendCheckRequired, false, false));
}
}
}
}
}
[Description("User Stream設定コンテキストに切り替えます")]
public class UserStreamContext : Context
{
public override IConfiguration[] Configurations
{
get
{
return new[] { CurrentSession.AddInManager.GetAddIn<UserStreamAddIn>().Config };
}
}
[Description("User Stream を有効にします")]
public void Enable()
{
var config = CurrentSession.AddInManager.GetConfig<UserStreamConfig>();
config.Enabled = true;
CurrentSession.AddInManager.SaveConfig(config);
CurrentSession.AddInManager.GetAddIn<UserStreamAddIn>().Setup(config.Enabled);
Console.NotifyMessage("User Stream を有効にしました。");
}
[Description("User Stream を無効にします")]
public void Disable()
{
var config = CurrentSession.AddInManager.GetConfig<UserStreamConfig>();
config.Enabled = false;
CurrentSession.AddInManager.SaveConfig(config);
CurrentSession.AddInManager.GetAddIn<UserStreamAddIn>().Setup(config.Enabled);
Console.NotifyMessage("User Stream を無効にしました。");
}
protected override void OnConfigurationChanged(IConfiguration config, MemberInfo memberInfo, object value)
{
CurrentSession.AddInManager.SaveConfig(config);
}
}
public class UserStreamConfig : IConfiguration
{
[Browsable(false)]
public Boolean Enabled { get; set; }
[Description("all@と同じ挙動になるかどうかを指定します。")]
public Boolean AllAtMode { get; set; }
[Description("自分のポストをUser Streamから拾わないようにするかどうかを指定します。")]
public Boolean IsThroughMyPostFromUserStream { get; set; }
[Description("切断された際に自動的に再接続を試みるかどうかを指定します。")]
public Boolean AutoRestart { get; set; }
}
[DataContract]
class _Status
{
[DataMember(Name = "id")]
public Int64 Id { get; set; }
[DataMember(Name = "text")]
public String Text { get; set; }
[DataMember(Name = "created_at")]
public String _created_at { get; set; }
public DateTime CreatedAt { get { return DateTime.ParseExact(_created_at, "ddd MMM dd HH:mm:ss zz00 yyyy", CultureInfo.InvariantCulture.DateTimeFormat); } }
[DataMember(Name = "source")]
public String Source { get; set; }
[DataMember(Name = "truncated")]
public Boolean Truncated { get; set; }
[DataMember(Name = "favorited")]
public String Favorited { get; set; }
[DataMember(Name = "in_reply_to_status_id")]
public String InReplyToStatusId { get; set; }
[DataMember(Name = "in_reply_to_user_id")]
public String InReplyToUserId { get; set; }
[DataMember(Name = "retweeted_status")]
public _Status RetweetedStatus { get; set; }
[DataMember(Name = "user")]
public _User User { get; set; }
public Status ToStatus()
{
return new Status()
{
Id = this.Id,
_textOriginal = this.Text,
CreatedAt = this.CreatedAt,
Source = this.Source,
Truncated = this.Truncated,
Favorited = this.Favorited,
InReplyToStatusId = this.InReplyToStatusId,
InReplyToUserId = this.InReplyToUserId,
RetweetedStatus = (this.RetweetedStatus == null) ? null : this.RetweetedStatus.ToStatus(),
User = this.User.ToUser()
};
}
}
[DataContract]
class _EventTarget
{
[DataMember(Name = "id")]
public String Id { get; set; }
}
[DataContract]
class _User
{
[DataMember(Name = "id")]
public String Id { get; set; }
[DataMember(Name = "screen_name")]
public String ScreenName { get; set; }
[DataMember(Name = "name")]
public String Name { get; set; }
[DataMember(Name = "description")]
public String Description { get; set; }
[DataMember(Name = "location")]
public String Location { get; set; }
[DataMember(Name = "profile_image_url")]
public String ProfileImageUrl { get; set; }
[DataMember(Name = "url")]
public String Url { get; set; }
[DataMember(Name = "protected")]
public Boolean Protected { get; set; }
public User ToUser()
{
return new User()
{
Id = Int32.Parse(this.Id),
ScreenName = this.ScreenName,
Name = this.Name,
Description = this.Description,
Location = this.Location,
ProfileImageUrl = this.ProfileImageUrl,
Url = this.Url,
Protected = this.Protected,
};
}
}
[DataContract]
class _FriendsObject
{
[DataMember(Name = "friends")]
public List<String> Friends { get; set; }
}
[DataContract]
class _EventObject
{
[DataMember(Name = "event")]
public String Event { get; set; }
[DataMember(Name = "target")]
public _EventTarget Target { get; set; }
[DataMember(Name = "source")]
public _EventTarget Source { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment