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]
|