Created
August 16, 2011 15:33
-
-
Save mashiro/1149370 to your computer and use it in GitHub Desktop.
いろいろいじってあって diff とれなかった
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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