aboutsummaryrefslogtreecommitdiffstats
path: root/hubzilla-versions.rb
blob: 203aa57ff7e4c0abbc3561780b3febf4176b3a35 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/env ruby

# SPDX-FileCopyrightText: 2022 Harald Eilertsen <haraldei@anduin.net>
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# A small program to query the-federation.info about the known Hubzilla
# instances and output a simple overview of which versions are actively in use.
#
# Usage:
#
#   ./hubzilla-versions.rb [<json-data-file>]
#
# With no arguments it fetches the information directly from
# the-federation.info.
#
# If you already have a downloaded json file with the proper fields available,
# you can supply the file name as the only argument, and it will use that
# instead of fetching it from the remote server. Mostly useful during
# development/testing to not overload the remote server.
#
# Requirements:
#
#   - A standard installation of the Ruby programming language.
#     (tested on Ruby version 3.0.3, but should afaict work on any
#     recent ruby.)
#
# License:
#
# This program is licensed under the GNU Affero General Public License version
# 3.0 (or at your option a later version), which means you are free to use,
# study, share and improve the program as you will. See
# LICENSES/AGPL-3.0-or-later.txt for the details.
#

require 'erb'
require 'json'
require 'net/http'
require 'time'
require 'uri'

query = <<~ENDQ
  {
    nodes( platform: "hubzilla" ) {
      host,
      version,
      updated,
      lastSuccess
    }
  }
ENDQ

graphql_uri = URI('https://the-federation.info/graphql')
graphql_uri.query = "query=#{ERB::Util::url_encode(query)}";

if ARGV.empty?
  puts "Fetching results..."
  result = JSON.parse(
    Net::HTTP::get(graphql_uri, { 'Accept' => 'application/json' }))
else
  puts "Reading #{ARGV[0]}..."
  result = JSON.parse(IO.read(ARGV[0]))
end

# Ignore any nodes we haven't seen in half a year
cutoff = Time.now - (3600 * 24 * 30)

nodes = result['data']['nodes']
  .select { |node| Time::xmlschema(node['lastSuccess']) > cutoff }

histogram = nodes.reduce(Hash.new) do |versions, node|
  v = node['version']
  versions[v] = 0 unless versions.has_key?(v)
  versions[v] += 1
  versions
end

total = histogram.values.sum

sorted_keys = histogram.keys.sort do |a,b|
  v1 = a.split('.').map { |n| n.to_i }
  v2 = b.split('.').map { |n| n.to_i }
  v2 <=> v1
end

sorted_keys.each do |k|
  puts "%-5s: %3d (%5.2f%%)" % [k, histogram[k], (histogram[k].to_f/total.to_f) * 100]
end

puts "----------"
puts "total: %3d" % [total]