mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-11-08 08:01:09 +00:00
Merge 842b8f81f1d1687ae629c97cdc916696cf1be885 into 1f24973b06ee77492742ba522002e028f38f4381
This commit is contained in:
commit
ecdb082dbe
@ -97,12 +97,31 @@ object RelayDirectory {
|
||||
}
|
||||
|
||||
val (lat, lon) = center
|
||||
return snapshot
|
||||
.asSequence()
|
||||
.sortedBy { haversineMeters(lat, lon, it.latitude, it.longitude) }
|
||||
.take(nRelays.coerceAtLeast(0))
|
||||
.map { it.url }
|
||||
.toList()
|
||||
return selectClosest(snapshot, lat, lon, nRelays)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same distance order as iOS, with the host as the tie-break, after
|
||||
* `host` and `host:443` have been collapsed to one URL.
|
||||
*/
|
||||
internal fun selectClosest(
|
||||
entries: List<RelayInfo>,
|
||||
lat: Double,
|
||||
lon: Double,
|
||||
count: Int
|
||||
): List<String> {
|
||||
if (entries.isEmpty() || count <= 0) return emptyList()
|
||||
val seen = LinkedHashSet<String>()
|
||||
entries
|
||||
.map { it.copy(url = canonicalRelayUrl(it.url)) }
|
||||
.sortedWith(
|
||||
compareBy<RelayInfo> { haversineMeters(lat, lon, it.latitude, it.longitude) }
|
||||
.thenBy { relaySortKey(it.url) }
|
||||
)
|
||||
.forEach { entry ->
|
||||
if (entry.url.isNotEmpty()) seen.add(entry.url)
|
||||
}
|
||||
return seen.take(count).toList()
|
||||
}
|
||||
|
||||
private fun haversineMeters(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double {
|
||||
@ -114,12 +133,28 @@ object RelayDirectory {
|
||||
return R * c
|
||||
}
|
||||
|
||||
private fun normalizeRelayUrl(raw: String): String {
|
||||
internal fun canonicalRelayUrl(raw: String): String {
|
||||
val trimmed = raw.trim()
|
||||
if (trimmed.isEmpty()) return trimmed
|
||||
return if ("://" in trimmed) trimmed else "wss://$trimmed"
|
||||
val withScheme = if ("://" in trimmed) trimmed else "wss://$trimmed"
|
||||
val schemeEnd = withScheme.indexOf("://")
|
||||
if (schemeEnd < 0) return withScheme
|
||||
val scheme = withScheme.substring(0, schemeEnd).lowercase()
|
||||
val rest = withScheme.substring(schemeEnd + 3)
|
||||
val authority = rest.substringBefore('/').substringBefore('?').substringBefore('#')
|
||||
val tail = rest.removePrefix(authority)
|
||||
val host = authority.substringBefore(':').lowercase()
|
||||
if (host.isEmpty()) return withScheme
|
||||
val port = authority.substringAfter(':', "")
|
||||
val authorityOut = if (port.isEmpty() || port == "443") host else "$host:$port"
|
||||
return "$scheme://$authorityOut$tail"
|
||||
}
|
||||
|
||||
private fun relaySortKey(url: String): String =
|
||||
url.substringAfter("://", url).substringBefore('/').substringBefore(':')
|
||||
|
||||
private fun normalizeRelayUrl(raw: String): String = canonicalRelayUrl(raw)
|
||||
|
||||
// ===== Implementation details =====
|
||||
|
||||
private fun getPrefs(application: Application): SharedPreferences =
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package com.bitchat.android.nostr
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class RelayDirectorySelectionTest {
|
||||
|
||||
@Test
|
||||
fun `canonical url drops the default port and lowercases the host`() {
|
||||
assertEquals(
|
||||
"wss://relay.example.com",
|
||||
RelayDirectory.canonicalRelayUrl("relay.example.com:443")
|
||||
)
|
||||
assertEquals(
|
||||
"wss://relay.example.com",
|
||||
RelayDirectory.canonicalRelayUrl("WSS://Relay.Example.com:443")
|
||||
)
|
||||
assertEquals(
|
||||
"wss://relay.example.com:8443",
|
||||
RelayDirectory.canonicalRelayUrl("relay.example.com:8443")
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `duplicate host and port do not take two of the five slots`() {
|
||||
val entries = listOf(
|
||||
RelayDirectory.RelayInfo("wss://b.example", 0.0, 0.0),
|
||||
RelayDirectory.RelayInfo("b.example:443", 0.0, 0.0),
|
||||
RelayDirectory.RelayInfo("a.example", 0.0, 0.0),
|
||||
RelayDirectory.RelayInfo("c.example", 1.0, 1.0)
|
||||
)
|
||||
|
||||
val picked = RelayDirectory.selectClosest(entries, lat = 0.0, lon = 0.0, count = 2)
|
||||
|
||||
assertEquals(listOf("wss://a.example", "wss://b.example"), picked)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user