Merge pull request #347 from kmycode/kb-draft-5.12-lts
Release: 5.12 LTS
This commit is contained in:
commit
e227885d0b
11 changed files with 82 additions and 63 deletions
|
@ -180,6 +180,16 @@ module CacheConcern
|
|||
def render_with_cache(**options)
|
||||
raise ArgumentError, 'Only JSON render calls are supported' unless options.key?(:json) || block_given?
|
||||
|
||||
if options.delete(:cancel_cache)
|
||||
if block_given?
|
||||
options[:json] = yield
|
||||
elsif options[:json].is_a?(Symbol)
|
||||
options[:json] = send(options[:json])
|
||||
end
|
||||
|
||||
return render(options)
|
||||
end
|
||||
|
||||
key = options.delete(:key) || [[params[:controller], params[:action]].join('/'), options[:json].respond_to?(:cache_key) ? options[:json].cache_key : nil, options[:fields].nil? ? nil : options[:fields].join(',')].compact.join(':')
|
||||
expires_in = options.delete(:expires_in) || 3.minutes
|
||||
body = Rails.cache.read(key, raw: true)
|
||||
|
|
|
@ -30,15 +30,15 @@ class StatusesController < ApplicationController
|
|||
end
|
||||
|
||||
format.json do
|
||||
expires_in 3.minutes, public: true if @status.distributable? && public_fetch_mode?
|
||||
render_with_cache json: @status, content_type: 'application/activity+json', serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter
|
||||
expires_in 3.minutes, public: true if @status.distributable? && public_fetch_mode? && !misskey_software?
|
||||
render_with_cache json: @status, content_type: 'application/activity+json', serializer: status_activity_serializer, adapter: ActivityPub::Adapter, cancel_cache: misskey_software?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def activity
|
||||
expires_in 3.minutes, public: @status.distributable? && public_fetch_mode?
|
||||
render_with_cache json: ActivityPub::ActivityPresenter.from_status(@status), content_type: 'application/activity+json', serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter
|
||||
expires_in 3.minutes, public: @status.distributable? && public_fetch_mode? && !misskey_software?
|
||||
render_with_cache json: ActivityPub::ActivityPresenter.from_status(@status, for_misskey: misskey_software?), content_type: 'application/activity+json', serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter, cancel_cache: misskey_software?
|
||||
end
|
||||
|
||||
def embed
|
||||
|
@ -76,6 +76,29 @@ class StatusesController < ApplicationController
|
|||
@instance_presenter = InstancePresenter.new
|
||||
end
|
||||
|
||||
def misskey_software?
|
||||
return @misskey_software if defined?(@misskey_software)
|
||||
|
||||
@misskey_software = false
|
||||
|
||||
return false if !@status.local? || signed_request_account&.domain.blank?
|
||||
|
||||
info = InstanceInfo.find_by(domain: signed_request_account.domain)
|
||||
return false if info.nil?
|
||||
|
||||
@misskey_software = %w(misskey calckey cherrypick sharkey).include?(info.software) &&
|
||||
((@status.public_unlisted_visibility? && @status.account.user&.setting_reject_public_unlisted_subscription) ||
|
||||
(@status.unlisted_visibility? && @status.account.user&.setting_reject_unlisted_subscription))
|
||||
end
|
||||
|
||||
def status_activity_serializer
|
||||
if misskey_software?
|
||||
ActivityPub::NoteForMisskeySerializer
|
||||
else
|
||||
ActivityPub::NoteSerializer
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_to_original
|
||||
redirect_to(ActivityPub::TagManager.instance.url_for(@status.reblog), allow_other_host: true) if @status.reblog?
|
||||
end
|
||||
|
|
|
@ -46,7 +46,6 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
end
|
||||
|
||||
create_account
|
||||
fetch_instance_info
|
||||
end
|
||||
|
||||
update_account
|
||||
|
@ -66,6 +65,8 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
check_links! if @account.fields.any?(&:requires_verification?)
|
||||
end
|
||||
|
||||
fetch_instance_info
|
||||
|
||||
@account
|
||||
rescue Oj::ParseError
|
||||
nil
|
||||
|
@ -211,7 +212,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
end
|
||||
|
||||
def fetch_instance_info
|
||||
ActivityPub::FetchInstanceInfoWorker.perform_async(@account.domain) unless InstanceInfo.exists?(domain: @account.domain)
|
||||
ActivityPub::FetchInstanceInfoWorker.perform_async(@account.domain) unless Rails.cache.exist?("fetch_instance_info:#{@account.domain}", expires_in: 1.day)
|
||||
end
|
||||
|
||||
def actor_type
|
||||
|
|
|
@ -8,28 +8,32 @@ class ActivityPub::FetchInstanceInfoWorker
|
|||
|
||||
sidekiq_options queue: 'push', retry: 2
|
||||
|
||||
class Error < StandardError; end
|
||||
class RequestError < Error; end
|
||||
class DeadError < Error; end
|
||||
|
||||
SUPPORTED_NOTEINFO_RELS = ['http://nodeinfo.diaspora.software/ns/schema/2.0', 'http://nodeinfo.diaspora.software/ns/schema/2.1'].freeze
|
||||
|
||||
def perform(domain)
|
||||
@instance = Instance.find_by(domain: domain)
|
||||
return if !@instance || @instance.unavailable_domain.present?
|
||||
|
||||
with_redis_lock("instance_info:#{domain}") do
|
||||
link = nodeinfo_link
|
||||
return if link.nil?
|
||||
|
||||
update_info!(link)
|
||||
Rails.cache.fetch("fetch_instance_info:#{@instance.domain}", expires_in: 1.day, race_condition_ttl: 1.hour) do
|
||||
fetch!
|
||||
end
|
||||
rescue ActivityPub::FetchInstanceInfoWorker::DeadError
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch!
|
||||
link = nodeinfo_link
|
||||
return if link.nil?
|
||||
|
||||
update_info!(link)
|
||||
|
||||
true
|
||||
rescue Mastodon::UnexpectedResponseError
|
||||
true
|
||||
end
|
||||
|
||||
def nodeinfo_link
|
||||
nodeinfo = fetch_json("https://#{@instance.domain}/.well-known/nodeinfo")
|
||||
return nil if nodeinfo.nil? || !nodeinfo.key?('links')
|
||||
|
@ -63,15 +67,9 @@ class ActivityPub::FetchInstanceInfoWorker
|
|||
|
||||
def fetch_json(url)
|
||||
build_request(url).perform do |response|
|
||||
if [200, 203].include?(response.code)
|
||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
||||
|
||||
body_to_json(response.body_with_limit)
|
||||
elsif [400, 401, 403, 404, 410].include?(response.code)
|
||||
raise ActivityPub::FetchInstanceInfoWorker::DeadError, "Request for #{@instance.domain} returned HTTP #{response.code}"
|
||||
else
|
||||
raise ActivityPub::FetchInstanceInfoWorker::RequestError, "Request for #{@instance.domain} returned HTTP #{response.code}"
|
||||
end
|
||||
body_to_json(response.body_with_limit)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Scheduler::UpdateInstanceInfoScheduler
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options retry: 0, lock: :until_executed, lock_ttl: 1.day.to_i
|
||||
|
||||
def perform
|
||||
Instance.select(:domain).reorder(nil).find_in_batches do |instances|
|
||||
ActivityPub::FetchInstanceInfoWorker.push_bulk(instances) do |instance|
|
||||
[instance.domain]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -62,10 +62,6 @@
|
|||
interval: 30 seconds
|
||||
class: Scheduler::SidekiqHealthScheduler
|
||||
queue: scheduler
|
||||
update_instance_info_scheduler:
|
||||
cron: '0 0 * * *'
|
||||
class: Scheduler::UpdateInstanceInfoScheduler
|
||||
queue: scheduler
|
||||
software_update_check_scheduler:
|
||||
interval: 30 minutes
|
||||
class: Scheduler::SoftwareUpdateCheckScheduler
|
||||
|
|
|
@ -9,7 +9,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def kmyblue_minor
|
||||
11
|
||||
12
|
||||
end
|
||||
|
||||
def kmyblue_flag
|
||||
|
|
|
@ -55,6 +55,7 @@ RSpec.describe ActivityPub::Activity::Update do
|
|||
stub_request(:get, actor_json[:following]).to_return(status: 404)
|
||||
stub_request(:get, actor_json[:featured]).to_return(status: 404)
|
||||
stub_request(:get, actor_json[:featuredTags]).to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/.well-known/nodeinfo').to_return(status: 404)
|
||||
|
||||
subject.perform
|
||||
end
|
||||
|
|
|
@ -5,6 +5,10 @@ require 'rails_helper'
|
|||
RSpec.describe ActivityPub::ProcessAccountService, type: :service do
|
||||
subject { described_class.new }
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/.well-known/nodeinfo').to_return(status: 404)
|
||||
end
|
||||
|
||||
context 'with searchability' do
|
||||
subject { described_class.new.call('alice', 'example.com', payload) }
|
||||
|
||||
|
|
|
@ -67,9 +67,22 @@ describe ActivityPub::FetchInstanceInfoWorker do
|
|||
Instance.refresh
|
||||
end
|
||||
|
||||
it 'does not update immediately' do
|
||||
stub_request(:get, 'https://example.com/nodeinfo/2.0').to_return(status: 200, body: nodeinfo_json)
|
||||
subject.perform('example.com')
|
||||
stub_request(:get, 'https://example.com/nodeinfo/2.0').to_return(status: 200, body: new_nodeinfo_json)
|
||||
subject.perform('example.com')
|
||||
|
||||
info = InstanceInfo.find_by(domain: 'example.com')
|
||||
expect(info).to_not be_nil
|
||||
expect(info.software).to eq 'mastodon'
|
||||
expect(info.version).to eq '4.2.0-beta1'
|
||||
end
|
||||
|
||||
it 'performs a mastodon instance' do
|
||||
stub_request(:get, 'https://example.com/nodeinfo/2.0').to_return(status: 200, body: nodeinfo_json)
|
||||
subject.perform('example.com')
|
||||
Rails.cache.delete('fetch_instance_info:example.com')
|
||||
stub_request(:get, 'https://example.com/nodeinfo/2.0').to_return(status: 200, body: new_nodeinfo_json)
|
||||
subject.perform('example.com')
|
||||
|
||||
|
@ -93,5 +106,12 @@ describe ActivityPub::FetchInstanceInfoWorker do
|
|||
info = InstanceInfo.find_by(domain: 'example.com')
|
||||
expect(info).to be_nil
|
||||
end
|
||||
|
||||
it 'does not fetch again immediately' do
|
||||
expect(subject.perform('example.com')).to be true
|
||||
expect(subject.perform('example.com')).to be true
|
||||
|
||||
expect(a_request(:get, 'https://example.com/.well-known/nodeinfo')).to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Scheduler::UpdateInstanceInfoScheduler do
|
||||
let(:worker) { described_class.new }
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/.well-known/nodeinfo').to_return(status: 200, body: '{}')
|
||||
Fabricate(:account, domain: 'example.com')
|
||||
Instance.refresh
|
||||
end
|
||||
|
||||
describe 'perform' do
|
||||
it 'runs without error' do
|
||||
expect { worker.perform }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue