diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2016-03-25 02:13:30 +0100 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2016-03-25 02:13:30 +0100 |
commit | a08e724476f47b85de9bb334eeadaf882a7a23ee (patch) | |
tree | d779668fa289d2b7077c878b19fc6691a57142b7 /app/services | |
parent | 9594f0e858172b9295c5598fcb6ab10506d3046d (diff) |
Fix subscriptions:clear task, refactor feeds, refactor streamable activites
and atom feed generation to some extent, as well as the way mentions are stored
Diffstat (limited to 'app/services')
-rw-r--r-- | app/services/fan_out_on_write_service.rb | 18 | ||||
-rw-r--r-- | app/services/precompute_feed_service.rb | 32 | ||||
-rw-r--r-- | app/services/process_feed_service.rb | 86 | ||||
-rw-r--r-- | app/services/process_mentions_service.rb | 2 |
4 files changed, 61 insertions, 77 deletions
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 62cf2a1fe..4bb3f0a10 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -1,6 +1,4 @@ class FanOutOnWriteService < BaseService - MAX_FEED_SIZE = 800 - # Push a status into home and mentions feeds # @param [Status] status def call(status) @@ -17,13 +15,13 @@ class FanOutOnWriteService < BaseService def deliver_to_followers(status, replied_to_user) status.account.followers.each do |follower| - next if (status.reply? && !(follower.id = replied_to_user.id || follower.following?(replied_to_user))) || !follower.local? + next if !follower.local? || FeedManager.filter_status?(status, follower) push(:home, follower.id, status) end end def deliver_to_mentioned(status) - status.mentioned_accounts.each do |mention| + status.mentions.each do |mention| mentioned_account = mention.account next unless mentioned_account.local? push(:mentions, mentioned_account.id, status) @@ -31,19 +29,15 @@ class FanOutOnWriteService < BaseService end def push(type, receiver_id, status) - redis.zadd(key(type, receiver_id), status.id, status.id) + redis.zadd(FeedManager.key(type, receiver_id), status.id, status.id) trim(type, receiver_id) end def trim(type, receiver_id) - return unless redis.zcard(key(type, receiver_id)) > MAX_FEED_SIZE - - last = redis.zrevrange(key(type, receiver_id), MAX_FEED_SIZE - 1, MAX_FEED_SIZE - 1) - redis.zremrangebyscore(key(type, receiver_id), '-inf', "(#{last.last}") - end + return unless redis.zcard(FeedManager.key(type, receiver_id)) > FeedManager::MAX_ITEMS - def key(type, id) - "feed:#{type}:#{id}" + last = redis.zrevrange(FeedManager.key(type, receiver_id), FeedManager::MAX_ITEMS - 1, FeedManager::MAX_ITEMS - 1) + redis.zremrangebyscore(FeedManager.key(type, receiver_id), '-inf', "(#{last.last}") end def redis diff --git a/app/services/precompute_feed_service.rb b/app/services/precompute_feed_service.rb index 9d3b8d370..de4201a8f 100644 --- a/app/services/precompute_feed_service.rb +++ b/app/services/precompute_feed_service.rb @@ -1,33 +1,21 @@ class PrecomputeFeedService < BaseService - MAX_FEED_SIZE = 800 - - # Fill up a user's home/mentions feed from DB and return it + # Fill up a user's home/mentions feed from DB and return a subset # @param [Symbol] type :home or :mentions # @param [Account] account # @return [Array] - def call(type, account) - statuses = send(type.to_s, account).order('created_at desc').limit(MAX_FEED_SIZE) - statuses.each { |status| push(type, account.id, status) } - statuses - end + def call(type, account, limit) + instant_return = [] - private - - def push(type, receiver_id, status) - redis.zadd(key(type, receiver_id), status.id, status.id) - end + Status.send("as_#{type}_timeline", account).order('created_at desc').limit(FeedManager::MAX_ITEMS).each do |status| + next if type == :home && FeedManager.filter_status?(status, account) + redis.zadd(FeedManager.key(type, receiver_id), status.id, status.id) + instant_return << status unless instant_return.size > limit + end - def home(account) - Status.where(account: [account] + account.following).with_includes.with_counters + instant_return end - def mentions(account) - Status.where(id: Mention.where(account: account).pluck(:status_id)).with_includes.with_counters - end - - def key(type, id) - "feed:#{type}:#{id}" - end + private def redis $redis diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb index 14ef83204..e842031f5 100644 --- a/app/services/process_feed_service.rb +++ b/app/services/process_feed_service.rb @@ -4,65 +4,67 @@ class ProcessFeedService < BaseService # @param [Account] account Account this feed belongs to def call(body, account) xml = Nokogiri::XML(body) + update_remote_profile_service.(xml.at_xpath('/xmlns:feed/xmlns:author'), account) unless xml.at_xpath('/xmlns:feed').nil? + xml.xpath('//xmlns:entry').each { |entry| process_entry(account, entry) } + end - # If we got a full feed, make sure the account's profile is up to date - unless xml.at_xpath('/xmlns:feed').nil? - update_remote_profile_service.(xml.at_xpath('/xmlns:feed/xmlns:author'), account) - end + private - # Process entries - xml.xpath('//xmlns:entry').each do |entry| - next unless [:note, :comment, :activity].include? object_type(entry) + def process_entry(account, entry) + return unless [:note, :comment, :activity].include? object_type(entry) - status = Status.find_by(uri: activity_id(entry)) + status = Status.find_by(uri: activity_id(entry)) - # If we already have a post and the verb is now "delete", we gotta delete it and move on! - if !status.nil? && verb(entry) == :delete - delete_post!(status) - next - end + # If we already have a post and the verb is now "delete", we gotta delete it and move on! + if !status.nil? && verb(entry) == :delete + delete_post!(status) + return + end - next unless status.nil? + return unless status.nil? - status = Status.new(uri: activity_id(entry), url: activity_link(entry), account: account, text: content(entry), created_at: published(entry), updated_at: updated(entry)) + status = Status.new(uri: activity_id(entry), url: activity_link(entry), account: account, text: content(entry), created_at: published(entry), updated_at: updated(entry)) - if verb(entry) == :share - add_reblog!(entry, status) - elsif verb(entry) == :post - if thread_id(entry).nil? - add_post!(entry, status) - else - add_reply!(entry, status) - end + if verb(entry) == :share + add_reblog!(entry, status) + elsif verb(entry) == :post + if thread_id(entry).nil? + add_post!(entry, status) + else + add_reply!(entry, status) end + end - # If we added a status, go through accounts it mentions and create respective relations - unless status.new_record? - entry.xpath('./xmlns:link[@rel="mentioned"]').each do |mention_link| - # Here we have to do a reverse lookup of local accounts by their URL! - # It's not pretty at all! I really wish all these protocols sticked to - # using acct:username@domain only! It would make things so much easier - # and tidier + # If we added a status, go through accounts it mentions and create respective relations + unless status.new_record? + record_remote_mentions(status, entry.xpath('./xmlns:link[@rel="mentioned"]')) + fan_out_on_write_service.(status) + end + end - href = Addressable::URI.parse(mention_link.attribute('href').value) + def record_remote_mentions(status, links) + # Here we have to do a reverse lookup of local accounts by their URL! + # It's not pretty at all! I really wish all these protocols sticked to + # using acct:username@domain only! It would make things so much easier + # and tidier - if href.host == Rails.configuration.x.local_domain - mentioned_account = Account.find_local(href.path.gsub('/users/', '')) + links.each do |mention_link| + href = Addressable::URI.parse(mention_link.attribute('href').value) - unless mentioned_account.nil? - mentioned_account.mentions.where(status: status).first_or_create(status: status) - NotificationMailer.mention(mentioned_account, status).deliver_later - end - end - end + if href.host == Rails.configuration.x.local_domain + # A local user is mentioned + mentioned_account = Account.find_local(href.path.gsub('/users/', '')) - fan_out_on_write_service.(status) + unless mentioned_account.nil? + mentioned_account.mentions.where(status: status).first_or_create(status: status) + NotificationMailer.mention(mentioned_account, status).deliver_later + end + else + # What to do about remote user? end end end - private - def add_post!(_entry, status) status.save! end diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb index d566b65c7..ba9486c1f 100644 --- a/app/services/process_mentions_service.rb +++ b/app/services/process_mentions_service.rb @@ -18,7 +18,7 @@ class ProcessMentionsService < BaseService mentioned_account.mentions.where(status: status).first_or_create(status: status) end - status.mentioned_accounts.each do |mention| + status.mentions.each do |mention| mentioned_account = mention.account if mentioned_account.local? |