Fix server merging and room sort

dev
gravel 2 years ago
parent b2308e4095
commit 44a47cad1d
Signed by: gravel
GPG Key ID: C0538F3C906B308F

@ -245,7 +245,10 @@ const TRANSFORMATION = {
numeric: (el) => parseInt(el.innerText), numeric: (el) => parseInt(el.innerText),
casefold: (el) => el.innerText.toLowerCase().trim(), casefold: (el) => el.innerText.toLowerCase().trim(),
getName: (_, row) => dom.row_info(row).name.toLowerCase(), 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.IDENTIFIER]: TRANSFORMATION.casefold,
[COLUMN.NAME]: TRANSFORMATION.getName, [COLUMN.NAME]: TRANSFORMATION.getName,
[COLUMN.DESCRIPTION]: TRANSFORMATION.casefold, [COLUMN.DESCRIPTION]: TRANSFORMATION.casefold,
[COLUMN.SERVER_ICON]: TRANSFORMATION.getRoomPublicKey [COLUMN.SERVER_ICON]: TRANSFORMATION.getServerId
} }
/** /**

@ -48,8 +48,8 @@
// Fetch server data and filter unreachable servers. // Fetch server data and filter unreachable servers.
$servers = CommunityServer::poll_reachable($servers); $servers = CommunityServer::poll_reachable($servers);
// Merge servers with the same public key. // Merge servers with the same public key and rooms.
$servers = CommunityServer::dedupe_by_pubkey($servers); $servers = CommunityServer::dedupe_by_data($servers);
// Fill additional information from sources. // Fill additional information from sources.
CommunityServer::source_additional_info($servers, $sources); CommunityServer::source_additional_info($servers, $sources);

@ -296,14 +296,14 @@
} }
/** /**
* Sort Community rooms in-place by their server's public key. * Sort Community rooms in-place by their server.
* @param CommunityRoom[] $rooms Rooms to sort by server pubkey. * @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) { usort($rooms, function(CommunityRoom $a, CommunityRoom $b) {
return strcmp( return strcmp(
$a->server->get_pubkey(), $a->server->get_pubkey() . $a->server->get_hostname(),
$b->server->get_pubkey() $b->server->get_pubkey() . $b->server->get_hostname()
); );
}); });
} }
@ -493,7 +493,7 @@
* @param string $matchee String matching room. Output parameter. * @param string $matchee String matching room. Output parameter.
* @return bool True if the array matches the Community, false otherwise. * @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) { foreach ($filter as $filter_item) {
if ($this->matched_by_identifier($filter_item)) { if ($this->matched_by_identifier($filter_item)) {
$matchee = $filter_item; $matchee = $filter_item;
@ -510,7 +510,7 @@
* @param string[] $matchees output parameter * @param string[] $matchees output parameter
* @return CommunityRoom[] * @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 = []; $_matchees = [];
$rooms = array_values(array_filter($rooms, function(CommunityRoom $room) use ($filter, $_matchees) { $rooms = array_values(array_filter($rooms, function(CommunityRoom $room) use ($filter, $_matchees) {
$matchee = null; $matchee = null;
@ -687,10 +687,10 @@
case SameHostname; case SameHostname;
/** /**
* @var SamePublicKey * @var SameData
* Strategy considering two servers to be identical if they share a SOGS public key. * 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. * 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 { public function should_merge_servers(CommunityServer $a, CommunityServer $b): bool {
return match ($this) { return match ($this) {
CommunityServerMergeStrategy::SameHostname => $a->get_hostname() == $b->get_hostname(), CommunityServerMergeStrategy::SameHostname =>
CommunityServerMergeStrategy::SamePublicKey => $a->get_pubkey() == $b->get_pubkey() $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'); 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. * Absorb candidates for the SOGS public key from a duplicate server instance.
*/ */
@ -830,7 +854,7 @@
exit(1); exit(1);
} }
$this->merge_pubkeys_from($server); $this->merge_pubkeys_from($server);
} else if ($strategy == CommunityServerMergeStrategy::SamePublicKey) { } else if ($strategy == CommunityServerMergeStrategy::SameData) {
if ($this->get_pubkey() != $server->get_pubkey()) { if ($this->get_pubkey() != $server->get_pubkey()) {
log_error("SamePublicKey merging: Merged servers differ in public key"); log_error("SamePublicKey merging: Merged servers differ in public key");
exit(1); exit(1);
@ -919,10 +943,10 @@
* @param CommunityServer[] $servers Servers to merge by public key. * @param CommunityServer[] $servers Servers to merge by public key.
* @return CommunityServer[] Servers merged 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::sort_by_pubkey($servers);
CommunityServer::merge_by($servers, CommunityServerMergeStrategy::SamePublicKey); CommunityServer::merge_by($servers, CommunityServerMergeStrategy::SameData);
$servers = CommunityServer::ensure_merge_consistency($servers); $servers = CommunityServer::ensure_merge_consistency($servers);

@ -22,7 +22,7 @@
// Sort rooms by name and then host. // Sort rooms by name and then host.
CommunityRoom::sort_rooms_str($rooms, 'name'); CommunityRoom::sort_rooms_str($rooms, 'name');
CommunityRoom::sort_rooms_by_pubkey($rooms); CommunityRoom::sort_rooms_by_server($rooms);
// Set the last-updated timestamp // Set the last-updated timestamp
// to the time the server data file was last modified. // to the time the server data file was last modified.

Loading…
Cancel
Save