fix prepare api

This commit is contained in:
Evgeny Poberezkin
2026-07-03 09:26:10 +01:00
parent c335ee374c
commit 23a387ddf2
9 changed files with 38 additions and 23 deletions
+2 -2
View File
@@ -350,8 +350,8 @@ enum ChatCommand: ChatCmdProtocol {
case let .apiConnectPlan(userId, connLink, linkOwnerSig):
let sigStr = if let linkOwnerSig { " sig=\(encodeJSON(linkOwnerSig))" } else { "" }
return "/_connect plan \(userId) \(connLink)\(sigStr)"
case let .apiPrepareContact(userId, connLink, contactShortLinkData, verifiedDomain): return "/_prepare contact \(userId) \(connLink.connFullLink) \(connLink.connShortLink ?? "") \(encodeJSON(contactShortLinkData))" + (verifiedDomain.map { " \($0.fullDomainName)" } ?? "")
case let .apiPrepareGroup(userId, connLink, directLink, groupShortLinkData, verifiedDomain): return "/_prepare group \(userId) \(connLink.connFullLink) \(connLink.connShortLink ?? "") direct=\(onOff(directLink)) \(encodeJSON(groupShortLinkData))" + (verifiedDomain.map { " \($0.fullDomainName)" } ?? "")
case let .apiPrepareContact(userId, connLink, contactShortLinkData, verifiedDomain): return "/_prepare contact \(userId) \(connLink.cmdString)\(verifiedDomain.map{ " \($0.cmdString)" } ?? "")\(encodeJSON(contactShortLinkData))"
case let .apiPrepareGroup(userId, connLink, directLink, groupShortLinkData, verifiedDomain): return "/_prepare group \(userId) \(connLink.cmdString) direct=\(onOff(directLink))\(verifiedDomain.map{ " \($0.cmdString)" } ?? "") \(encodeJSON(groupShortLinkData))"
case let .apiChangePreparedContactUser(contactId, newUserId): return "/_set contact user @\(contactId) \(newUserId)"
case let .apiChangePreparedGroupUser(groupId, newUserId): return "/_set group user #\(groupId) \(newUserId)"
case let .apiConnectPreparedContact(contactId, incognito, mc): return "/_connect contact @\(contactId) incognito=\(onOff(incognito))\(maybeContent(mc))"
+4
View File
@@ -184,6 +184,10 @@ public struct CreatedConnLink: Decodable, Hashable {
public func simplexChatUri(short: Bool = true) -> String {
short ? (connShortLink ?? simplexChatLink(connFullLink)) : simplexChatLink(connFullLink)
}
public var cmdString: String {
connFullLink + (connShortLink.map { " \($0)"} ?? "")
}
}
public func simplexChatLink(_ uri: String) -> String {
+4
View File
@@ -5312,6 +5312,10 @@ public struct SimplexDomain: Codable, Equatable, Hashable {
return (subDomain.reversed() + [domain] + tld).joined(separator: ".")
}
public var cmdString: String {
"domain=\(fullDomainName)"
}
public init(nameTLD: SimplexTLD, domain: String, subDomain: [String]) {
self.nameTLD = nameTLD
self.domain = domain
@@ -4896,15 +4896,16 @@ data class SimplexDomain(
val subDomain: List<String>
) {
// mirrors backend fullDomainName: reverse(subDomain) + [domain] + tld
val fullDomainName: String
get() {
val tld = when (nameTLD) {
SimplexTLD.simplex -> listOf("simplex")
SimplexTLD.testing -> listOf("testing")
SimplexTLD.web -> emptyList()
}
return (subDomain.reversed() + domain + tld).joinToString(".")
val fullDomainName: String get() {
val tld = when (nameTLD) {
SimplexTLD.simplex -> listOf("simplex")
SimplexTLD.testing -> listOf("testing")
SimplexTLD.web -> emptyList()
}
return (subDomain.reversed() + domain + tld).joinToString(".")
}
val cmdString: String get() = "domain=$fullDomainName"
}
@Serializable
@@ -4073,8 +4073,8 @@ sealed class CC {
val sigStr = if (linkOwnerSig != null) " sig=${json.encodeToString(linkOwnerSig)}" else ""
"/_connect plan $userId $connLink$sigStr"
}
is APIPrepareContact -> "/_prepare contact $userId ${connLink.connFullLink} ${connLink.connShortLink ?: ""} ${json.encodeToString(contactShortLinkData)}${verifiedDomain?.let { " ${it.fullDomainName}" } ?: ""}"
is APIPrepareGroup -> "/_prepare group $userId ${connLink.connFullLink} ${connLink.connShortLink ?: ""} direct=${onOff(directLink)} ${json.encodeToString(groupShortLinkData)}${verifiedDomain?.let { " ${it.fullDomainName}" } ?: ""}"
is APIPrepareContact -> "/_prepare contact $userId ${connLink.cmdString}${verifiedDomain?.let { " ${it.cmdString}" } ?: ""} ${json.encodeToString(contactShortLinkData)}"
is APIPrepareGroup -> "/_prepare group $userId ${connLink.cmdString} direct=${onOff(directLink)}${verifiedDomain?.let { " ${it.cmdString}" } ?: ""} ${json.encodeToString(groupShortLinkData)}"
is APIChangePreparedContactUser -> "/_set contact user @$contactId $newUserId"
is APIChangePreparedGroupUser -> "/_set group user #$groupId $newUserId"
is APIConnectPreparedContact -> "/_connect contact @$contactId incognito=${onOff(incognito)}${maybeContent(msg)}"
@@ -7083,6 +7083,8 @@ data class CreatedConnLink(val connFullLink: String, val connShortLink: String?)
fun simplexChatUri(short: Boolean): String =
if (short) connShortLink ?: simplexChatLink(connFullLink)
else simplexChatLink(connFullLink)
val cmdString: String get() = connFullLink + (if (connShortLink == null) "" else " $connShortLink")
}
fun simplexChatLink(uri: String): String =
@@ -979,7 +979,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
let GroupShortLinkData {groupProfile = GroupProfile {displayName}} = groupSLinkData
ownerContact = GroupOwnerContact {contactId = contactId' ct, memberId = mId}
sendMessage cc ct $ "Joining the " <> gt <> " " <> displayName <> ""
sendChatCmd cc (APIPrepareGroup userId ccLink False groupSLinkData Nothing) >>= \case
sendChatCmd cc (APIPrepareGroup userId ccLink False Nothing groupSLinkData) >>= \case
Right (CRNewPreparedChat _ (AChat SCTGroup (Chat (GroupChat gInfo _) _ _))) -> do
let gId = groupId' gInfo
addGroupReg notifyAdminUsers st cc ct gInfo GRSProposed $ \_ -> pure ()
+2 -2
View File
@@ -530,8 +530,8 @@ data ChatCommand
| APISetConnectionIncognito Int64 IncognitoEnabled
| APIChangeConnectionUser Int64 UserId -- new user id to switch connection to
| APIConnectPlan {userId :: UserId, connectTarget :: Maybe AConnectTarget, resolveKnown :: Bool, linkOwnerSig :: Maybe LinkOwnerSig} -- Maybe AConnectTarget is used to report parsing failure as special error
| APIPrepareContact UserId ACreatedConnLink ContactShortLinkData (Maybe SimplexDomain)
| APIPrepareGroup UserId CreatedLinkContact DirectLink GroupShortLinkData (Maybe SimplexDomain)
| APIPrepareContact UserId ACreatedConnLink (Maybe SimplexDomain) ContactShortLinkData
| APIPrepareGroup UserId CreatedLinkContact DirectLink (Maybe SimplexDomain) GroupShortLinkData
| APIChangePreparedContactUser ContactId UserId
| APIChangePreparedGroupUser GroupId UserId
| APIConnectPreparedContact {contactId :: ContactId, incognito :: IncognitoEnabled, msgContent_ :: Maybe MsgContent}
+8 -8
View File
@@ -56,7 +56,7 @@ import Data.Type.Equality
import qualified Data.UUID as UUID
import qualified Data.UUID.V4 as V4
import Simplex.Chat.Library.Subscriber
import Simplex.Chat.Badges (BadgeCredential (..), LocalBadge (..), ProofPresHeader (..), maxXFTPFileSize, mkBadgeStatus, verifyCredential)
import Simplex.Chat.Badges (BadgeCredential (..), LocalBadge (..), maxXFTPFileSize, mkBadgeStatus, verifyCredential)
import Simplex.Chat.Names (SimplexDomainProof (..), SimplexDomainClaim (..), claimDomain, mkDomainClaim)
import Simplex.Chat.Call
import Simplex.Chat.Controller
@@ -96,7 +96,7 @@ import Simplex.Chat.Web (webPreviewWorker)
import Simplex.FileTransfer.Description (FileDescriptionURI (..), maxFileSizeHard)
import Simplex.Messaging.Agent
import Simplex.Messaging.Agent.Env.SQLite (ServerCfg (..), ServerRoles (..), allRoles)
import Simplex.Messaging.Agent.Protocol hiding (ConnectTarget (..))
import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Agent.Store.Entity
import Simplex.Messaging.Agent.Store.Interface (execSQL)
import Simplex.Messaging.Agent.Store.Shared (upMigration)
@@ -2061,7 +2061,7 @@ processChatCommand cxt nm = \case
APIConnectPlan userId (Just ct) resolveKnown linkOwnerSig_ -> withUserId userId $ \user ->
uncurry (CRConnectionPlan user) <$> connectPlan user ct resolveKnown linkOwnerSig_
APIConnectPlan _ Nothing _ _ -> throwChatError CEInvalidConnReq
APIPrepareContact userId accLink contactSLinkData verifiedDomain -> withUserId userId $ \user -> do
APIPrepareContact userId accLink verifiedDomain contactSLinkData -> withUserId userId $ \user -> do
let ContactShortLinkData {profile, message, business} = contactSLinkData
welcomeSharedMsgId <- forM message $ \_ -> getSharedMsgId
case accLink of
@@ -2096,7 +2096,7 @@ processChatCommand cxt nm = \case
Just (AChatItem SCTDirect dir _ ci) -> Chat cInfo [CChatItem dir ci] emptyChatStats {unreadCount = 1, minUnreadItemId = chatItemId' ci}
_ -> Chat cInfo [] emptyChatStats
pure $ CRNewPreparedChat user $ AChat SCTDirect chat
APIPrepareGroup userId ccLink direct groupSLinkData verifiedDomain -> withUserId userId $ \user -> do
APIPrepareGroup userId ccLink direct verifiedDomain groupSLinkData -> withUserId userId $ \user -> do
let GroupShortLinkData {groupProfile = GroupProfile {description}} = groupSLinkData
welcomeSharedMsgId <- forM description $ \_ -> getSharedMsgId
(gInfo, hostMember_) <- preparedGroupFromLink user ccLink direct groupSLinkData welcomeSharedMsgId (True <$ verifiedDomain)
@@ -4340,7 +4340,7 @@ processChatCommand cxt nm = \case
throwError e
where
prepareChannelGroup =
processChatCommand cxt nm (APIPrepareGroup userId ccl False gld vName) >>= \case
processChatCommand cxt nm (APIPrepareGroup userId ccl False vName gld) >>= \case
CRNewPreparedChat _ (AChat SCTGroup (Chat (GroupChat gInfo _) _ _)) -> pure gInfo
_ -> throwChatError $ CEException "joinChannelViaRelays: unexpected response from APIPrepareGroup"
deletePreparedChannel groupId = do
@@ -4349,7 +4349,7 @@ processChatCommand cxt nm = \case
withFastStore' $ \db -> deleteGroup db user gInfo
connectContactViaName :: ContactShortLinkData -> Maybe SimplexDomain -> CM ChatResponse
connectContactViaName sld vName =
processChatCommand cxt nm (APIPrepareContact userId ccLink sld vName) >>= \case
processChatCommand cxt nm (APIPrepareContact userId ccLink vName sld) >>= \case
CRNewPreparedChat _ (AChat SCTDirect (Chat (DirectChat Contact {contactId}) _ _)) ->
processChatCommand cxt nm (APIConnectPreparedContact contactId incognito Nothing)
_ -> throwChatError $ CEException "connectContactViaName: unexpected response from APIPrepareContact"
@@ -5450,8 +5450,8 @@ chatCommandP =
"/_contacts " *> (APIListContacts <$> A.decimal),
"/contacts" $> ListContacts,
"/_connect plan " *> (APIConnectPlan <$> A.decimal <* A.space <*> ((Just <$> strP) <|> A.takeTill (== ' ') $> Nothing) <*> ((" resolve=" *> onOffP) <|> pure False) <*> optional (" sig=" *> jsonP)),
"/_prepare contact " *> (APIPrepareContact <$> A.decimal <* A.space <*> connLinkP <* A.space <*> jsonP <*> optional (A.space *> strP)),
"/_prepare group " *> (APIPrepareGroup <$> A.decimal <* A.space <*> connLinkP' <*> (" direct=" *> onOffP <|> pure True) <* A.space <*> jsonP <*> optional (A.space *> strP)),
"/_prepare contact " *> (APIPrepareContact <$> A.decimal <* A.space <*> connLinkP <*> optional (" domain=" *> strP) <* A.space <*> jsonP),
"/_prepare group " *> (APIPrepareGroup <$> A.decimal <* A.space <*> connLinkP' <*> (" direct=" *> onOffP <|> pure True) <*> optional (" domain=" *> strP) <* A.space <*> jsonP),
"/_set contact user @" *> (APIChangePreparedContactUser <$> A.decimal <* A.space <*> A.decimal),
"/_set group user #" *> (APIChangePreparedGroupUser <$> A.decimal <* A.space <*> A.decimal),
"/_connect contact @" *> (APIConnectPreparedContact <$> A.decimal <*> incognitoOnOffP <*> optional (A.space *> msgContentP)),
@@ -1143,6 +1143,10 @@ Plan:
Query: INSERT INTO users DEFAULT VALUES
Plan:
Query: SELECT 1 FROM connections WHERE conn_id = ? AND deleted_at_wait_delivery < ? LIMIT 1
Plan:
SEARCH connections USING PRIMARY KEY (conn_id=?)
Query: SELECT 1 FROM encrypted_rcv_message_hashes WHERE conn_id = ? AND hash = ? LIMIT 1
Plan:
SEARCH encrypted_rcv_message_hashes USING COVERING INDEX idx_encrypted_rcv_message_hashes_hash (conn_id=? AND hash=?)