diff --git a/output/js/util.js b/output/js/util.js index d5d41528..7cb8d0c6 100644 --- a/output/js/util.js +++ b/output/js/util.js @@ -245,7 +245,10 @@ const TRANSFORMATION = { numeric: (el) => parseInt(el.innerText), casefold: (el) => el.innerText.toLowerCase().trim(), getName: (_, row) => dom.row_info(row).name.toLowerCase(), - getRoomPublicKey: (_, row) => dom.row_info(row).public_key + getServerId: (_, row) => { + const rowInfo = dom.row_info(row); + return `${rowInfo.public_key}${rowInfo.join_link}`; + } } /** @@ -256,7 +259,7 @@ export const COLUMN_TRANSFORMATION = { [COLUMN.IDENTIFIER]: TRANSFORMATION.casefold, [COLUMN.NAME]: TRANSFORMATION.getName, [COLUMN.DESCRIPTION]: TRANSFORMATION.casefold, - [COLUMN.SERVER_ICON]: TRANSFORMATION.getRoomPublicKey + [COLUMN.SERVER_ICON]: TRANSFORMATION.getServerId } /** diff --git a/php/fetch-servers.php b/php/fetch-servers.php index 1eefa0c1..a29d8e42 100644 --- a/php/fetch-servers.php +++ b/php/fetch-servers.php @@ -48,8 +48,8 @@ // Fetch server data and filter unreachable servers. $servers = CommunityServer::poll_reachable($servers); - // Merge servers with the same public key. - $servers = CommunityServer::dedupe_by_pubkey($servers); + // Merge servers with the same public key and rooms. + $servers = CommunityServer::dedupe_by_data($servers); // Fill additional information from sources. CommunityServer::source_additional_info($servers, $sources); diff --git a/php/servers/servers-rooms.php b/php/servers/servers-rooms.php index 3d0eb7a1..3bf2b71e 100644 --- a/php/servers/servers-rooms.php +++ b/php/servers/servers-rooms.php @@ -296,14 +296,14 @@ } /** - * Sort Community rooms in-place by their server's public key. - * @param CommunityRoom[] $rooms Rooms to sort by server pubkey. + * Sort Community rooms in-place by their server. + * @param CommunityRoom[] $rooms Rooms to sort by server. */ - public static function sort_rooms_by_pubkey(array &$rooms) { + public static function sort_rooms_by_server(array &$rooms) { usort($rooms, function(CommunityRoom $a, CommunityRoom $b) { return strcmp( - $a->server->get_pubkey(), - $b->server->get_pubkey() + $a->server->get_pubkey() . $a->server->get_hostname(), + $b->server->get_pubkey() . $b->server->get_hostname() ); }); } @@ -493,7 +493,7 @@ * @param string $matchee String matching room. Output parameter. * @return bool True if the array matches the Community, false otherwise. */ - public function matched_by_list(array $filter, string &$matchee): bool { + public function matched_by_list(array $filter, string &$matchee = null): bool { foreach ($filter as $filter_item) { if ($this->matched_by_identifier($filter_item)) { $matchee = $filter_item; @@ -510,7 +510,7 @@ * @param string[] $matchees output parameter * @return CommunityRoom[] */ - public static function select_rooms(array $rooms, array|string $filter, array &$matchees): array { + public static function select_rooms(array $rooms, array|string $filter, array &$matchees = null): array { $_matchees = []; $rooms = array_values(array_filter($rooms, function(CommunityRoom $room) use ($filter, $_matchees) { $matchee = null; @@ -687,10 +687,10 @@ case SameHostname; /** - * @var SamePublicKey - * Strategy considering two servers to be identical if they share a SOGS public key. + * @var SameData + * Strategy considering two servers to be identical if they share a SOGS public key and room data. */ - case SamePublicKey; + case SameData; /** * Determine whether two CommunityServer instances are identical under the given criteria. @@ -700,8 +700,11 @@ */ public function should_merge_servers(CommunityServer $a, CommunityServer $b): bool { return match ($this) { - CommunityServerMergeStrategy::SameHostname => $a->get_hostname() == $b->get_hostname(), - CommunityServerMergeStrategy::SamePublicKey => $a->get_pubkey() == $b->get_pubkey() + CommunityServerMergeStrategy::SameHostname => + $a->get_hostname() == $b->get_hostname(), + CommunityServerMergeStrategy::SameData => + $a->get_pubkey() == $b->get_pubkey() && + CommunityServer::rooms_in_common($a, $b) }; } } @@ -801,6 +804,27 @@ usort($servers, 'CommunityServer::compare_by_pubkey'); } + /** + * Return true whether the two servers given share a room. + */ + public static function rooms_in_common(CommunityServer $a, CommunityServer $b): bool { + // Rely on at least token or creation date differing. + // Do not strictly compare room lists because the servers + // may have been polled at different times. + + $room_date_pairs = []; + $rooms = CommunityServer::enumerate_rooms([$a, $b]); + foreach ($rooms as $room) { + $room_date_pairs[] = $room->token . "+" . $room->created; + } + + if (count(array_unique($room_date_pairs)) < count($rooms)) { + return true; + } + + return false; + } + /** * Absorb candidates for the SOGS public key from a duplicate server instance. */ @@ -830,7 +854,7 @@ exit(1); } $this->merge_pubkeys_from($server); - } else if ($strategy == CommunityServerMergeStrategy::SamePublicKey) { + } else if ($strategy == CommunityServerMergeStrategy::SameData) { if ($this->get_pubkey() != $server->get_pubkey()) { log_error("SamePublicKey merging: Merged servers differ in public key"); exit(1); @@ -919,10 +943,10 @@ * @param CommunityServer[] $servers Servers to merge by public key. * @return CommunityServer[] Servers merged by public key- */ - public static function dedupe_by_pubkey($servers) { + public static function dedupe_by_data($servers) { CommunityServer::sort_by_pubkey($servers); - CommunityServer::merge_by($servers, CommunityServerMergeStrategy::SamePublicKey); + CommunityServer::merge_by($servers, CommunityServerMergeStrategy::SameData); $servers = CommunityServer::ensure_merge_consistency($servers); diff --git a/sites/index.php b/sites/index.php index dfe350fe..5352f34d 100644 --- a/sites/index.php +++ b/sites/index.php @@ -22,7 +22,7 @@ // Sort rooms by name and then host. CommunityRoom::sort_rooms_str($rooms, 'name'); - CommunityRoom::sort_rooms_by_pubkey($rooms); + CommunityRoom::sort_rooms_by_server($rooms); // Set the last-updated timestamp // to the time the server data file was last modified.