core: add fields to chat relay profiles; remove unique name requirement; update relay profile in relay address link data (#6743)

* core: add fields to chat relay profiles

* wip

* wip

* fix

* fix

* fix

* enable tests

* schema

* api

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
This commit is contained in:
Evgeny
2026-04-03 13:42:43 +01:00
committed by GitHub
parent 0ca7cdaf1d
commit 8167f7c2ab
29 changed files with 153 additions and 131 deletions
+10 -5
View File
@@ -1544,7 +1544,7 @@ processChatCommand vr nm = \case
processChatCommand vr nm $ APISetUserServers userId $ L.map (updatedRelays relays') userServers
where
aUserRelay :: CLINewRelay -> AUserChatRelay
aUserRelay CLINewRelay {address, name} = AUCR SDBNew $ newChatRelay name [""] address
aUserRelay CLINewRelay {address, name} = AUCR SDBNew $ newChatRelay (relayProfileFromName name) [""] address
APIGetServerOperators -> CRServerOperatorConditions <$> withFastStore getServerOperators
APISetServerOperators operators -> do
as <- asks randomAgentServers
@@ -2202,7 +2202,7 @@ processChatCommand vr nm = \case
CRContactsList user <$> withFastStore' (\db -> getUserContacts db vr user)
ListContacts -> withUser $ \User {userId} ->
processChatCommand vr nm $ APIListContacts userId
APICreateMyAddress userId -> withUserId userId $ \user@User {profile = LocalProfile {displayName}, userChatRelay} -> do
APICreateMyAddress userId -> withUserId userId $ \user@User {userChatRelay} -> do
withFastStore' (\db -> runExceptT $ getUserAddress db user) >>= \case
Left SEUserContactLinkNotFound -> pure ()
Left e -> throwError $ ChatErrorStore e
@@ -2210,7 +2210,7 @@ processChatCommand vr nm = \case
subMode <- chatReadVar subscriptionMode
-- TODO [relays] relay: add identity, key to link data?
let userData
| isTrue userChatRelay = encodeShortLinkData $ RelayAddressLinkData {relayProfile = RelayProfile {name = displayName}}
| isTrue userChatRelay = relayShortLinkData (userProfileDirect user Nothing Nothing True)
| otherwise = contactShortLinkData (userProfileDirect user Nothing Nothing True) Nothing
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
-- TODO [certs rcv]
@@ -3583,11 +3583,13 @@ processChatCommand vr nm = \case
fmap $ \SndMessage {msgId, msgBody} ->
(conn, MsgFlags {notification = hasNotification XInfo_}, (vrValue msgBody, [msgId]))
setMyAddressData :: User -> UserContactLink -> CM UserContactLink
setMyAddressData user ucl@UserContactLink {userContactLinkId, connLinkContact = CCLink connFullLink _sLnk_, addressSettings} = do
setMyAddressData user@User {userChatRelay} ucl@UserContactLink {userContactLinkId, connLinkContact = CCLink connFullLink _sLnk_, addressSettings} = do
conn <- withFastStore $ \db -> getUserAddressConnection db vr user
let shortLinkProfile = userProfileDirect user Nothing Nothing True
-- TODO [short links] do not save address to server if data did not change, spinners, error handling
userData = contactShortLinkData shortLinkProfile $ Just addressSettings
userData
| isTrue userChatRelay = relayShortLinkData shortLinkProfile
| otherwise = contactShortLinkData shortLinkProfile $ Just addressSettings
userLinkData = UserContactLinkData UserContactData {direct = True, owners = [], relays = [], userData}
sLnk <- shortenShortLink' =<< withAgent (\a -> setConnShortLink a nm (aConnId conn) SCMContact userLinkData Nothing)
withFastStore' $ \db -> setUserContactLinkShortLink db userContactLinkId sLnk
@@ -4063,6 +4065,9 @@ processChatCommand vr nm = \case
business = maybe False businessAddress settings
contactData = ContactShortLinkData p msg business
in encodeShortLinkData contactData
relayShortLinkData :: Profile -> UserLinkData
relayShortLinkData Profile {displayName, fullName, shortDescr, image} =
encodeShortLinkData $ RelayAddressLinkData {relayProfile = RelayProfile {displayName, fullName, shortDescr, image}}
updatePCCShortLinkData :: PendingContactConnection -> Profile -> CM (Maybe ShortLinkInvitation)
updatePCCShortLinkData conn@PendingContactConnection {connLinkInv} profile =
forM (connShortLink =<< connLinkInv) $ \_ -> do
+7 -11
View File
@@ -331,17 +331,17 @@ newUserServer_ :: Bool -> Bool -> ProtoServerWithAuth p -> NewUserServer p
newUserServer_ preset enabled server =
UserServer {serverId = DBNewEntity, server, preset, tested = Nothing, enabled, deleted = False}
presetChatRelay :: Bool -> Text -> [Text] -> ShortLinkContact -> NewUserChatRelay
presetChatRelay :: Bool -> RelayProfile -> [Text] -> ShortLinkContact -> NewUserChatRelay
presetChatRelay = newChatRelay_ True
{-# INLINE presetChatRelay #-}
newChatRelay :: Text -> [Text] -> ShortLinkContact -> NewUserChatRelay
newChatRelay :: RelayProfile -> [Text] -> ShortLinkContact -> NewUserChatRelay
newChatRelay = newChatRelay_ False True
{-# INLINE newChatRelay #-}
newChatRelay_ :: Bool -> Bool -> Text -> [Text] -> ShortLinkContact -> NewUserChatRelay
newChatRelay_ preset enabled name domains !address =
UserChatRelay {chatRelayId = DBNewEntity, address, relayProfile = RelayProfile {name}, domains, preset, tested = Nothing, enabled, deleted = False}
newChatRelay_ :: Bool -> Bool -> RelayProfile -> [Text] -> ShortLinkContact -> NewUserChatRelay
newChatRelay_ preset enabled relayProfile domains !address =
UserChatRelay {chatRelayId = DBNewEntity, address, relayProfile, domains, preset, tested = Nothing, enabled, deleted = False}
-- This function should be used inside DB transaction to update conditions in the database
-- it evaluates to (current conditions, and conditions to add)
@@ -507,7 +507,6 @@ data UserServersError
| USEStorageMissing {protocol :: AProtocolType, user :: Maybe User}
| USEProxyMissing {protocol :: AProtocolType, user :: Maybe User}
| USEDuplicateServer {protocol :: AProtocolType, duplicateServer :: Text, duplicateHost :: TransportHost}
| USEDuplicateChatRelayName {duplicateChatRelay :: Text}
| USEDuplicateChatRelayAddress {duplicateChatRelay :: Text, duplicateAddress :: ShortLinkContact}
deriving (Show)
@@ -544,11 +543,8 @@ validateUserServers curr others = (currUserErrs <> concatMap otherUserErrs other
chatRelayErrs uss = concatMap duplicateErrs_ cRelays
where
cRelays = filter (\(AUCR _ UserChatRelay {deleted}) -> not deleted) $ userChatRelays uss
duplicateErrs_ (AUCR _ UserChatRelay {relayProfile = RelayProfile {name}, address}) =
[USEDuplicateChatRelayName name | name `elem` duplicateNames]
<> [USEDuplicateChatRelayAddress name address | address `elem` duplicateAddresses]
duplicateNames = snd $ foldl' addDuplicate (S.empty, S.empty) allNames
allNames = map (\(AUCR _ UserChatRelay {relayProfile = RelayProfile {name}}) -> name) cRelays
duplicateErrs_ (AUCR _ UserChatRelay {relayProfile = RelayProfile {displayName}, address}) =
[USEDuplicateChatRelayAddress displayName address | address `elem` duplicateAddresses]
duplicateAddresses = snd $ foldl' addAddress ([], []) allAddresses
allAddresses = map (\(AUCR _ UserChatRelay {address}) -> address) cRelays
addAddress :: ([ShortLinkContact], [ShortLinkContact]) -> ShortLinkContact -> ([ShortLinkContact], [ShortLinkContact])
+4 -3
View File
@@ -8,6 +8,7 @@ module Simplex.Chat.Operators.Presets where
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as L
import Simplex.Chat.Operators
import Simplex.Chat.Protocol (relayProfileFromName)
import Simplex.Messaging.Agent.Env.SQLite (ServerRoles (..), allRoles)
import Simplex.Messaging.Agent.Store.Entity
import Simplex.Messaging.Encoding.String
@@ -91,9 +92,9 @@ disabledSimplexChatSMPServers =
-- TODO [relays] real chat relays
simplexChatRelays :: [NewUserChatRelay]
simplexChatRelays =
[ presetChatRelay True "chat_relay_1" ["simplex.im"] (either error id $ strDecode "https://smp111.simplex.im/r#Pz9qz7ZVljMofoRxiDDpL_w2DZSazK8IgafxqnWKv6Y"),
presetChatRelay True "chat_relay_2" ["simplex.im"] (either error id $ strDecode "https://smp222.simplex.im/r#Pz9qz7ZVljMofoRxiDDpL_w2DZSazK8IgafxqnWKv6Y"),
presetChatRelay True "chat_relay_3" ["simplex.im"] (either error id $ strDecode "https://smp333.simplex.im/r#Pz9qz7ZVljMofoRxiDDpL_w2DZSazK8IgafxqnWKv6Y")
[ presetChatRelay True (relayProfileFromName "chat_relay_1") ["simplex.im"] (either error id $ strDecode "https://smp111.simplex.im/r#Pz9qz7ZVljMofoRxiDDpL_w2DZSazK8IgafxqnWKv6Y"),
presetChatRelay True (relayProfileFromName "chat_relay_2") ["simplex.im"] (either error id $ strDecode "https://smp222.simplex.im/r#Pz9qz7ZVljMofoRxiDDpL_w2DZSazK8IgafxqnWKv6Y"),
presetChatRelay True (relayProfileFromName "chat_relay_3") ["simplex.im"] (either error id $ strDecode "https://smp333.simplex.im/r#Pz9qz7ZVljMofoRxiDDpL_w2DZSazK8IgafxqnWKv6Y")
]
fluxSMPServers :: [NewUserServer 'PSMP]
+12 -1
View File
@@ -1455,11 +1455,22 @@ data RelayShortLinkData = RelayShortLinkData
$(JQ.deriveJSON defaultJSON ''RelayShortLinkData)
data RelayProfile = RelayProfile {name :: ContactName}
data RelayProfile = RelayProfile
{ displayName :: ContactName,
fullName :: Text,
shortDescr :: Maybe Text,
image :: Maybe ImageData
}
deriving (Eq, Show)
$(JQ.deriveJSON defaultJSON ''RelayProfile)
toRelayProfile :: (ContactName, Text, Maybe Text, Maybe ImageData) -> RelayProfile
toRelayProfile (displayName, fullName, shortDescr, image) = RelayProfile {displayName, fullName, shortDescr, image}
relayProfileFromName :: ContactName -> RelayProfile
relayProfileFromName displayName = RelayProfile {displayName, fullName = "", shortDescr = Nothing, image = Nothing}
data RelayAddressLinkData = RelayAddressLinkData {relayProfile :: RelayProfile}
deriving (Show)
+6 -6
View File
@@ -1329,21 +1329,21 @@ groupRelayQuery :: Query
groupRelayQuery =
[sql|
SELECT gr.group_relay_id, gr.group_member_id,
cr.chat_relay_id, cr.address, cr.name, cr.domains, cr.preset, cr.tested, cr.enabled, cr.deleted,
cr.chat_relay_id, cr.address, cr.display_name, cr.full_name, cr.short_descr, cr.image, cr.domains, cr.preset, cr.tested, cr.enabled, cr.deleted,
gr.relay_status, gr.relay_link
FROM group_relays gr
JOIN chat_relays cr ON cr.chat_relay_id = gr.chat_relay_id
|]
toGroupRelay :: (Int64, GroupMemberId, DBEntityId, ShortLinkContact, Text, Text, BoolInt, Maybe BoolInt, BoolInt, BoolInt, RelayStatus, Maybe ShortLinkContact) -> GroupRelay
toGroupRelay (groupRelayId, groupMemberId, chatRelayId, address, name, domains, BI preset, tested, BI enabled, BI deleted, relayStatus, relayLink) =
let userChatRelay = UserChatRelay {chatRelayId, address, relayProfile = RelayProfile {name}, domains = T.splitOn "," domains, preset, tested = unBI <$> tested, enabled, deleted}
toGroupRelay :: (Int64, GroupMemberId, DBEntityId, ShortLinkContact, Text, Text, Maybe Text, Maybe ImageData, Text, BoolInt) :. (Maybe BoolInt, BoolInt, BoolInt, RelayStatus, Maybe ShortLinkContact) -> GroupRelay
toGroupRelay ((groupRelayId, groupMemberId, chatRelayId, address, displayName, fullName, shortDescr, image, domains, BI preset) :. (tested, BI enabled, BI deleted, relayStatus, relayLink)) =
let userChatRelay = UserChatRelay {chatRelayId, address, relayProfile = toRelayProfile (displayName, fullName, shortDescr, image), domains = T.splitOn "," domains, preset, tested = unBI <$> tested, enabled, deleted}
in GroupRelay {groupRelayId, groupMemberId, userChatRelay, relayStatus, relayLink}
createRelayForOwner :: DB.Connection -> VersionRangeChat -> TVar ChaChaDRG -> User -> GroupInfo -> UserChatRelay -> ExceptT StoreError IO GroupMember
createRelayForOwner db vr gVar user@User {userId, userContactId} GroupInfo {groupId, membership} UserChatRelay {relayProfile = RelayProfile {name}} = do
createRelayForOwner db vr gVar user@User {userId, userContactId} GroupInfo {groupId, membership} UserChatRelay {relayProfile = RelayProfile {displayName}} = do
currentTs <- liftIO getCurrentTime
let relayProfile = profileFromName name
let relayProfile = profileFromName displayName
(localDisplayName, memProfileId) <- createNewMemberProfile_ db user relayProfile currentTs
groupMemberId <- createWithRandomId' db gVar $ \memId -> runExceptT $ do
indexInGroup <- getUpdateNextIndexInGroup_ db groupId
@@ -13,7 +13,10 @@ m20260222_chat_relays =
CREATE TABLE chat_relays(
chat_relay_id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
address BYTEA NOT NULL,
name TEXT NOT NULL,
display_name TEXT NOT NULL,
full_name TEXT NOT NULL DEFAULT '',
short_descr TEXT,
image TEXT,
domains TEXT NOT NULL,
preset SMALLINT NOT NULL DEFAULT 0,
tested SMALLINT,
@@ -25,7 +28,6 @@ CREATE TABLE chat_relays(
);
CREATE INDEX idx_chat_relays_user_id ON chat_relays(user_id);
CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON chat_relays(user_id, address);
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON chat_relays(user_id, name);
ALTER TABLE users ADD COLUMN is_user_chat_relay SMALLINT NOT NULL DEFAULT 0;
@@ -111,7 +113,6 @@ DROP TABLE group_relays;
DROP INDEX idx_chat_relays_user_id;
DROP INDEX idx_chat_relays_user_id_address;
DROP INDEX idx_chat_relays_user_id_name;
DROP TABLE chat_relays;
ALTER TABLE group_members
@@ -363,7 +363,10 @@ ALTER TABLE test_chat_schema.chat_items ALTER COLUMN chat_item_id ADD GENERATED
CREATE TABLE test_chat_schema.chat_relays (
chat_relay_id bigint NOT NULL,
address bytea NOT NULL,
name text NOT NULL,
display_name text NOT NULL,
full_name text DEFAULT ''::text NOT NULL,
short_descr text,
image text,
domains text NOT NULL,
preset smallint DEFAULT 0 NOT NULL,
tested smallint,
@@ -2027,10 +2030,6 @@ CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON test_chat_schema.chat_rel
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON test_chat_schema.chat_relays USING btree (user_id, name);
CREATE INDEX idx_chat_tags_chats_chat_tag_id ON test_chat_schema.chat_tags_chats USING btree (chat_tag_id);
+15 -15
View File
@@ -626,15 +626,15 @@ getChatRelays db User {userId} =
<$> DB.query
db
[sql|
SELECT chat_relay_id, address, name, domains, preset, tested, enabled
SELECT chat_relay_id, address, display_name, full_name, short_descr, image, domains, preset, tested, enabled
FROM chat_relays
WHERE user_id = ? AND deleted = 0
|]
(Only userId)
toChatRelay :: (DBEntityId, ShortLinkContact, Text, Text, BoolInt, Maybe BoolInt, BoolInt) -> UserChatRelay
toChatRelay (chatRelayId, address, name, domains, BI preset, tested, BI enabled) =
UserChatRelay {chatRelayId, address, relayProfile = RelayProfile {name}, domains = T.splitOn "," domains, preset, tested = unBI <$> tested, enabled, deleted = False}
toChatRelay :: (DBEntityId, ShortLinkContact, Text, Text, Maybe Text, Maybe ImageData, Text, BoolInt, Maybe BoolInt, BoolInt) -> UserChatRelay
toChatRelay (chatRelayId, address, displayName, fullName, shortDescr, image, domains, BI preset, tested, BI enabled) =
UserChatRelay {chatRelayId, address, relayProfile = toRelayProfile (displayName, fullName, shortDescr, image), domains = T.splitOn "," domains, preset, tested = unBI <$> tested, enabled, deleted = False}
getChatRelayById :: DB.Connection -> User -> Int64 -> ExceptT StoreError IO UserChatRelay
getChatRelayById db User {userId} relayId =
@@ -642,38 +642,38 @@ getChatRelayById db User {userId} relayId =
DB.query
db
[sql|
SELECT chat_relay_id, address, name, domains, preset, tested, enabled
SELECT chat_relay_id, address, display_name, full_name, short_descr, image, domains, preset, tested, enabled
FROM chat_relays
WHERE user_id = ? AND chat_relay_id = ? AND deleted = 0
|]
(userId, relayId)
insertChatRelay :: DB.Connection -> User -> UTCTime -> NewUserChatRelay -> IO UserChatRelay
insertChatRelay db User {userId} ts relay@UserChatRelay {address, relayProfile = RelayProfile {name}, domains, preset, tested, enabled} = do
insertChatRelay db User {userId} ts relay@UserChatRelay {address, relayProfile = RelayProfile {displayName, fullName, shortDescr, image}, domains, preset, tested, enabled} = do
crId <-
fromOnly . head
<$> DB.query
db
[sql|
INSERT INTO chat_relays
(address, name, domains, preset, tested, enabled, user_id, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?)
(address, display_name, full_name, short_descr, image, domains, preset, tested, enabled, user_id, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?)
RETURNING chat_relay_id
|]
(address, name, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, userId, ts, ts)
((address, displayName, fullName, shortDescr, image, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, userId) :. (ts, ts))
pure (relay :: NewUserChatRelay) {chatRelayId = DBEntityId crId}
updateChatRelay :: DB.Connection -> UTCTime -> UserChatRelay -> IO ()
updateChatRelay db ts UserChatRelay {chatRelayId, address, relayProfile = RelayProfile {name}, domains, preset, tested, enabled} =
updateChatRelay db ts UserChatRelay {chatRelayId, address, relayProfile = RelayProfile {displayName, fullName, shortDescr, image}, domains, preset, tested, enabled} =
DB.execute
db
[sql|
UPDATE chat_relays
SET address = ?, name = ?, domains = ?,
SET address = ?, display_name = ?, full_name = ?, short_descr = ?, image = ?, domains = ?,
preset = ?, tested = ?, enabled = ?, updated_at = ?
WHERE chat_relay_id = ?
|]
(address, name, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, ts, chatRelayId)
((address, displayName, fullName, shortDescr, image, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, ts) :. Only chatRelayId)
getServerOperators :: DB.Connection -> ExceptT StoreError IO ServerOperatorConditions
getServerOperators db = do
@@ -948,15 +948,15 @@ setUserServers' db user@User {userId} ts UpdatedUserOperatorServers {operator, s
| otherwise -> Just relay <$ updateChatRelay db ts relay
-- Un-delete soft-deleted relay, updating name and settings but keeping the address unchanged.
undeleteRelay :: Int64 -> NewUserChatRelay -> IO ()
undeleteRelay existingId UserChatRelay {relayProfile = RelayProfile {name = nm}, domains, preset, tested, enabled} =
undeleteRelay existingId UserChatRelay {relayProfile = RelayProfile {displayName, fullName, shortDescr, image}, domains, preset, tested, enabled} =
DB.execute db
[sql|
UPDATE chat_relays
SET name = ?, domains = ?,
SET display_name = ?, full_name = ?, short_descr = ?, image = ?, domains = ?,
preset = ?, tested = ?, enabled = ?, deleted = 0, updated_at = ?
WHERE chat_relay_id = ?
|]
(nm, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, ts, existingId)
(displayName, fullName, shortDescr, image, T.intercalate "," domains, BI preset, BI <$> tested, BI enabled, ts, existingId)
createCall :: DB.Connection -> User -> Call -> UTCTime -> IO ()
createCall db user@User {userId} Call {contactId, callId, callUUID, chatItemId, callState} callTs = do
@@ -24,7 +24,10 @@ m20260222_chat_relays =
CREATE TABLE chat_relays(
chat_relay_id INTEGER PRIMARY KEY,
address BLOB NOT NULL,
name TEXT NOT NULL,
display_name TEXT NOT NULL,
full_name TEXT NOT NULL DEFAULT '',
short_descr TEXT,
image TEXT,
domains TEXT NOT NULL,
preset INTEGER NOT NULL DEFAULT 0,
tested INTEGER,
@@ -36,7 +39,6 @@ CREATE TABLE chat_relays(
) STRICT;
CREATE INDEX idx_chat_relays_user_id ON chat_relays(user_id);
CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON chat_relays(user_id, address);
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON chat_relays(user_id, name);
ALTER TABLE users ADD COLUMN is_user_chat_relay INTEGER NOT NULL DEFAULT 0;
@@ -116,7 +118,6 @@ DROP TABLE group_relays;
DROP INDEX idx_chat_relays_user_id;
DROP INDEX idx_chat_relays_user_id_address;
DROP INDEX idx_chat_relays_user_id_name;
DROP TABLE chat_relays;
ALTER TABLE group_members DROP COLUMN relay_link;
@@ -750,7 +750,10 @@ CREATE TABLE connections_sync(
CREATE TABLE chat_relays(
chat_relay_id INTEGER PRIMARY KEY,
address BLOB NOT NULL,
name TEXT NOT NULL,
display_name TEXT NOT NULL,
full_name TEXT NOT NULL DEFAULT '',
short_descr TEXT,
image TEXT,
domains TEXT NOT NULL,
preset INTEGER NOT NULL DEFAULT 0,
tested INTEGER,
@@ -1270,7 +1273,6 @@ CREATE UNIQUE INDEX idx_chat_relays_user_id_address ON chat_relays(
user_id,
address
);
CREATE UNIQUE INDEX idx_chat_relays_user_id_name ON chat_relays(user_id, name);
CREATE INDEX idx_group_relays_group_id ON group_relays(group_id);
CREATE UNIQUE INDEX idx_group_relays_group_member_id ON group_relays(
group_member_id
+2 -2
View File
@@ -1579,7 +1579,7 @@ viewUserServers UserOperatorServers {operator, smpServers, xftpServers, chatRela
[" Chat relays"] <> map (plain . (" " <>) . viewChatRelay) cRelays
| otherwise = []
where
viewChatRelay UserChatRelay {relayProfile = RelayProfile {name}, address, preset, tested, enabled} = name <> relayAddress <> relayInfo
viewChatRelay UserChatRelay {relayProfile = RelayProfile {displayName, fullName, shortDescr}, address, preset, tested, enabled} = displayName <> optionalFullName displayName fullName shortDescr <> relayAddress <> relayInfo
where
relayAddress = ": " <> safeDecodeUtf8 (strEncode address)
relayInfo = if null relayInfo_ then "" else parens $ T.intercalate ", " relayInfo_
@@ -1619,7 +1619,7 @@ viewRelayTestResult relayProfile_ = \case
Just RelayTestFailure {rtfStep, rtfError} ->
["relay test failed at " <> plain (show rtfStep) <> ", error: " <> plain (show rtfError)]
Nothing -> case relayProfile_ of
Just RelayProfile {name} -> ["relay test passed, profile: " <> plain (T.unpack name)]
Just RelayProfile {displayName, fullName, shortDescr} -> ["relay test passed, profile: " <> ttyFullName displayName fullName shortDescr]
Nothing -> ["relay test passed"]
viewServerOperators :: [ServerOperator] -> Maybe UsageConditionsAction -> [StyledString]