From 1cf96fc29100c7df7cfb8a811e7876f2b743d001 Mon Sep 17 00:00:00 2001 From: shum Date: Fri, 5 Jun 2026 10:09:02 +0000 Subject: [PATCH] deps: bump simplexmq for NameRecord reshape; update consumers simplexmq 5ee014dd reshaped NameRecord to align with the Python resolver JSON: nrChannelLinks/nrContactLinks (lists of NameLink) became nrSimplexChannel/nrSimplexContact (Maybe Text); nrDisplayName became nrName; nrResolver was added; the NameLink wrapper type and nrIsTest/ nrExpiry/nrAdminAddress/nrAdminEmail fields were dropped. Update dispatchResolvedRecord destructure and firstNameLink signature to the new Maybe Text shape, and refresh the ResolveNameTests fixtures and assertions accordingly. --- cabal.project | 2 +- src/Simplex/Chat/Library/Commands.hs | 25 +++++---- tests/ResolveNameTests.hs | 78 ++++++++++++++-------------- 3 files changed, 51 insertions(+), 54 deletions(-) diff --git a/cabal.project b/cabal.project index 2c9d1da4b4..18fd30645f 100644 --- a/cabal.project +++ b/cabal.project @@ -21,7 +21,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 90de60eeb46f8856af87f11b934b49546363a2fa + tag: 5ee014ddccd11e612fe873a7150ccf78b81a0ad2 source-repository-package type: git diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index cd4d87da93..ce676941fa 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -107,7 +107,7 @@ import Simplex.Messaging.Crypto.Ratchet (PQEncryption (..), PQSupport (..), patt import Simplex.Messaging.Encoding import Simplex.Messaging.Encoding.String import Simplex.Messaging.Parsers (base64P) -import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), MsgFlags (..), NameLink, NameRecord (..), NtfServer, ProtoServerWithAuth (..), ProtocolServer, ProtocolType (..), ProtocolTypeI (..), SMPServer, SProtocolType (..), SubscriptionMode (..), UserProtocol, unNameLink, userProtocol) +import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType (..), MsgFlags (..), NameRecord (..), NtfServer, ProtoServerWithAuth (..), ProtocolServer, ProtocolType (..), ProtocolTypeI (..), SMPServer, SProtocolType (..), SubscriptionMode (..), UserProtocol, userProtocol) import qualified Simplex.Messaging.Protocol as SMP import Simplex.Messaging.ServiceScheme (ServiceScheme (..)) import qualified Simplex.Messaging.TMap as TM @@ -4671,8 +4671,8 @@ resolveOnUserServers user@User {userId} domain = do -- parameter (introduced for the local-prepare path, see commit c6f26150), so -- the resolver hit reuses the same DB write path as a local-prepare hit. dispatchResolvedRecord :: VersionRangeChat -> NetworkRequestMode -> User -> SimplexNameInfo -> NameRecord -> CM (ACreatedConnLink, ConnectionPlan) -dispatchResolvedRecord vr nm user ni@SimplexNameInfo {nameType} NameRecord {nrChannelLinks, nrContactLinks} = do - lnk <- liftEither $ firstNameLink nameType nrChannelLinks nrContactLinks ni +dispatchResolvedRecord vr nm user ni@SimplexNameInfo {nameType} NameRecord {nrSimplexChannel, nrSimplexContact} = do + lnk <- liftEither $ firstNameLink nameType nrSimplexChannel nrSimplexContact ni acl <- liftEither $ first (chatErrorAgent . AGENT . A_LINK) $ strDecode (encodeUtf8 lnk) prepareAndPlan acl where @@ -4722,17 +4722,16 @@ dispatchResolvedRecord vr nm user ni@SimplexNameInfo {nameType} NameRecord {nrCh CSLInvitation _ srv lnkId linkKey -> CSLInvitation SLSServer srv lnkId linkKey CSLContact _ ct srv linkKey -> CSLContact SLSServer ct srv linkKey --- | Pick the first link from the @NameRecord@ matching the queried name type. --- An empty list (record exists but advertises no link of this kind) is --- treated as "not found" — same UX as a local-store miss. -firstNameLink :: SimplexNameType -> [NameLink] -> [NameLink] -> SimplexNameInfo -> Either ChatError Text -firstNameLink nameType channelLinks contactLinks ni = case links of - l : _ -> Right $ unNameLink l - [] -> Left $ ChatError $ CESimplexNameNotFound ni +-- | Pick the link from the @NameRecord@ matching the queried name type. +-- A missing per-type field (record exists but advertises no link of this kind) +-- is treated as "not found" — same UX as a local-store miss. +firstNameLink :: SimplexNameType -> Maybe Text -> Maybe Text -> SimplexNameInfo -> Either ChatError Text +firstNameLink nameType simplexChannel simplexContact ni = + maybe (Left $ ChatError $ CESimplexNameNotFound ni) Right link where - links = case nameType of - NTPublicGroup -> channelLinks - NTContact -> contactLinks + link = case nameType of + NTPublicGroup -> simplexChannel + NTContact -> simplexContact -- | Map a resolver failure to the corresponding ChatError surfaced to the user. -- AUTH (NameNotRegistered) collapses to the same UX as a local-store miss, so diff --git a/tests/ResolveNameTests.hs b/tests/ResolveNameTests.hs index fae49732f2..3e5c9d4dbe 100644 --- a/tests/ResolveNameTests.hs +++ b/tests/ResolveNameTests.hs @@ -12,7 +12,7 @@ import Simplex.Chat.Library.Commands (ResolveError (..), firstNameLink, iterateR import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Agent.Protocol (AgentErrorType (..), SimplexNameDomain (..), SimplexNameInfo (..), SimplexNameType (..), SimplexTLD (..)) import Simplex.Messaging.Client (ProxyClientError (..)) -import Simplex.Messaging.Protocol (NameLink, NameRecord (..), SMPServer, mkNameLink, mkNameOwner, pattern SMPServer) +import Simplex.Messaging.Protocol (NameRecord (..), SMPServer, mkNameOwner, pattern SMPServer) import qualified Simplex.Messaging.Protocol as SMP import Test.Hspec @@ -66,31 +66,31 @@ resolveNameTests = do ChatErrorAgent e _ _ -> e `shouldBe` timeoutErr other -> expectationFailure $ "expected ChatErrorAgent, got " <> show other -- firstNameLink is the pure link-picker used by dispatchResolvedRecord: - -- it selects nrContactLinks for NTContact, nrChannelLinks for NTPublicGroup, - -- returning the first entry. Empty lists collapse to CESimplexNameNotFound - -- so the UX is identical to a local-store miss. + -- it selects nrSimplexContact for NTContact, nrSimplexChannel for NTPublicGroup. + -- A Nothing for the queried type collapses to CESimplexNameNotFound so the UX + -- is identical to a local-store miss. describe "firstNameLink" $ do - it "picks the first nrContactLinks entry for NTContact" $ - case firstNameLink NTContact [channelOne] [contactOne, contactTwo] aliceNi of - Right lnk -> lnk `shouldBe` "simplex:/contact-alice" + it "picks nrSimplexContact for NTContact" $ + case firstNameLink NTContact (Just channelLink) (Just contactLink) aliceNi of + Right lnk -> lnk `shouldBe` contactLink Left e -> expectationFailure $ "expected Right, got " <> show e - it "picks the first nrChannelLinks entry for NTPublicGroup" $ - case firstNameLink NTPublicGroup [channelOne, channelTwo] [contactOne] groupNi of - Right lnk -> lnk `shouldBe` "simplex:/channel-team" + it "picks nrSimplexChannel for NTPublicGroup" $ + case firstNameLink NTPublicGroup (Just channelLink) (Just contactLink) groupNi of + Right lnk -> lnk `shouldBe` channelLink Left e -> expectationFailure $ "expected Right, got " <> show e - it "returns CESimplexNameNotFound when nrContactLinks is empty for NTContact" $ - case firstNameLink NTContact [channelOne] [] aliceNi of + it "returns CESimplexNameNotFound when nrSimplexContact is Nothing for NTContact" $ + case firstNameLink NTContact (Just channelLink) Nothing aliceNi of Left (ChatError (CESimplexNameNotFound ni)) -> ni `shouldBe` aliceNi other -> expectationFailure $ "expected CESimplexNameNotFound, got " <> show other - it "returns CESimplexNameNotFound when nrChannelLinks is empty for NTPublicGroup" $ - case firstNameLink NTPublicGroup [] [contactOne] groupNi of + it "returns CESimplexNameNotFound when nrSimplexChannel is Nothing for NTPublicGroup" $ + case firstNameLink NTPublicGroup Nothing (Just contactLink) groupNi of Left (ChatError (CESimplexNameNotFound ni)) -> ni `shouldBe` groupNi other -> expectationFailure $ "expected CESimplexNameNotFound, got " <> show other - -- NTContact ignores nrChannelLinks even when nrContactLinks is empty. - -- The resolver-side semantics say each name advertises a per-type link - -- set; cross-type fallback would silently connect to the wrong target. - it "does not fall back to nrChannelLinks for NTContact" $ - case firstNameLink NTContact [channelOne] [] aliceNi of + -- NTContact ignores nrSimplexChannel even when nrSimplexContact is Nothing. + -- The resolver-side semantics say each name advertises a per-type link; + -- cross-type fallback would silently connect to the wrong target. + it "does not fall back to nrSimplexChannel for NTContact" $ + case firstNameLink NTContact (Just channelLink) Nothing aliceNi of Left (ChatError (CESimplexNameNotFound _)) -> pure () other -> expectationFailure $ "expected CESimplexNameNotFound, got " <> show other @@ -110,19 +110,13 @@ aliceNi = SimplexNameInfo NTContact (SimplexNameDomain TLDSimplex "alice" []) groupNi :: SimplexNameInfo groupNi = SimplexNameInfo NTPublicGroup (SimplexNameDomain TLDSimplex "team" []) --- Synthetic links to exercise firstNameLink's selection logic. mkNameLink only --- enforces the ≤1024-byte upper bound; the strings are deliberately not real --- AConnShortLink encodings — the link parser is exercised separately by the --- A_LINK error path inside dispatchResolvedRecord and by AConnShortLink's own --- round-trip tests in simplexmq. -mkLink :: Text -> NameLink -mkLink = either error id . mkNameLink - -channelOne, channelTwo, contactOne, contactTwo :: NameLink -channelOne = mkLink "simplex:/channel-team" -channelTwo = mkLink "simplex:/channel-team-backup" -contactOne = mkLink "simplex:/contact-alice" -contactTwo = mkLink "simplex:/contact-alice-backup" +-- Synthetic links to exercise firstNameLink's selection logic. The strings are +-- deliberately not real AConnShortLink encodings — the link parser is exercised +-- separately by the A_LINK error path inside dispatchResolvedRecord and by +-- AConnShortLink's own round-trip tests in simplexmq. +channelLink, contactLink :: Text +channelLink = "simplex:/channel-team" +contactLink = "simplex:/contact-alice" srv1 :: SMPServer srv1 = SMPServer "smp1.example" "5223" (C.KeyHash "\1\2\3\4") @@ -133,15 +127,19 @@ srv2 = SMPServer "smp2.example" "5223" (C.KeyHash "\5\6\7\8") sampleRecord :: NameRecord sampleRecord = NameRecord - { nrDisplayName = "alice", - -- mkNameOwner enforces the 20-byte invariant; this string is intentionally 20 ASCII bytes. + { nrName = "alice", + nrNickname = Nothing, + nrWebsite = Nothing, + nrLocation = Nothing, + nrSimplexContact = Nothing, + nrSimplexChannel = Nothing, + nrEth = Nothing, + nrBtc = Nothing, + nrXmr = Nothing, + nrDot = Nothing, + -- mkNameOwner enforces the 20-byte invariant; these strings are intentionally 20 ASCII bytes. nrOwner = either error id $ mkNameOwner "owner-bytes-1234567x", - nrChannelLinks = [], - nrContactLinks = [], - nrAdminAddress = Nothing, - nrAdminEmail = Nothing, - nrExpiry = 0, - nrIsTest = True + nrResolver = either error id $ mkNameOwner "resolver-bytes12345x" } -- AUTH from a name-capable destination relay: surfaces as SMP host AUTH