friends_controller.rb 2.1 KB
Newer Older
Eugen Rochko's avatar
Eugen Rochko committed
1 2
# frozen_string_literal: true

Eugen Rochko's avatar
Eugen Rochko committed
3 4 5 6 7
require 'twitter'

class FriendsController < ApplicationController
  before_action :authenticate_user!

8 9 10 11
  MAX_INSTANCES = 20
  MIN_INSTANCES = 4

  helper_method :default_domains
12

Eugen Rochko's avatar
Eugen Rochko committed
13
  def index
14
    session[:job_id] = FindFriendsWorker.perform_async(current_user.id) unless job_exists?
Eugen Rochko's avatar
Eugen Rochko committed
15 16
  end

Eugen Rochko's avatar
Eugen Rochko committed
17
  def results
18 19 20 21 22
    render json: friends, each_serializer: UserSerializer
  end

  def domains
    render json: friends_domains
Eugen Rochko's avatar
Eugen Rochko committed
23 24
  end

Eugen Rochko's avatar
Eugen Rochko committed
25
  def status
26
    render json: Sidekiq::Status::get_all(job_id)
Eugen Rochko's avatar
Eugen Rochko committed
27 28
  end

Eugen Rochko's avatar
Eugen Rochko committed
29
  private
30

Eugen Rochko's avatar
Eugen Rochko committed
31 32
  def job_id
    session[:job_id]
Eugen Rochko's avatar
Eugen Rochko committed
33 34
  end

35 36 37 38
  def job_exists?
    job_id.present? && Sidekiq::Status::get_all(job_id).key?('status')
  end

Eugen Rochko's avatar
Eugen Rochko committed
39 40
  def friends
    return unless Sidekiq::Status::complete?(job_id)
41

42 43 44 45 46 47 48 49 50 51 52 53 54 55
    data_map = Rails.cache.fetch("#{current_user.id}/friends") { [] }.map { |d| [d.first, d] }.to_h

    return [] if data_map.empty?

    User.where(id: data_map.keys).includes(:mastodon, :twitter).map do |user|
      user.relative_account_id = data_map[user.id][1]
      user.following           = data_map[user.id][2]
      user
    end
  end

  def friends_domains
    data = Rails.cache.fetch("#{current_user.id}/friends")

56
    return default_domains if data.empty?
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

    Authorization.where(provider: 'mastodon', user_id: data.map(&:first))
                 .map(&:uid)
                 .map { |uid| uid.split('@').last }
                 .inject(Hash.new(0)) { |h, k| h[k] += 1; h }
                 .sort_by { |k, v| -v }
                 .take(MAX_INSTANCES)
                 .map { |k, _| fetch_instance_info(k) }
                 .compact
  end

  def default_domains
    %w(
      octodon.social
      mastodon.art
      niu.moe
      todon.nl
      soc.ialis.me
      scifi.fyi
      hostux.social
      mstdn.maud.io
      mastodon.sdf.org
      x0r.be
      toot.cafe
81
    ).sample(MIN_INSTANCES).map { |k| fetch_instance_info(k) }.compact
82 83
  end

84 85 86 87
  def fetch_instance_info(host)
    Rails.cache.fetch("instance:#{host}", expires_in: 1.week) { Oj.load(HTTP.get("https://#{host}/api/v1/instance").to_s, mode: :strict) }
  rescue HTTP::Error, OpenSSL::SSL::SSLError, Oj::ParseError
    nil
88
  end
Eugen Rochko's avatar
Eugen Rochko committed
89
end