Skip to content

Repository files navigation

NodeInfo

NodeInfo is a standardized way for Fediverse servers to expose metadata about themselves, including software information, supported protocols, usage statistics, and more.

Ruby gem implemementation of the NodeInfo protocol for the Fediverse, providing both client and server functionality. This gem implements NodeInfo 2.1 as specified in FEP-f1d5.

Features

  • Language agnostic - Works with any Ruby framework or plain scripts
  • Client - Discover and fetch NodeInfo from any Fediverse server
  • Server - Serve your own NodeInfo documents
  • Dynamic Stats - Support for static values or dynamic procs for usage statistics

Installation

Add this line to your application's Gemfile:

gem'node_info'

And then execute:

bundleinstall

Or install it yourself as:

geminstallnode_info

Usage

Client

Fetch NodeInfo from any Fediverse server:

require'node_info'# Create a clientclient=NodeInfo::Client.new# Fetch NodeInfo from a serverinfo=client.fetch'mastodon.social'# Access the informationputsinfo.software.name# => 'mastodon'putsinfo.software.version# => '4.2.0'putsinfo.protocols# => ['activitypub']putsinfo.open_registrations# => true# Access usage statisticsputsinfo.usage.users[:total]# => 1000000putsinfo.usage.users[:activeMonth]# => 50000putsinfo.usage.local_posts# => 5000000

Discovery and Fetching Separately

# Discover the NodeInfo URLurl=client.discover'mastodon.social'# => 'https://mastodon.social/nodeinfo/2.1'# Fetch the NodeInfo documentinfo=client.fetch_documenturl

Client Options

# Custom timeout (default: 10 seconds)client=NodeInfo::Client.newtimeout: 5# Disable redirect following (default: true)client=NodeInfo::Client.newfollow_redirects: false

Server

Serve NodeInfo documents from your application:

require'node_info'# Create a server with configurationserver=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.software_repository='https://github.com/xoengineering/example'config.software_homepage='https://example.com'config.protocols=['activitypub']config.services_inbound=['atom1.0']config.services_outbound=['rss2.0','atom1.0']config.open_registrations=trueconfig.metadata={nodeName: 'An example instance',nodeDescription: 'An example place for exemplar people'}end# Generate the well-known response: /.well-known/nodeinfoserver.well_known_json'https://example.com'# => {# "links": [# {# "rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",# "href": "https://example.com/nodeinfo/2.1"# }# ]# }# Generate the NodeInfo document (/nodeinfo/2.1)server.to_json# => Full NodeInfo 2.1 JSON document

Static Usage Statistics

server=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']# Static valuesconfig.usage_users={total: 100,activeMonth: 50,activeHalfyear: 75}config.usage_local_posts=1000config.usage_local_comments=500end

Dynamic Usage Statistics

For production applications, you’ll want to compute statistics dynamically:

server=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']# Use procs to compute values dynamicallyconfig.usage_users=->{User.count}config.usage_users_active_month=->{User.active_last_month.count}config.usage_users_active_halfyear=->{User.active_last_six_months.count}config.usage_local_posts=->{Post.local.count}config.usage_local_comments=->{Comment.local.count}end# Stats are computed fresh each timeserver.to_json# Calls all the procs to get current values

Alternative Proc Syntax

config.usage_users={total: ->{User.count},activeMonth: ->{User.active_last_month.count},activeHalfyear: ->{User.active_last_six_months.count}}

Framework Integration

Sinatra

require'sinatra'require'node_info'# Configure your server (perhaps in a config file or initializer)NODE_INFO_SERVER=NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']config.base_url='https://example.com'config.usage_users=->{User.count}end# Well-known endpointget'/.well-known/nodeinfo'docontent_type:jsonNODE_INFO_SERVER.well_known_jsonend# NodeInfo document endpointget'/nodeinfo/2.1'docontent_type:jsonNODE_INFO_SERVER.to_jsonend

Rails

# config/routes.rbRails.application.routes.drawdoget'/.well-known/nodeinfo',to: 'node_info#well_known'get'/nodeinfo/2.1',to: 'node_info#show'end# app/controllers/node_info_controller.rbclassNodeInfoController < ApplicationControllerdefwell_knownrenderjson: server.well_known(request.base_url)enddefshowrenderjson: server.to_jsonendprivatedefserver@server ||= NodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version=Rails.application.config.versionconfig.protocols=['activitypub']config.open_registrations=Rails.application.config.open_registrationsconfig.usage_users=->{User.count}config.usage_users_active_month=->{User.active_last_month.count}config.usage_local_posts=->{Post.local.count}endendend

Hanami

# config/routes.rbget'/.well-known/nodeinfo',to: 'node_info.well_known'get'/nodeinfo/2.1',to: 'node_info.show'# app/actions/node_info/well_known.rbmoduleExampleAppmoduleActionsmoduleNodeInfoclassWellKnown < ExampleApp::Actiondefhandlerequest,responseserver=build_serverresponse.format=:jsonresponse.body=server.well_known_jsonrequest.base_urlendprivatedefbuild_serverNodeInfo::Server.newdo |config|
config.software_name='example_app'config.software_version='1.0.0'config.protocols=['activitypub']endendendendendend

Configuration Options

Server Configuration

OptionTypeRequiredDescription
protocolsArrayYesSupported protocols (e.g., ['activitypub'])
software_nameStringYesName of your software
software_versionStringYesVersion of your software
software_repositoryStringNoURL to source code repository
software_homepageStringNoURL to software homepage
services_inboundArrayNoInbound services (e.g., ['atom1.0'])
services_outboundArrayNoOutbound services (e.g., ['rss2.0'])
open_registrationsBooleanNoWhether registrations are open (default: false)
usage_usersHash/ProcNoUser statistics
usage_users_active_monthInteger/ProcNoActive users in last month
usage_users_active_halfyearInteger/ProcNoActive users in last 6 months
usage_local_postsInteger/ProcNoNumber of local posts
usage_local_commentsInteger/ProcNoNumber of local comments
metadataHashNoCustom metadata
base_urlStringNoBase URL for well-known response

Error Handling

The gem defines several error classes:

NodeInfo::Error# Base error classNodeInfo::DiscoveryError# Discovery failedNodeInfo::FetchError# Fetching document failedNodeInfo::ParseError# Parsing document failedNodeInfo::ValidationError# Validation failedNodeInfo::HTTPError# HTTP request failed

Example error handling:

begininfo=client.fetch'example.com'rescueNodeInfo::DiscoveryError=>eputs"Could not discover NodeInfo: #{e.message}"rescueNodeInfo::FetchError=>eputs"Could not fetch NodeInfo: #{e.message}"rescueNodeInfo::ParseError=>eputs"Could not parse NodeInfo: #{e.message}"rescueNodeInfo::Error=>eputs"NodeInfo error: #{e.message}"end

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install.

Running Tests

bundleexecrspec

Running RuboCop

bundleexecrubocop

Running All Checks

bundleexecrake

Contributing

Bug reports and pull requests are welcome on GitHub at the https://github.com/xoengineering/node_info repo.

License

The gem is available as open source under the terms of the MIT License.

References

About

NodeInfo protocol (FEP-f1d5) for the Fediverse client and server Ruby gem

Topics

Resources

Code of conduct

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages