2016-11-16 00:56:29 +09:00
# frozen_string_literal: true
2016-09-10 03:04:34 +09:00
require 'singleton'
2016-03-25 10:13:30 +09:00
class FeedManager
2016-09-10 03:04:34 +09:00
include Singleton
2016-03-25 10:13:30 +09:00
MAX_ITEMS = 800
2016-09-10 03:04:34 +09:00
def key ( type , id )
2016-03-25 10:13:30 +09:00
" feed: #{ type } : #{ id } "
end
2016-10-02 22:28:47 +09:00
def filter? ( timeline_type , status , receiver )
if timeline_type == :home
filter_from_home? ( status , receiver )
2016-11-08 07:20:52 +09:00
elsif timeline_type == :mentions
2016-10-02 22:28:47 +09:00
filter_from_mentions? ( status , receiver )
2016-11-10 08:03:33 +09:00
elsif timeline_type == :public
filter_from_public? ( status , receiver )
2016-11-08 07:20:52 +09:00
else
false
2016-10-02 22:28:47 +09:00
end
2016-03-25 10:13:30 +09:00
end
2016-09-11 01:36:48 +09:00
def push ( timeline_type , account , status )
2016-09-30 04:40:37 +09:00
redis . zadd ( key ( timeline_type , account . id ) , status . id , status . reblog? ? status . reblog_of_id : status . id )
2016-09-11 01:36:48 +09:00
trim ( timeline_type , account . id )
2017-02-02 08:03:31 +09:00
broadcast ( account . id , event : 'update' , payload : inline_render ( account , 'api/v1/statuses/show' , status ) )
2016-09-13 01:22:43 +09:00
end
2016-11-05 23:20:05 +09:00
def broadcast ( timeline_id , options = { } )
2017-02-05 11:19:04 +09:00
options [ :queued_at ] = ( Time . now . to_f * 1000 . 0 ) . to_i
2016-11-05 23:20:05 +09:00
ActionCable . server . broadcast ( " timeline: #{ timeline_id } " , options )
2016-09-11 01:36:48 +09:00
end
def trim ( type , account_id )
return unless redis . zcard ( key ( type , account_id ) ) > FeedManager :: MAX_ITEMS
last = redis . zrevrange ( key ( type , account_id ) , FeedManager :: MAX_ITEMS - 1 , FeedManager :: MAX_ITEMS - 1 )
redis . zremrangebyscore ( key ( type , account_id ) , '-inf' , " ( #{ last . last } " )
end
2016-12-23 07:03:57 +09:00
def merge_into_timeline ( from_account , into_account )
timeline_key = key ( :home , into_account . id )
from_account . statuses . limit ( MAX_ITEMS ) . each do | status |
2017-01-24 05:09:27 +09:00
next if filter? ( :home , status , into_account )
2016-12-23 07:03:57 +09:00
redis . zadd ( timeline_key , status . id , status . id )
end
trim ( :home , into_account . id )
end
2017-01-24 05:29:34 +09:00
def unmerge_from_timeline ( from_account , into_account )
timeline_key = key ( :home , into_account . id )
from_account . statuses . select ( 'id' ) . find_each do | status |
redis . zrem ( timeline_key , status . id )
redis . zremrangebyscore ( timeline_key , status . id , status . id )
end
end
2016-11-20 08:33:02 +09:00
def inline_render ( target_account , template , object )
2016-09-11 01:36:48 +09:00
rabl_scope = Class . new do
include RoutingHelper
def initialize ( account )
@account = account
end
def current_user
2016-10-07 23:00:11 +09:00
@account . try ( :user )
2016-09-11 01:36:48 +09:00
end
def current_account
@account
end
end
2016-11-20 08:33:02 +09:00
Rabl :: Renderer . new ( template , object , view_path : 'app/views' , format : :json , scope : rabl_scope . new ( target_account ) ) . render
2016-09-11 01:36:48 +09:00
end
2016-10-07 23:00:11 +09:00
private
def redis
2016-11-16 00:56:29 +09:00
Redis . current
2016-10-07 23:00:11 +09:00
end
def filter_from_home? ( status , receiver )
2016-11-08 07:20:52 +09:00
should_filter = false
2016-12-31 22:35:08 +09:00
if status . reply? && ! status . in_reply_to_account_id . nil? # Filter out if it's a reply
should_filter = ! receiver . following? ( status . in_reply_to_account ) # and I'm not following the person it's a reply to
should_filter && = ! ( receiver . id == status . in_reply_to_account_id ) # and it's not a reply to me
should_filter && = ! ( status . account_id == status . in_reply_to_account_id ) # and it's not a self-reply
elsif status . reblog? # Filter out a reblog
should_filter = receiver . blocking? ( status . reblog . account ) # if I'm blocking the reblogged person
2016-11-08 07:20:52 +09:00
end
2016-12-31 22:35:08 +09:00
should_filter || = receiver . blocking? ( status . mentions . map ( & :account_id ) ) # or if it mentions someone I blocked
2016-11-25 20:35:21 +09:00
2016-11-08 07:20:52 +09:00
should_filter
2016-10-07 23:00:11 +09:00
end
def filter_from_mentions? ( status , receiver )
2016-12-05 00:51:49 +09:00
should_filter = receiver . id == status . account_id # Filter if I'm mentioning myself
should_filter || = receiver . blocking? ( status . account ) # or it's from someone I blocked
2016-11-25 21:13:16 +09:00
should_filter || = receiver . blocking? ( status . mentions . includes ( :account ) . map ( & :account ) ) # or if it mentions someone I blocked
2016-12-05 00:51:49 +09:00
should_filter || = ( status . account . silenced? && ! receiver . following? ( status . account ) ) # of if the account is silenced and I'm not following them
2016-12-23 07:14:24 +09:00
should_filter || = ( status . private_visibility? && ! receiver . following? ( status . account ) ) # or if the mentioned account is not permitted to see the private status
2016-11-14 05:11:45 +09:00
2016-12-31 22:35:08 +09:00
if status . reply? && ! status . in_reply_to_account_id . nil? # or it's a reply
should_filter || = receiver . blocking? ( status . in_reply_to_account ) # to a user I blocked
2016-11-14 05:11:45 +09:00
end
2016-11-08 07:20:52 +09:00
should_filter
2016-10-07 23:00:11 +09:00
end
2016-11-10 08:03:33 +09:00
def filter_from_public? ( status , receiver )
2016-11-25 20:35:21 +09:00
should_filter = receiver . blocking? ( status . account )
2016-11-25 21:13:16 +09:00
should_filter || = receiver . blocking? ( status . mentions . includes ( :account ) . map ( & :account ) )
2016-11-10 08:03:33 +09:00
2016-12-31 22:35:08 +09:00
if status . reply? && ! status . in_reply_to_account_id . nil?
should_filter || = receiver . blocking? ( status . in_reply_to_account )
2016-11-10 08:03:33 +09:00
elsif status . reblog?
2016-11-16 00:56:29 +09:00
should_filter || = receiver . blocking? ( status . reblog . account )
2016-11-10 08:03:33 +09:00
end
should_filter
end
2016-03-25 10:13:30 +09:00
end