diaspora/lib/node_info.rb
Benjamin Neff 01f8f55dbb
Add parsing of newer versions of NodeInfo
Always take the newest versions both nodes support
2022-07-23 16:59:41 +02:00

203 lines
5 KiB
Ruby

# frozen_string_literal: true
require "pathname"
require "json-schema"
module NodeInfo
VERSIONS = %w[1.0 2.0 2.1].freeze
SCHEMAS = {} # rubocop:disable Style/MutableConstant
private_constant :SCHEMAS
Document = Struct.new(:version, :software, :protocols, :services, :open_registrations, :usage, :metadata) do
# rubocop:disable Lint/ConstantDefinitionInBlock
Software = Struct.new(:name, :version, :repository, :homepage) do
def initialize(name=nil, version=nil)
super(name, version)
end
def version_10_hash
{
"name" => name,
"version" => version
}
end
def version_21_hash
version_10_hash.merge(
"repository" => repository,
"homepage" => homepage
)
end
end
Protocols = Struct.new(:protocols) do
def initialize(protocols=[])
super(protocols)
end
def version_10_hash
{
"inbound" => protocols,
"outbound" => protocols
}
end
def version_20_array
protocols
end
end
Services = Struct.new(:inbound, :outbound) do
def initialize(inbound=[], outbound=[])
super(inbound, outbound)
end
def version_10_hash
{
"inbound" => inbound,
"outbound" => outbound
}
end
end
Usage = Struct.new(:users, :local_posts, :local_comments) do
Users = Struct.new(:total, :active_halfyear, :active_month) do
def initialize(total=nil, active_halfyear=nil, active_month=nil)
super(total, active_halfyear, active_month)
end
def version_10_hash
{
"total" => total,
"activeHalfyear" => active_halfyear,
"activeMonth" => active_month
}
end
end
def initialize(local_posts=nil, local_comments=nil)
super(Users.new, local_posts, local_comments)
end
def version_10_hash
{
"users" => users.version_10_hash,
"localPosts" => local_posts,
"localComments" => local_comments
}
end
end
# rubocop:enable Lint/ConstantDefinitionInBlock
def self.build
new.tap do |doc|
yield doc
doc.validate
end
end
def initialize(version=nil, open_registrations=nil, metadata={})
super(version, Software.new, Protocols.new, Services.new, open_registrations, Usage.new, metadata)
end
def as_json(_options={})
case version
when "1.0"
version_10_hash
when "2.0"
version_20_hash
when "2.1"
version_21_hash
end
end
def content_type
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/#{version}#"
end
def schema
NodeInfo.schema version
end
def validate
assert NodeInfo.supported_version?(version), "Unknown version #{version}"
JSON::Validator.validate!(schema, as_json)
end
private
def assert(condition, message)
raise ArgumentError, message unless condition
end
def version_10_hash
deep_compact(
"version" => "1.0",
"software" => software.version_10_hash,
"protocols" => protocols.version_10_hash,
"services" => services.version_10_hash,
"openRegistrations" => open_registrations,
"usage" => usage.version_10_hash,
"metadata" => metadata
)
end
def version_20_hash
deep_compact(
"version" => "2.0",
"software" => software.version_10_hash,
"protocols" => protocols.version_20_array,
"services" => services.version_10_hash,
"openRegistrations" => open_registrations,
"usage" => usage.version_10_hash,
"metadata" => metadata
)
end
def version_21_hash
deep_compact(
"version" => "2.1",
"software" => software.version_21_hash,
"protocols" => protocols.version_20_array,
"services" => services.version_10_hash,
"openRegistrations" => open_registrations,
"usage" => usage.version_10_hash,
"metadata" => metadata
)
end
def deep_compact(hash)
hash.tap do |hash|
hash.reject! {|_, value|
deep_compact value if value.is_a? Hash
value.nil?
}
end
end
end
def self.schema(version)
SCHEMAS[version] ||= JSON.parse(
Pathname.new(__dir__).join("..", "vendor", "nodeinfo", "schemas", "#{version}.json").expand_path.read
)
end
def self.build(&block)
Document.build(&block)
end
def self.jrd(endpoint)
{
"links" => VERSIONS.map {|version|
{
"rel" => "http://nodeinfo.diaspora.software/ns/schema/#{version}",
"href" => endpoint % {version: version}
}
}
}
end
def self.supported_version?(version)
VERSIONS.include? version
end
end