Skip to content
This repository has been archived by the owner on May 18, 2021. It is now read-only.

Commit

Permalink
Update notification model.
Browse files Browse the repository at this point in the history
Fix: user streams parameter is not applied.
  • Loading branch information
karno committed Mar 20, 2018
1 parent d8712b2 commit b3ef0c0
Show file tree
Hide file tree
Showing 18 changed files with 381 additions and 184 deletions.
24 changes: 20 additions & 4 deletions StarryEyes.Feather/Proxies/INotificationProxy.cs
Expand Up @@ -115,11 +115,27 @@ public interface INotificationProxy
/// The user retweeted the tweet.
/// </summary>
/// <param name="source">source user</param>
/// <param name="original">original tweet</param>
/// <param name="retweet">retweeted tweet</param>
/// <param name="retweetedRetweet">notificaion is raised by retweeted_retweet</param>
/// <param name="status">retweeted tweet</param>
/// <returns>return true to trap notification</returns>
bool NotifyRetweeted(TwitterUser source, TwitterStatus original, TwitterStatus retweet, bool retweetedRetweet);
bool NotifyRetweeted(TwitterUser source, TwitterStatus status);

/// <summary>
/// Someone favorited retweeted status.
/// </summary>
/// <param name="source">source user</param>
/// <param name="target">target user</param>
/// <param name="status">target status</param>
/// <returns></returns>
bool NotifyRetweetFavorited(TwitterUser source, TwitterUser target, TwitterStatus status);

/// <summary>
/// Someone retweeted retweeted status.
/// </summary>
/// <param name="source">source user</param>
/// <param name="target">target user</param>
/// <param name="status">target status</param>
/// <returns></returns>
bool NotifyRetweetRetweeted(TwitterUser source, TwitterUser target, TwitterStatus status);

/// <summary>
/// The user quoted the tweet.
Expand Down
17 changes: 14 additions & 3 deletions StarryEyes/Models/Backstages/TwitterEvents/FavoritedEvent.cs
Expand Up @@ -6,14 +6,25 @@ namespace StarryEyes.Models.Backstages.TwitterEvents
{
public sealed class FavoritedEvent : TwitterEventBase
{
public FavoritedEvent(TwitterUser source, TwitterStatus target)
: base(source, target.User, target)
private readonly bool _notifyRetweet;

public FavoritedEvent(TwitterUser source, TwitterStatus status)
: base(source, status.User, status)
{
_notifyRetweet = false;
}

public FavoritedEvent(TwitterUser source, TwitterUser target, TwitterStatus status)
: base(source, target, status)
{
_notifyRetweet = true;
}

public override string Title => "";

public override string Detail => Source.ScreenName + ": " + TargetStatus;
public override string Detail => _notifyRetweet
? Source.ScreenName + ": RT " + TargetUser.ScreenName + ": " + TargetStatus
: Source.ScreenName + ": " + TargetStatus;

public override Color Background => MetroColors.Amber;
}
Expand Down
6 changes: 3 additions & 3 deletions StarryEyes/Models/Backstages/TwitterEvents/QuotedEvent.cs
Expand Up @@ -7,10 +7,10 @@ namespace StarryEyes.Models.Backstages.TwitterEvents
{
public sealed class QuotedEvent : TwitterEventBase
{
public QuotedEvent(TwitterUser source, TwitterStatus target)
: base(source, target.QuotedStatus?.User, target)
public QuotedEvent(TwitterUser source, TwitterStatus status)
: base(source, status.QuotedStatus?.User, status)
{
if (target.QuotedStatus == null)
if (status.QuotedStatus == null)
{
throw new ArgumentException("specified status has not quote information.");
}
Expand Down
17 changes: 14 additions & 3 deletions StarryEyes/Models/Backstages/TwitterEvents/RetweetedEvent.cs
Expand Up @@ -5,14 +5,25 @@ namespace StarryEyes.Models.Backstages.TwitterEvents
{
public sealed class RetweetedEvent : TwitterEventBase
{
public RetweetedEvent(TwitterUser source, TwitterStatus target)
: base(source, target.User, target)
private readonly bool _notifyRetweet;

public RetweetedEvent(TwitterUser source, TwitterStatus status)
: base(source, status.User, status)
{
_notifyRetweet = false;
}

public RetweetedEvent(TwitterUser source, TwitterUser target, TwitterStatus status)
: base(source, target, status)
{
_notifyRetweet = true;
}

public override string Title => "RT";

public override string Detail => Source.ScreenName + ": " + TargetStatus;
public override string Detail => _notifyRetweet
? Source.ScreenName + ": RT " + TargetUser.ScreenName + ": " + TargetStatus
: Source.ScreenName + ": " + TargetStatus;

public override System.Windows.Media.Color Background => MetroColors.Emerald;
}
Expand Down
Expand Up @@ -15,6 +15,8 @@ public abstract class TwitterEventBase : BackstageEventBase

public TwitterUser TargetUser { get; }

public TwitterStatus OriginalStatus { get; }

public TwitterStatus TargetStatus { get; }

public bool IsLocalUserInvolved => Setting.Accounts.Ids.Contains(Source.Id) ||
Expand All @@ -27,10 +29,11 @@ public TwitterEventBase(TwitterUser source, TwitterUser target)
TargetUser = target;
}

public TwitterEventBase(TwitterUser source, TwitterUser target, TwitterStatus targetStatus)
public TwitterEventBase(TwitterUser source, TwitterUser target, TwitterStatus status)
: this(source, target)
{
TargetStatus = targetStatus;
OriginalStatus = status;
TargetStatus = status.RetweetedStatus ?? status;
}

public override Color Background => MetroColors.Cyan;
Expand Down
Expand Up @@ -5,8 +5,8 @@ namespace StarryEyes.Models.Backstages.TwitterEvents
{
public sealed class UnfavoritedEvent : TwitterEventBase
{
public UnfavoritedEvent(TwitterUser user, TwitterStatus target)
: base(user, target.User, target)
public UnfavoritedEvent(TwitterUser user, TwitterStatus status)
: base(user, status.User, status)
{
}

Expand Down
167 changes: 91 additions & 76 deletions StarryEyes/Models/Receiving/Managers/UserReceiveManager.cs
Expand Up @@ -229,83 +229,12 @@ public bool IsUserStreamsEnabled

if (value)
{
var handler = StreamHandler.Create(StatusInbox.Enqueue, BackstageModel.NotifyException,
_ => StateChanged?.Invoke(_account));
handler.RegisterHandler<StreamStatusEvent>(se =>
var handler = CreateHandler();
_userStreamsReceiver = new UserStreamReceiver(_streamAccessor, handler)
{
switch (se.Event)
{
case StatusEvents.Unknown:
BackstageModel.RegisterEvent(new UnknownEvent(se.Source, se.RawEvent));
break;
case StatusEvents.Favorite:
case StatusEvents.FavoriteRetweet:
NotificationService.NotifyFavorited(se.Source, se.TargetObject);
break;
case StatusEvents.Unfavorite:
NotificationService.NotifyUnfavorited(se.Source, se.TargetObject);
break;
case StatusEvents.RetweetRetweet:
if (se.TargetObject.RetweetedStatus != null)
{
NotificationService.NotifyRetweeted(se.Source,
se.TargetObject.RetweetedStatus, se.TargetObject, true);
}
break;
case StatusEvents.Quote:
if (se.TargetObject.QuotedStatus != null)
{
NotificationService.NotifyQuoted(se.Source,
se.TargetObject.QuotedStatus, se.TargetObject);
}
break;
default:
throw new ArgumentOutOfRangeException();
}
});
handler.RegisterHandler<StreamUserEvent>(ue =>
{
switch (ue.Event)
{
case UserEvents.Unknown:
BackstageModel.RegisterEvent(new UnknownEvent(ue.Source, ue.RawEvent));
break;
case UserEvents.Follow:
NotificationService.NotifyFollowed(ue.Source, ue.Target);
break;
case UserEvents.Unfollow:
NotificationService.NotifyUnfollowed(ue.Source, ue.Target);
break;
case UserEvents.Block:
NotificationService.NotifyBlocked(ue.Source, ue.Target);
break;
case UserEvents.Unblock:
NotificationService.NotifyUnblocked(ue.Source, ue.Target);
break;
case UserEvents.Mute:
NotificationService.NotifyMuted(ue.Source, ue.Target);
break;
case UserEvents.UnMute:
NotificationService.NotifyUnmuted(ue.Source, ue.Target);
break;
case UserEvents.UserUpdate:
NotificationService.NotifyUserUpdated(ue.Source);
break;
case UserEvents.UserDelete:
case UserEvents.UserSuspend:
// do nothing
break;
default:
throw new ArgumentOutOfRangeException();
}
});
handler.RegisterHandler<StreamDelete>(de => NotificationService.NotifyDeleted(de.Id, null));
handler.RegisterHandler<StreamLimit>(
le => NotificationService.NotifyLimitationInfoGot(_account, (int)le.UndeliveredCount));

// list handler is not used.

_userStreamsReceiver = new UserStreamReceiver(_streamAccessor, handler);
RepliesAll = _account.ReceiveRepliesAll,
IncludeFollowingsActivities = _account.ReceiveFollowingsActivity
};
ReceiveManager.ReceiveEngine.RegisterReceiver(_userStreamsReceiver);
}
else
Expand All @@ -317,6 +246,92 @@ public bool IsUserStreamsEnabled
}
}

private StreamHandler CreateHandler()
{
var handler = StreamHandler.Create(StatusInbox.Enqueue, BackstageModel.NotifyException,
_ => StateChanged?.Invoke(_account));
handler.RegisterHandler<StreamStatusEvent>(se =>
{
switch (se.Event)
{
case StatusEvents.Unknown:
BackstageModel.RegisterEvent(new UnknownEvent(se.Source, se.RawEvent));
break;
case StatusEvents.Favorite:
NotificationService.NotifyFavorited(se.Source, se.TargetObject);
break;
case StatusEvents.FavoriteRetweet:
if (se.TargetObject.RetweetedStatus != null)
{
NotificationService.NotifyRetweetFavorited(se.Source, se.Target,
se.TargetObject);
}
break;
case StatusEvents.Unfavorite:
NotificationService.NotifyUnfavorited(se.Source, se.TargetObject);
break;
case StatusEvents.RetweetRetweet:
if (se.TargetObject.RetweetedStatus != null)
{
NotificationService.NotifyRetweetRetweeted(se.Source, se.Target,
se.TargetObject);
}
break;
case StatusEvents.Quote:
if (se.TargetObject.QuotedStatus != null)
{
NotificationService.NotifyQuoted(se.Source,
se.TargetObject.QuotedStatus, se.TargetObject);
}
break;
default:
throw new ArgumentOutOfRangeException();
}
});
handler.RegisterHandler<StreamUserEvent>(ue =>
{
switch (ue.Event)
{
case UserEvents.Unknown:
BackstageModel.RegisterEvent(new UnknownEvent(ue.Source, ue.RawEvent));
break;
case UserEvents.Follow:
NotificationService.NotifyFollowed(ue.Source, ue.Target);
break;
case UserEvents.Unfollow:
NotificationService.NotifyUnfollowed(ue.Source, ue.Target);
break;
case UserEvents.Block:
NotificationService.NotifyBlocked(ue.Source, ue.Target);
break;
case UserEvents.Unblock:
NotificationService.NotifyUnblocked(ue.Source, ue.Target);
break;
case UserEvents.Mute:
NotificationService.NotifyMuted(ue.Source, ue.Target);
break;
case UserEvents.UnMute:
NotificationService.NotifyUnmuted(ue.Source, ue.Target);
break;
case UserEvents.UserUpdate:
NotificationService.NotifyUserUpdated(ue.Source);
break;
case UserEvents.UserDelete:
case UserEvents.UserSuspend:
// do nothing
break;
default:
throw new ArgumentOutOfRangeException();
}
});
handler.RegisterHandler<StreamDelete>(de => NotificationService.NotifyDeleted(de.Id, null));
handler.RegisterHandler<StreamLimit>(
le => NotificationService.NotifyLimitationInfoGot(_account, (int)le.UndeliveredCount));

// list handler is not used.
return handler;
}

public UserStreamsConnectionState ConnectionState => _userStreamsReceiver == null
? UserStreamsConnectionState.Disconnected
: (UserStreamsConnectionState)(int)_userStreamsReceiver.CurrentState;
Expand Down
53 changes: 47 additions & 6 deletions StarryEyes/Models/Subsystems/NotificationService.cs
Expand Up @@ -60,7 +60,7 @@ internal static void NotifyReceived(TwitterStatus status)
{
if (status.RetweetedStatus != null)
{
NotifyRetweeted(status.User, status.RetweetedStatus, status, false);
NotifyRetweeted(status.User, status.RetweetedStatus);
}
if (status.QuotedStatus != null)
{
Expand Down Expand Up @@ -242,16 +242,57 @@ internal static void NotifyUnfavorited(TwitterUser source, TwitterStatus status)
Head.NotifyUnfavorited(source, status);
}

internal static void NotifyRetweeted(TwitterUser source, TwitterStatus original, TwitterStatus retweet,
bool retweetedRetweet)
internal static void NotifyRetweeted(TwitterUser source, TwitterStatus status)
{
if (MuteBlockManager.IsBlocked(source) || MuteBlockManager.IsOfficialMuted(source)) return;
if (!Setting.NotifyBackfilledTweets.Value &&
retweet.CreatedAt < App.StartupDateTime)
if (!Setting.NotifyBackfilledTweets.Value && status.CreatedAt < App.StartupDateTime)
{
// backfilled tweets
return;
}
var original = status.RetweetedStatus;
if (original == null) return;
Task.Run(() => UserProxy.StoreUser(source));
Task.Run(() => StatusModel.UpdateStatusInfo(
original.Id,
model => model.AddRetweetedUser(source), _ =>
{
StatusProxy.AddRetweeter(original.Id, source.Id);
StatusBroadcaster.Republish(original);
}));
Head.NotifyRetweeted(source, status);
}

internal static void NotifyRetweetFavorited(TwitterUser source, TwitterUser target, TwitterStatus status)
{
if (MuteBlockManager.IsBlocked(source) || MuteBlockManager.IsOfficialMuted(source)) return;
if (!NotificationLatch.CheckSetPositive(NotificationLatchTarget.Favorite, source.Id, status.Id))
{
return;
}
var original = status.RetweetedStatus;
if (original == null) return;
Task.Run(() => UserProxy.StoreUser(source));
Task.Run(() => StatusModel.UpdateStatusInfo(
original.Id,
model => model.AddFavoritedUser(source), _ =>
{
StatusProxy.AddFavoritor(original.Id, source.Id);
StatusBroadcaster.Republish(original);
}));
Head.NotifyRetweetFavorited(source, target, status);
}

internal static void NotifyRetweetRetweeted(TwitterUser source, TwitterUser target, TwitterStatus status)
{
if (MuteBlockManager.IsBlocked(source) || MuteBlockManager.IsOfficialMuted(source)) return;
if (!Setting.NotifyBackfilledTweets.Value && status.CreatedAt < App.StartupDateTime)
{
// backfilled tweets
return;
}
var original = status.RetweetedStatus;
if (original == null) return;
Task.Run(() => UserProxy.StoreUser(source));
Task.Run(() => StatusModel.UpdateStatusInfo(
original.Id,
Expand All @@ -260,7 +301,7 @@ internal static void NotifyUnfavorited(TwitterUser source, TwitterStatus status)
StatusProxy.AddRetweeter(original.Id, source.Id);
StatusBroadcaster.Republish(original);
}));
Head.NotifyRetweeted(source, original, retweet, retweetedRetweet);
Head.NotifyRetweetRetweeted(source, target, status);
}

internal static void NotifyQuoted(TwitterUser source, TwitterStatus original, TwitterStatus quote)
Expand Down

0 comments on commit b3ef0c0

Please sign in to comment.