support multiple fallback links for splx contact and channels

This commit is contained in:
Alain Brenzikofer
2026-06-09 14:32:36 +02:00
parent c95d4bcdc1
commit bbea84c605
2 changed files with 34 additions and 7 deletions
+14 -4
View File
@@ -151,8 +151,11 @@ curl -s http://127.0.0.1:8000/resolve/foobar.testing | jq .
"nickname": "Foo",
"website": "https://foo.bar",
"location": "",
"simplexContact": "https://smp16.simplex.im/a#Q_F00BA7",
"simplexChannel": "",
"simplexContact": [
"https://smp16.simplex.im/a#Q_F00BA7",
"https://smp11.simplex.im/a#Q_F00BA8"
],
"simplexChannel": [],
"eth": null,
"btc": "bc1qpzht4wp64yg7z6sgl07vvrnepyux740juynfcn",
"xmr": "4ANzdVJFxLtCKcBgNGkFSEA41zJFgrTX93LWt9UR6xpg7YNCsdrSV817cw2xKT8NXeS5euBBqTApS2u8kRTxMhyiDGN3Qgt",
@@ -162,6 +165,13 @@ curl -s http://127.0.0.1:8000/resolve/foobar.testing | jq .
}
```
`simplexContact` and `simplexChannel` are arrays so a name can advertise
multiple SMP servers for redundancy. Clients SHOULD try the URLs in
order; the first entry is the primary and the rest are fallbacks. The
on-chain text record stores them as a single comma-separated string
(`"url1,url2,url3"`); this resolver splits, trims whitespace, and drops
empty entries before returning.
All field names are lowercase-initial and contain no dots, so they map
directly onto Haskell record fields and can be consumed via aeson's
`Generic`-derived `FromJSON` without a key-rewriting layer. Equivalent
@@ -173,8 +183,8 @@ data SnrcRecord = SnrcRecord
, nickname :: Text
, website :: Text
, location :: Text
, simplexContact :: Text
, simplexChannel :: Text
, simplexContact :: [Text]
, simplexChannel :: [Text]
, eth :: Maybe Text
, btc :: Maybe Text
, xmr :: Maybe Text
+20 -3
View File
@@ -12,10 +12,15 @@ deployment on Ethereum mainnet (or any compatible ENS-shaped registry)
and returns a flat JSON document with these fields:
name, nickname, website, location,
simplexContact, simplexChannel,
simplexContact, simplexChannel, -- list[str], primary first
eth, btc, xmr, dot,
owner, resolver
`simplexContact` and `simplexChannel` are arrays so a name can advertise
multiple SMP servers for redundancy. Clients SHOULD try the URLs in the
order returned. The on-chain text record stores them as a single
comma-separated string; this resolver splits and trims into a list.
All keys are valid Haskell record-field identifiers (lowercase initial,
no dots), so consumers can derive aeson FromJSON instances directly
without a key-rewriting layer.
@@ -367,6 +372,18 @@ TEXT_KEYS = [
]
def split_csv(value: str) -> list:
"""Split a comma-separated text record into an ordered list of entries.
Trims whitespace around each element and drops empties so trailing
commas, doubled commas, and all-whitespace inputs all yield clean
output. Single-value records yield a 1-element list; empty inputs
yield `[]`. Used for `simplex.contact` / `simplex.channel`, which
store one-or-more SMP-server URLs as a single comma-joined string.
"""
return [item.strip() for item in value.split(",") if item.strip()]
def resolve(name: str):
tld = name.rsplit(".", 1)[-1]
registry = REGISTRIES.get(tld)
@@ -412,8 +429,8 @@ def resolve(name: str):
"nickname": nickname,
"website": texts.get("url", ""),
"location": texts.get("location", ""),
"simplexContact": texts.get("simplex.contact", ""),
"simplexChannel": texts.get("simplex.channel", ""),
"simplexContact": split_csv(texts.get("simplex.contact", "")),
"simplexChannel": split_csv(texts.get("simplex.channel", "")),
"eth": addr_multicoin(resolver_addr, node, COIN_ETH),
"btc": addr_multicoin(resolver_addr, node, COIN_BTC),
"xmr": addr_multicoin(resolver_addr, node, COIN_XMR),