You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.5 KiB

  1. # frozen_string_literal: true
  2. class ActivityPub::Activity
  3. include JsonLdHelper
  4. def initialize(json, account, **options)
  5. @json = json
  6. @account = account
  7. @object = @json['object']
  8. @options = options
  9. end
  10. def perform
  11. raise NotImplementedError
  12. end
  13. class << self
  14. def factory(json, account, **options)
  15. @json = json
  16. klass&.new(json, account, options)
  17. end
  18. private
  19. def klass
  20. case @json['type']
  21. when 'Create'
  22. ActivityPub::Activity::Create
  23. when 'Announce'
  24. ActivityPub::Activity::Announce
  25. when 'Delete'
  26. ActivityPub::Activity::Delete
  27. when 'Follow'
  28. ActivityPub::Activity::Follow
  29. when 'Like'
  30. ActivityPub::Activity::Like
  31. when 'Block'
  32. ActivityPub::Activity::Block
  33. when 'Update'
  34. ActivityPub::Activity::Update
  35. when 'Undo'
  36. ActivityPub::Activity::Undo
  37. when 'Accept'
  38. ActivityPub::Activity::Accept
  39. when 'Reject'
  40. ActivityPub::Activity::Reject
  41. when 'Flag'
  42. ActivityPub::Activity::Flag
  43. when 'Add'
  44. ActivityPub::Activity::Add
  45. when 'Remove'
  46. ActivityPub::Activity::Remove
  47. when 'Move'
  48. ActivityPub::Activity::Move
  49. end
  50. end
  51. end
  52. protected
  53. def status_from_uri(uri)
  54. ActivityPub::TagManager.instance.uri_to_resource(uri, Status)
  55. end
  56. def account_from_uri(uri)
  57. ActivityPub::TagManager.instance.uri_to_resource(uri, Account)
  58. end
  59. def object_uri
  60. @object_uri ||= value_or_id(@object)
  61. end
  62. def redis
  63. Redis.current
  64. end
  65. def distribute(status)
  66. crawl_links(status)
  67. notify_about_reblog(status) if reblog_of_local_account?(status)
  68. notify_about_mentions(status)
  69. # Only continue if the status is supposed to have arrived in real-time.
  70. # Note that if @options[:override_timestamps] isn't set, the status
  71. # may have a lower snowflake id than other existing statuses, potentially
  72. # "hiding" it from paginated API calls
  73. return unless @options[:override_timestamps] || status.within_realtime_window?
  74. distribute_to_followers(status)
  75. end
  76. def reblog_of_local_account?(status)
  77. status.reblog? && status.reblog.account.local?
  78. end
  79. def notify_about_reblog(status)
  80. NotifyService.new.call(status.reblog.account, status)
  81. end
  82. def notify_about_mentions(status)
  83. status.active_mentions.includes(:account).each do |mention|
  84. next unless mention.account.local? && audience_includes?(mention.account)
  85. NotifyService.new.call(mention.account, mention)
  86. end
  87. end
  88. def crawl_links(status)
  89. return if status.spoiler_text?
  90. # Spread out crawling randomly to avoid DDoSing the link
  91. LinkCrawlWorker.perform_in(rand(1..59).seconds, status.id)
  92. end
  93. def distribute_to_followers(status)
  94. ::DistributionWorker.perform_async(status.id)
  95. end
  96. def delete_arrived_first?(uri)
  97. redis.exists("delete_upon_arrival:#{@account.id}:#{uri}")
  98. end
  99. def delete_later!(uri)
  100. redis.setex("delete_upon_arrival:#{@account.id}:#{uri}", 6.hours.seconds, uri)
  101. end
  102. def fetch_remote_original_status
  103. if object_uri.start_with?('http')
  104. return if ActivityPub::TagManager.instance.local_uri?(object_uri)
  105. ActivityPub::FetchRemoteStatusService.new.call(object_uri, id: true, on_behalf_of: @account.followers.local.first)
  106. elsif @object['url'].present?
  107. ::FetchRemoteStatusService.new.call(@object['url'])
  108. end
  109. end
  110. def lock_or_return(key, expire_after = 7.days.seconds)
  111. yield if redis.set(key, true, nx: true, ex: expire_after)
  112. ensure
  113. redis.del(key)
  114. end
  115. end