Created
March 30, 2024 18:16
-
-
Save lucianghinda/3e70725ed2a2f8d2f183985efd3788a8 to your computer and use it in GitHub Desktop.
Mastodon Client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Mastodon | |
ApiResponse = Data.define(:body, :headers, :code, :links) | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Mastodon | |
class Client | |
class UnauthenticatedError < StandardError; end | |
class InvalidPostError < StandardError; end | |
class InvalidResponseBodyError < StandardError; end | |
LINK_HEADER_KEY = "Link" | |
def initialize(access_token = ENV.fetch("MASTODON_ACCESS_TOKEN")) | |
@api_url = Instance.new(ENV.fetch("MASTODON_INSTANCE")).api_url | |
@access_token = access_token | |
end | |
def bookmarks(id_type: nil, id: nil) | |
query_params = if id_type.nil? | |
{} | |
else | |
{ id_type => id } | |
end | |
get("/bookmarks", query_params:) | |
end | |
def post(id:) = get("/statuses/#{id}") | |
def embed(url:) = get("/api/oembed", query_params: { url: }) | |
private | |
attr_reader :api_url, :access_token | |
def get(path, query_params: {}) = request(:get, path:, query_params:) | |
def request(method, path:, query_params: {}) | |
url = api_url.dup | |
url.path += path | |
url.query = query_params.to_query unless query_params.empty? | |
request = Typhoeus::Request.new(url.to_s, method:, headers:) | |
begin | |
response = request.run | |
if response.code == 401 | |
Rails.logger.error("Unauthenticated: #{response.body}") | |
raise UnauthenticatedError | |
end | |
if response.code == 400 | |
Rails.logger.error("Invalid post: #{response.body}") | |
raise InvalidPostError | |
end | |
api_response(code: response.code, response_body: response.body, headers: response.headers) | |
rescue StandardError => e | |
Rails.logger.error("An error has occurred: #{e.message}") | |
Rails.logger.error(e.backtrace.join("\n")) | |
::ImportErrorLogger.error("Mastodon::Error importing #{path}", e) | |
end | |
end | |
def headers | |
{ | |
"Authorization": "Bearer #{access_token}", | |
"User-Agent": "ShortRubyClient" | |
} | |
end | |
def api_response(code:, response_body:, headers:) | |
body = JSON.parse(response_body, symbolize_names: true) | |
links = parse_links(headers) | |
Mastodon::ApiResponse.new( | |
body:, | |
code:, | |
headers:, | |
links: | |
) | |
rescue JSON::ParserError => e | |
Rails.logger.error("Invalid response body: #{response_body}, with headers: #{headers}. Error #{e.message}") | |
raise InvalidResponseBodyError | |
end | |
def parse_links(headers) | |
links = headers[LINK_HEADER_KEY] | |
return [] if links.nil? | |
links.split(",").map do |link| | |
Mastodon::PaginationLink.parse(link) | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Mastodon | |
NextLink = Data.define(:id_type, :id) | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Mastodon | |
class PaginationLink | |
attr_reader :url, :rel, :next_link | |
# @param url [URI] | |
# @param rel [String] | |
def initialize(url:, rel:) | |
@url = URI.parse(url.to_s) | |
@rel = rel | |
@next_link = parse_next_link | |
end | |
class << self | |
def parse(link_header) | |
link_header.strip! | |
url, rel_part = link_header.split(";") | |
new(url: extract_link(url), rel: extract_rel(rel_part)) | |
end | |
def extract_link(url) = URI.extract(url)&.first | |
def extract_rel(rel_part) = clean_quotes_from_rel(rel_part.split("=").last) | |
def clean_quotes_from_rel(rel) = rel.delete("\"") | |
end | |
private | |
def parse_next_link | |
query_params = Rack::Utils.parse_query(url.query) | |
Mastodon::NextLink.new( | |
id_type: query_params.keys.first, | |
id: query_params.values.first | |
) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment