]> git.mxchange.org Git - friendica.git/blob - src/Module/Admin/Federation.php
Merge pull request #11213 from annando/platform-cleaning
[friendica.git] / src / Module / Admin / Federation.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Module\Admin;
23
24 use Friendica\Core\Renderer;
25 use Friendica\Database\DBA;
26 use Friendica\DI;
27 use Friendica\Model\GServer;
28 use Friendica\Module\BaseAdmin;
29
30 class Federation extends BaseAdmin
31 {
32         protected function content(array $request = []): string
33         {
34                 parent::content();
35
36                 // get counts on active federation systems this node is knowing
37                 // We list the more common systems by name. The rest is counted as "other"
38                 $systems = [
39                         'friendica'    => ['name' => 'Friendica', 'color' => '#ffc018'], // orange from the logo
40                         'birdsitelive' => ['name' => 'BirdsiteLIVE', 'color' => '#1b6ec2'], // Color from the page
41                         'bookwyrm'     => ['name' => 'BookWyrm', 'color' => '#00d1b2'], // Color from the page
42                         'diaspora'     => ['name' => 'Diaspora', 'color' => '#a1a1a1'], // logo is black and white, makes a gray
43                         'funkwhale'    => ['name' => 'Funkwhale', 'color' => '#4082B4'], // From the homepage
44                         'gnusocial'    => ['name' => 'GNU Social/Statusnet', 'color' => '#a22430'], // dark red from the logo
45                         'hubzilla'     => ['name' => 'Hubzilla/Red Matrix', 'color' => '#43488a'], // blue from the logo
46                         'lemmy'        => ['name' => 'Lemmy', 'color' => '#00c853'], // Green from the page
47                         'mastodon'     => ['name' => 'Mastodon', 'color' => '#1a9df9'], // blue from the Mastodon logo
48                         'misskey'      => ['name' => 'Misskey', 'color' => '#ccfefd'], // Font color of the homepage
49                         'mobilizon'    => ['name' => 'Mobilizon', 'color' => '#ffd599'], // Background color of parts of the homepage
50                         'nextcloud'    => ['name' => 'Nextcloud', 'color' => '#1cafff'], // Logo color
51                         'mistpark'     => ['name' => 'Nomad projects (Mistpark, Osada, Roadhouse, Zap)', 'color' => '#348a4a'], // Green like the Mistpark green
52                         'peertube'     => ['name' => 'Peertube', 'color' => '#ffad5c'], // One of the logo colors
53                         'pixelfed'     => ['name' => 'Pixelfed', 'color' => '#11da47'], // One of the logo colors
54                         'pleroma'      => ['name' => 'Pleroma', 'color' => '#E46F0F'], // Orange from the text that is used on Pleroma instances
55                         'plume'        => ['name' => 'Plume', 'color' => '#7765e3'], // From the homepage
56                         'relay'        => ['name' => 'ActivityPub Relay', 'color' => '#888888'], // Grey like the second color of the ActivityPub logo
57                         'socialhome'   => ['name' => 'SocialHome', 'color' => '#52056b'], // lilac from the Django Image used at the Socialhome homepage
58                         'wordpress'    => ['name' => 'WordPress', 'color' => '#016087'], // Background color of the homepage
59                         'writefreely'  => ['name' => 'WriteFreely', 'color' => '#292929'], // Font color of the homepage
60                         'other'        => ['name' => DI::l10n()->t('Other'), 'color' => '#F1007E'], // ActivityPub main color
61                 ];
62
63                 $platforms = array_keys($systems);
64
65                 $counts = [];
66                 foreach ($platforms as $platform) {
67                         $counts[$platform] = [];
68                 }
69
70                 $total = 0;
71                 $users = 0;
72
73                 $gservers = DBA::p("SELECT COUNT(*) AS `total`, SUM(`registered-users`) AS `users`, `platform`,
74                         ANY_VALUE(`network`) AS `network`, MAX(`version`) AS `version`
75                         FROM `gserver` WHERE NOT `failed` AND `detection-method` != ? GROUP BY `platform`", GServer::DETECT_MANUAL);
76                 while ($gserver = DBA::fetch($gservers)) {
77                         $total += $gserver['total'];
78                         $users += $gserver['users'];
79
80                         $versionCounts = [];
81                         $versions = DBA::p("SELECT COUNT(*) AS `total`, `version` FROM `gserver`
82                                 WHERE NOT `failed` AND `platform` = ? AND `detection-method` != ?
83                                 GROUP BY `version` ORDER BY `version`", $gserver['platform'], GServer::DETECT_MANUAL);
84                         while ($version = DBA::fetch($versions)) {
85                                 $version['version'] = str_replace(["\n", "\r", "\t"], " ", $version['version']);
86
87                                 if (in_array($gserver['platform'], ['Red Matrix', 'redmatrix', 'red'])) {
88                                         $version['version'] = 'Red ' . $version['version'];
89                                 } elseif (in_array($gserver['platform'], ['osada', 'mistpark', 'roadhouse', 'zap'])) {
90                                         $version['version'] = $gserver['platform'] . ' ' . $version['version'];
91                                 } elseif (in_array($gserver['platform'], ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) {
92                                         $version['version'] = $gserver['platform'] . '-' . $version['version'];
93                                 }
94
95                                 $versionCounts[] = $version;
96                         }
97                         DBA::close($versions);
98
99                         $platform = $gserver['platform'] = strtolower($gserver['platform']);
100
101                         if ($platform == 'friendika') {
102                                 $platform = 'friendica';
103                         } elseif (in_array($platform, ['red matrix', 'redmatrix', 'red'])) {
104                                 $platform = 'hubzilla';
105                         } elseif (in_array($platform, ['mistpark', 'osada', 'roadhouse', 'zap'])) {
106                                 $platform = 'mistpark';
107                         } elseif(stristr($platform, 'pleroma')) {
108                                 $platform = 'pleroma';
109                         } elseif(stristr($platform, 'statusnet')) {
110                                 $platform = 'gnusocial';
111                         } elseif(stristr($platform, 'wordpress')) {
112                                 $platform = 'wordpress';
113                         } elseif (in_array($platform, ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) {
114                                 $platform = 'relay';
115                         } elseif (!in_array($platform, $platforms)) {
116                                 $platform = 'other';
117                         }
118
119                         if ($platform != $gserver['platform']) {
120                                 if ($platform == 'other') {
121                                         $versionCounts = $counts[$platform][1] ?? [];
122                                         $versionCounts[] = ['version' => $gserver['platform'] ?: DI::l10n()->t('unknown'), 'total' => $gserver['total']];
123                                         $gserver['version'] = '';
124                                 } else {
125                                         $versionCounts = array_merge($versionCounts, $counts[$platform][1] ?? []);
126                                 }
127
128                                 $gserver['platform'] = $platform;
129                                 $gserver['total'] += $counts[$platform][0]['total'] ?? 0;
130                                 $gserver['users'] += $counts[$platform][0]['users'] ?? 0;
131                         }
132
133                         if ($platform == 'friendica') {
134                                 $versionCounts = self::reformaFriendicaVersions($versionCounts);
135                         } elseif ($platform == 'pleroma') {
136                                 $versionCounts = self::reformaPleromaVersions($versionCounts);
137                         } elseif ($platform == 'diaspora') {
138                                 $versionCounts = self::reformaDiasporaVersions($versionCounts);
139                         } elseif ($platform == 'relay') {
140                                 $versionCounts = self::reformatRelayVersions($versionCounts);
141                         } elseif (in_array($platform, ['funkwhale', 'mastodon', 'mobilizon', 'misskey'])) {
142                                 $versionCounts = self::removeVersionSuffixes($versionCounts);
143                         }
144
145                         if (!in_array($platform, ['other', 'relay', 'mistpark'])) {
146                                 $versionCounts = self::sortVersion($versionCounts);
147                         } else {
148                                 ksort($versionCounts);
149                         }
150
151                         $gserver['platform'] = $systems[$platform]['name'];
152
153                         $counts[$platform] = [$gserver, $versionCounts, str_replace([' ', '%'], '', $platform), $systems[$platform]['color']];
154                 }
155                 DBA::close($gserver);
156
157                 // some helpful text
158                 $intro = DI::l10n()->t('This page offers you some numbers to the known part of the federated social network your Friendica node is part of. These numbers are not complete but only reflect the part of the network your node is aware of.');
159
160                 // load the template, replace the macros and return the page content
161                 $t = Renderer::getMarkupTemplate('admin/federation.tpl');
162                 return Renderer::replaceMacros($t, [
163                         '$title' => DI::l10n()->t('Administration'),
164                         '$page' => DI::l10n()->t('Federation Statistics'),
165                         '$intro' => $intro,
166                         '$counts' => $counts,
167                         '$version' => FRIENDICA_VERSION,
168                         '$legendtext' => DI::l10n()->t('Currently this node is aware of %d nodes with %d registered users from the following platforms:', $total, $users),
169                 ]);
170         }
171
172         /**
173          * early friendica versions have the format x.x.xxxx where xxxx is the
174          * DB version stamp; those should be operated out and versions be combined
175          *
176          * @param array $versionCounts list of version numbers
177          * @return array with cleaned version numbers
178          */
179         private static function reformaFriendicaVersions(array $versionCounts)
180         {
181                 $newV = [];
182                 $newVv = [];
183                 foreach ($versionCounts as $vv) {
184                         $newVC = $vv['total'];
185                         $newVV = $vv['version'];
186                         $lastDot = strrpos($newVV, '.');
187                         $firstDash = strpos($newVV, '-');
188                         $len = strlen($newVV) - 1;
189                         if (($lastDot == $len - 4) && (!strrpos($newVV, '-rc') == $len - 3) && (!$firstDash == $len - 1)) {
190                                 $newVV = substr($newVV, 0, $lastDot);
191                         }
192                         if (isset($newV[$newVV])) {
193                                 $newV[$newVV] += $newVC;
194                         } else {
195                                 $newV[$newVV] = $newVC;
196                         }
197                 }
198                 foreach ($newV as $key => $value) {
199                         array_push($newVv, ['total' => $value, 'version' => $key]);
200                 }
201                 $versionCounts = $newVv;
202
203                 return $versionCounts;
204         }
205
206         /**
207          * in the DB the Diaspora versions have the format x.x.x.x-xx the last
208          * part (-xx) should be removed to clean up the versions from the "head
209          * commit" information and combined into a single entry for x.x.x.x
210          *
211          * @param array $versionCounts list of version numbers
212          * @return array with cleaned version numbers
213          */
214         private static function reformaDiasporaVersions(array $versionCounts)
215         {
216                 $newV = [];
217                 $newVv = [];
218                 foreach ($versionCounts as $vv) {
219                         $newVC = $vv['total'];
220                         $newVV = $vv['version'];
221                         $posDash = strpos($newVV, '-');
222                         if ($posDash) {
223                                 $newVV = substr($newVV, 0, $posDash);
224                         }
225                         if (isset($newV[$newVV])) {
226                                 $newV[$newVV] += $newVC;
227                         } else {
228                                 $newV[$newVV] = $newVC;
229                         }
230                 }
231                 foreach ($newV as $key => $value) {
232                         array_push($newVv, ['total' => $value, 'version' => $key]);
233                 }
234                 $versionCounts = $newVv;
235
236                 return $versionCounts;
237         }
238
239         /**
240          * Clean up Pleroma version numbers
241          *
242          * @param array $versionCounts list of version numbers
243          * @return array with cleaned version numbers
244          */
245         private static function reformaPleromaVersions(array $versionCounts)
246         {
247                 $compacted = [];
248                 foreach ($versionCounts as $key => $value) {
249                         $version = $versionCounts[$key]['version'];
250                         $parts = explode(' ', trim($version));
251                         do {
252                                 $part = array_pop($parts);
253                         } while (!empty($parts) && ((strlen($part) >= 40) || (strlen($part) <= 3)));
254                         // only take the x.x.x part of the version, not the "release" after the dash
255                         if (!empty($part) && strpos($part, '-')) {
256                                 $part = explode('-', $part)[0];
257                         }
258                         if (!empty($part)) {
259                                 if (empty($compacted[$part])) {
260                                         $compacted[$part] = $versionCounts[$key]['total'];
261                                 } else {
262                                         $compacted[$part] += $versionCounts[$key]['total'];
263                                 }
264                         }
265                 }
266
267                 $versionCounts = [];
268                 foreach ($compacted as $version => $pl_total) {
269                         $versionCounts[] = ['version' => $version, 'total' => $pl_total];
270                 }
271
272                 return $versionCounts;
273         }
274
275         /**
276          * Clean up version numbers
277          *
278          * @param array $versionCounts list of version numbers
279          * @return array with cleaned version numbers
280          */
281         private static function removeVersionSuffixes(array $versionCounts)
282         {
283                 $compacted = [];
284                 foreach ($versionCounts as $key => $value) {
285                         $version = $versionCounts[$key]['version'];
286
287                         foreach ([' ', '+', '-', '#', '_', '~'] as $delimiter) {
288                                 $parts = explode($delimiter, trim($version));
289                                 $version = array_shift($parts);
290                         }
291
292                         if (empty($compacted[$version])) {
293                                 $compacted[$version] = $versionCounts[$key]['total'];
294                         } else {
295                                 $compacted[$version] += $versionCounts[$key]['total'];
296                         }
297                 }
298
299                 $versionCounts = [];
300                 foreach ($compacted as $version => $pl_total) {
301                         $versionCounts[] = ['version' => $version, 'total' => $pl_total];
302                 }
303
304                 return $versionCounts;
305         }
306
307         /**
308          * Clean up relay version numbers
309          *
310          * @param array $versionCounts list of version numbers
311          * @return array with cleaned version numbers
312          */
313         private static function reformatRelayVersions(array $versionCounts)
314         {
315                 $compacted = [];
316                 foreach ($versionCounts as $key => $value) {
317                         $version = $versionCounts[$key]['version'];
318
319                         $parts = explode(' ', trim($version));
320                         $version = array_shift($parts);
321
322                         if (empty($compacted[$version])) {
323                                 $compacted[$version] = $versionCounts[$key]['total'];
324                         } else {
325                                 $compacted[$version] += $versionCounts[$key]['total'];
326                         }
327                 }
328
329                 $versionCounts = [];
330                 foreach ($compacted as $version => $pl_total) {
331                         $versionCounts[] = ['version' => $version, 'total' => $pl_total];
332                 }
333
334                 return $versionCounts;
335         }
336
337         /**
338          * Reformat, sort and compact version numbers
339          *
340          * @param array $versionCounts list of version numbers
341          * @return array with reformatted version numbers
342          */
343         private static function sortVersion(array $versionCounts)
344         {
345                 //
346                 // clean up version numbers
347                 //
348                 // some platforms do not provide version information, add a unkown there
349                 // to the version string for the displayed list.
350                 foreach ($versionCounts as $key => $value) {
351                         if ($versionCounts[$key]['version'] == '') {
352                                 $versionCounts[$key] = ['total' => $versionCounts[$key]['total'], 'version' => DI::l10n()->t('unknown')];
353                         }
354                 }
355
356                 // Assure that the versions are sorted correctly
357                 $v2 = [];
358                 $versions = [];
359                 foreach ($versionCounts as $vv) {
360                         $version = trim(strip_tags($vv["version"]));
361                         $v2[$version] = $vv;
362                         $versions[] = $version;
363                 }
364
365                 usort($versions, 'version_compare');
366
367                 $versionCounts = [];
368                 foreach ($versions as $version) {
369                         $versionCounts[] = $v2[$version];
370                 }
371
372                 return $versionCounts;
373         }
374 }