diff --git a/bots/src/API/Docs/Commands.hs b/bots/src/API/Docs/Commands.hs index 917226873b..3cfedd11e2 100644 --- a/bots/src/API/Docs/Commands.hs +++ b/bots/src/API/Docs/Commands.hs @@ -306,6 +306,7 @@ undocumentedCommands = "APIActivateChat", "APIAddGroupShortLink", "APIAddMyAddressShortLink", + "APIAddRelays", "APIArchiveReceivedReports", "APICallStatus", "APIChangeConnectionUser", @@ -324,6 +325,7 @@ undocumentedCommands = "APICreateChatItems", "APICreateChatTag", "APICreateMemberContact", + "APICreateRelayedGroupLink", "APISendMemberContactInvitation", "APIAcceptMemberContact", "APIDeleteChatTag", diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 025ea7fc0e..3c637fb3b6 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -745,6 +745,7 @@ data ChatResponse | CRGroupProfile {user :: User, groupInfo :: GroupInfo} | CRGroupDescription {user :: User, groupInfo :: GroupInfo} -- only used in CLI | CRGroupLinkCreated {user :: User, groupInfo :: GroupInfo, groupLink :: GroupLink} + | CRGroupRelaysAdded {user :: User, groupInfo :: GroupInfo, groupLink :: GroupLink, groupRelays :: [GroupRelay]} | CRGroupLink {user :: User, groupInfo :: GroupInfo, groupLink :: GroupLink} | CRGroupLinkDeleted {user :: User, groupInfo :: GroupInfo} | CRNewMemberContact {user :: User, contact :: Contact, groupInfo :: GroupInfo, member :: GroupMember} diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index cee34a8536..ff1be20c2b 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -2702,16 +2702,29 @@ processChatCommand vr nm = \case _sLnk' <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a nm connId SCMContact userData' (Just crClientData)) -- ^^^ gVar <- asks random - gLink <- withFastStore $ \db -> createGroupLink db gVar user gInfo connId ccLink' groupLinkId GRMember subMode - -- TODO - if autoChooseRelays: - -- TODO - choose group relays from configured relays (chat_relays) - -- TODO - addRelays - ok_ - APIAddRelays groupId _relayIds -> withUser $ \_user -> withGroupLock "addRelays" groupId $ do - -- TODO [relays] owner: add user chosen relays - -- TODO - get group link - -- TODO - addRelays - ok_ + (gLink, gInfo') <- withFastStore $ \db -> do + gLink <- createGroupLink db gVar user gInfo connId ccLink' groupLinkId GRMember subMode + gInfo' <- updateGroupProfile db user gInfo groupProfile' + pure (gLink, gInfo') + if autoChooseRelays + then do + relayIds <- chooseRelays + relays <- addRelays user gInfo' relayIds + pure $ CRGroupRelaysAdded user gInfo' gLink relays + else + pure $ CRGroupLinkCreated user gInfo' gLink + where + chooseRelays = do + -- TODO - load configured relays (chat_relays) + -- TODO - select 3 random relays + pure [] + APIAddRelays groupId relayIds -> withUser $ \user -> withGroupLock "addRelays" groupId $ do + (gInfo, gLink) <- withFastStore $ \db -> do + gInfo <- getGroupInfo db vr user groupId + gLink <- getGroupLink db user gInfo + pure (gInfo, gLink) + relays <- addRelays user gInfo $ L.toList relayIds + pure $ CRGroupRelaysAdded user gInfo gLink relays APIGroupLinkMemberRole groupId mRole' -> withUser $ \user -> withGroupLock "groupLinkMemberRole" groupId $ do gInfo <- withFastStore $ \db -> getGroupInfo db vr user groupId gLnk@GroupLink {acceptMemberRole} <- withFastStore $ \db -> getGroupLink db user gInfo @@ -3554,13 +3567,13 @@ processChatCommand vr nm = \case toView $ CEvtNewChatItems user [AChatItem SCTDirect SMDSnd (DirectChat ct) ci] forM_ (timed_ >>= timedDeleteAt') $ startProximateTimedItemThread user (ChatRef CTDirect contactId Nothing, chatItemId' ci) - addRelays :: User -> GroupInfo -> ShortLinkContact -> [Int64] -> CM () - addRelays _user _gInfo _groupLink _relayIds = do + addRelays :: User -> GroupInfo -> [Int64] -> CM [GroupRelay] + addRelays _user _gInfo _relayIds = do -- TODO [relays] owner: send contact requests to relays -- TODO - create relay member connections, relay records (group_relays), relay status: RSNew -- TODO - send requests to relays: INV message - XGrpRelayInv, relay status: RSInvited -- TODO - agent joinConnectionAsync for contact links (currently prohibited) - pure () + pure [] drgRandomBytes :: Int -> CM ByteString drgRandomBytes n = asks random >>= atomically . C.randomBytes n privateGetUser :: UserId -> CM User diff --git a/src/Simplex/Chat/Store/Groups.hs b/src/Simplex/Chat/Store/Groups.hs index f970c2e8fd..715741676e 100644 --- a/src/Simplex/Chat/Store/Groups.hs +++ b/src/Simplex/Chat/Store/Groups.hs @@ -1762,7 +1762,7 @@ createMemberConnection_ db userId groupMemberId agentConnId chatV peerChatVRange createConnection_ db userId ConnMember (Just groupMemberId) agentConnId ConnNew chatV peerChatVRange viaContact Nothing Nothing connLevel currentTs subMode PQSupportOff updateGroupProfile :: DB.Connection -> User -> GroupInfo -> GroupProfile -> ExceptT StoreError IO GroupInfo -updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, shortDescr, description, image, groupPreferences, memberAdmission} +updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, groupProfile = GroupProfile {displayName}} p'@GroupProfile {displayName = newName, fullName, shortDescr, description, image, groupLink, groupPreferences, memberAdmission} | displayName == newName = liftIO $ do currentTs <- getCurrentTime updateGroupProfile_ currentTs @@ -1780,14 +1780,16 @@ updateGroupProfile db user@User {userId} g@GroupInfo {groupId, localDisplayName, db [sql| UPDATE group_profiles - SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, preferences = ?, member_admission = ?, updated_at = ? + SET display_name = ?, full_name = ?, short_descr = ?, description = ?, image = ?, group_link = ?, preferences = ?, member_admission = ?, updated_at = ? WHERE group_profile_id IN ( SELECT group_profile_id FROM groups WHERE user_id = ? AND group_id = ? ) |] - (newName, fullName, shortDescr, description, image, groupPreferences, memberAdmission, currentTs, userId, groupId) + ( (newName, fullName, shortDescr, description, image, groupLink) + :. (groupPreferences, memberAdmission, currentTs, userId, groupId) + ) updateGroup_ ldn currentTs = do DB.execute db