Compare commits

...

10 Commits

Author SHA1 Message Date
Evgeny Poberezkin ceecaf6592 simplexmq 2024-07-29 19:36:51 +01:00
Evgeny Poberezkin fb831439e9 ios: load chats and refresh call invitations before chat is started 2024-07-29 19:35:48 +01:00
Evgeny Poberezkin 018d9a1064 core: allow getting call invitations and notificationn token when chat is stopped 2024-07-29 19:17:44 +01:00
Evgeny Poberezkin 4b382841a1 check chat is running 2024-07-29 18:51:01 +01:00
Evgeny Poberezkin 6834138270 fix race in the tests 2024-07-29 18:19:01 +01:00
Evgeny Poberezkin bf83ba40a3 simplexmq 2024-07-29 17:39:49 +01:00
Evgeny Poberezkin ca166d7f96 use priority database access 2024-07-29 15:12:18 +01:00
Evgeny Poberezkin 42669454b0 multiplatform: load chat data before starting chat 2024-07-29 11:37:32 +01:00
Evgeny Poberezkin 243f3a7516 revert some 2024-07-29 10:57:40 +01:00
spaced4ndy aadba41e66 core: move db actions out of synchronous execution on chat start 2024-07-29 13:33:31 +04:00
8 changed files with 355 additions and 295 deletions
+12 -2
View File
@@ -225,6 +225,15 @@ func apiStartChat(ctrl: chat_ctrl? = nil) throws -> Bool {
} }
} }
func apiCheckChatRunning() throws -> Bool {
let r = chatSendCmdSync(.checkChatRunning)
switch r {
case .chatRunning: return true
case .chatStopped: return false
default: throw r
}
}
func apiStopChat() async throws { func apiStopChat() async throws {
let r = await chatSendCmd(.apiStopChat) let r = await chatSendCmd(.apiStopChat)
switch r { switch r {
@@ -1439,15 +1448,16 @@ func startChat(refreshInvitations: Bool = true) throws {
logger.debug("startChat") logger.debug("startChat")
let m = ChatModel.shared let m = ChatModel.shared
try setNetworkConfig(getNetCfg()) try setNetworkConfig(getNetCfg())
let justStarted = try apiStartChat() let chatRunning = try apiCheckChatRunning()
m.users = try listUsers() m.users = try listUsers()
if justStarted { if !chatRunning {
try getUserChatData() try getUserChatData()
NtfManager.shared.setNtfBadgeCount(m.totalUnreadCountForAllUsers()) NtfManager.shared.setNtfBadgeCount(m.totalUnreadCountForAllUsers())
if (refreshInvitations) { if (refreshInvitations) {
try refreshCallInvitations() try refreshCallInvitations()
} }
(m.savedToken, m.tokenStatus, m.notificationMode, m.notificationServer) = apiGetNtfToken() (m.savedToken, m.tokenStatus, m.notificationMode, m.notificationServer) = apiGetNtfToken()
_ = try apiStartChat()
// deviceToken is set when AppDelegate.application(didRegisterForRemoteNotificationsWithDeviceToken:) is called, // deviceToken is set when AppDelegate.application(didRegisterForRemoteNotificationsWithDeviceToken:) is called,
// when it is called before startChat // when it is called before startChat
if let token = m.deviceToken { if let token = m.deviceToken {
+3
View File
@@ -27,6 +27,7 @@ public enum ChatCommand {
case apiUnmuteUser(userId: Int64) case apiUnmuteUser(userId: Int64)
case apiDeleteUser(userId: Int64, delSMPQueues: Bool, viewPwd: String?) case apiDeleteUser(userId: Int64, delSMPQueues: Bool, viewPwd: String?)
case startChat(mainApp: Bool, enableSndFiles: Bool) case startChat(mainApp: Bool, enableSndFiles: Bool)
case checkChatRunning
case apiStopChat case apiStopChat
case apiActivateChat(restoreChat: Bool) case apiActivateChat(restoreChat: Bool)
case apiSuspendChat(timeoutMicroseconds: Int) case apiSuspendChat(timeoutMicroseconds: Int)
@@ -173,6 +174,7 @@ public enum ChatCommand {
case let .apiUnmuteUser(userId): return "/_unmute user \(userId)" case let .apiUnmuteUser(userId): return "/_unmute user \(userId)"
case let .apiDeleteUser(userId, delSMPQueues, viewPwd): return "/_delete user \(userId) del_smp=\(onOff(delSMPQueues))\(maybePwd(viewPwd))" case let .apiDeleteUser(userId, delSMPQueues, viewPwd): return "/_delete user \(userId) del_smp=\(onOff(delSMPQueues))\(maybePwd(viewPwd))"
case let .startChat(mainApp, enableSndFiles): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles))" case let .startChat(mainApp, enableSndFiles): return "/_start main=\(onOff(mainApp)) snd_files=\(onOff(enableSndFiles))"
case .checkChatRunning: return "/_check running"
case .apiStopChat: return "/_stop" case .apiStopChat: return "/_stop"
case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))" case let .apiActivateChat(restore): return "/_app activate restore=\(onOff(restore))"
case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)" case let .apiSuspendChat(timeoutMicroseconds): return "/_app suspend \(timeoutMicroseconds)"
@@ -334,6 +336,7 @@ public enum ChatCommand {
case .apiUnmuteUser: return "apiUnmuteUser" case .apiUnmuteUser: return "apiUnmuteUser"
case .apiDeleteUser: return "apiDeleteUser" case .apiDeleteUser: return "apiDeleteUser"
case .startChat: return "startChat" case .startChat: return "startChat"
case .checkChatRunning: return "checkChatRunning"
case .apiStopChat: return "apiStopChat" case .apiStopChat: return "apiStopChat"
case .apiActivateChat: return "apiActivateChat" case .apiActivateChat: return "apiActivateChat"
case .apiSuspendChat: return "apiSuspendChat" case .apiSuspendChat: return "apiSuspendChat"
@@ -461,12 +461,11 @@ object ChatController {
Log.d(TAG, "user: $user") Log.d(TAG, "user: $user")
try { try {
apiSetNetworkConfig(getNetCfg()) apiSetNetworkConfig(getNetCfg())
val justStarted = apiStartChat() val chatRunning = apiCheckChatRunning()
appPrefs.chatStopped.set(false)
val users = listUsers(null) val users = listUsers(null)
chatModel.users.clear() chatModel.users.clear()
chatModel.users.addAll(users) chatModel.users.addAll(users)
if (justStarted) { if (!chatRunning) {
chatModel.currentUser.value = user chatModel.currentUser.value = user
chatModel.localUserCreated.value = true chatModel.localUserCreated.value = true
getUserChatData(null) getUserChatData(null)
@@ -485,6 +484,8 @@ object ChatController {
} }
Log.d(TAG, "startChat: running") Log.d(TAG, "startChat: running")
} }
apiStartChat()
appPrefs.chatStopped.set(false)
} catch (e: Throwable) { } catch (e: Throwable) {
Log.e(TAG, "failed starting chat $e") Log.e(TAG, "failed starting chat $e")
throw e throw e
@@ -738,6 +739,15 @@ object ChatController {
} }
} }
private suspend fun apiCheckChatRunning(): Boolean {
val r = sendCmd(null, CC.CheckChatRunning())
when (r) {
is CR.ChatRunning -> return true
is CR.ChatStopped -> return false
else -> throw Exception("failed check chat running: ${r.responseType} ${r.details}")
}
}
suspend fun apiStopChat(): Boolean { suspend fun apiStopChat(): Boolean {
val r = sendCmd(null, CC.ApiStopChat()) val r = sendCmd(null, CC.ApiStopChat())
when (r) { when (r) {
@@ -2709,6 +2719,7 @@ sealed class CC {
class ApiUnmuteUser(val userId: Long): CC() class ApiUnmuteUser(val userId: Long): CC()
class ApiDeleteUser(val userId: Long, val delSMPQueues: Boolean, val viewPwd: String?): CC() class ApiDeleteUser(val userId: Long, val delSMPQueues: Boolean, val viewPwd: String?): CC()
class StartChat(val mainApp: Boolean): CC() class StartChat(val mainApp: Boolean): CC()
class CheckChatRunning: CC()
class ApiStopChat: CC() class ApiStopChat: CC()
@Serializable @Serializable
class ApiSetAppFilePaths(val appFilesFolder: String, val appTempFolder: String, val appAssetsFolder: String, val appRemoteHostsFolder: String): CC() class ApiSetAppFilePaths(val appFilesFolder: String, val appTempFolder: String, val appAssetsFolder: String, val appRemoteHostsFolder: String): CC()
@@ -2854,6 +2865,7 @@ sealed class CC {
is ApiUnmuteUser -> "/_unmute user $userId" is ApiUnmuteUser -> "/_unmute user $userId"
is ApiDeleteUser -> "/_delete user $userId del_smp=${onOff(delSMPQueues)}${maybePwd(viewPwd)}" is ApiDeleteUser -> "/_delete user $userId del_smp=${onOff(delSMPQueues)}${maybePwd(viewPwd)}"
is StartChat -> "/_start main=${onOff(mainApp)}" is StartChat -> "/_start main=${onOff(mainApp)}"
is CheckChatRunning -> "/_check running"
is ApiStopChat -> "/_stop" is ApiStopChat -> "/_stop"
is ApiSetAppFilePaths -> "/set file paths ${json.encodeToString(this)}" is ApiSetAppFilePaths -> "/set file paths ${json.encodeToString(this)}"
is ApiSetEncryptLocalFiles -> "/_files_encrypt ${onOff(enable)}" is ApiSetEncryptLocalFiles -> "/_files_encrypt ${onOff(enable)}"
@@ -3007,6 +3019,7 @@ sealed class CC {
is ApiUnmuteUser -> "apiUnmuteUser" is ApiUnmuteUser -> "apiUnmuteUser"
is ApiDeleteUser -> "apiDeleteUser" is ApiDeleteUser -> "apiDeleteUser"
is StartChat -> "startChat" is StartChat -> "startChat"
is CheckChatRunning -> "checkChatRunning"
is ApiStopChat -> "apiStopChat" is ApiStopChat -> "apiStopChat"
is ApiSetAppFilePaths -> "apiSetAppFilePaths" is ApiSetAppFilePaths -> "apiSetAppFilePaths"
is ApiSetEncryptLocalFiles -> "apiSetEncryptLocalFiles" is ApiSetEncryptLocalFiles -> "apiSetEncryptLocalFiles"
+1 -1
View File
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package source-repository-package
type: git type: git
location: https://github.com/simplex-chat/simplexmq.git location: https://github.com/simplex-chat/simplexmq.git
tag: 2de16cfae89661605b468df71eff8b8e8188ef86 tag: 3753379ae47a1201c8e546eaabc7bdf245463a70
source-repository-package source-repository-package
type: git type: git
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"https://github.com/simplex-chat/simplexmq.git"."2de16cfae89661605b468df71eff8b8e8188ef86" = "00bgpy3gygqhmcbb2r5i8kryc5vn667bdg5s3xl3lf7y9m13g047"; "https://github.com/simplex-chat/simplexmq.git"."3753379ae47a1201c8e546eaabc7bdf245463a70" = "1h6wnjp1bqcjn55h3d9jbfz6fp49shy50izp649cvpyvls3difcm";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
+282 -279
View File
File diff suppressed because it is too large Load Diff
+17 -3
View File
@@ -73,7 +73,7 @@ import Simplex.Messaging.Agent.Client (AgentLocks, AgentQueuesInfo (..), AgentWo
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, NetworkConfig, ServerCfg) import Simplex.Messaging.Agent.Env.SQLite (AgentConfig, NetworkConfig, ServerCfg)
import Simplex.Messaging.Agent.Lock import Simplex.Messaging.Agent.Lock
import Simplex.Messaging.Agent.Protocol import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation, SQLiteStore, UpMigration, withTransaction) import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation, SQLiteStore, UpMigration, withTransaction, withTransactionPriority)
import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..)) import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..))
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
import Simplex.Messaging.Client (SMPProxyFallback (..), SMPProxyMode (..), SocksMode (..)) import Simplex.Messaging.Client (SMPProxyFallback (..), SMPProxyMode (..), SocksMode (..))
@@ -264,6 +264,7 @@ data ChatCommand
| APIDeleteUser UserId Bool (Maybe UserPwd) | APIDeleteUser UserId Bool (Maybe UserPwd)
| DeleteUser UserName Bool (Maybe UserPwd) | DeleteUser UserName Bool (Maybe UserPwd)
| StartChat {mainApp :: Bool, enableSndFiles :: Bool} -- enableSndFiles has no effect when mainApp is True | StartChat {mainApp :: Bool, enableSndFiles :: Bool} -- enableSndFiles has no effect when mainApp is True
| CheckChatRunning
| APIStopChat | APIStopChat
| APIActivateChat {restoreChat :: Bool} | APIActivateChat {restoreChat :: Bool}
| APISuspendChat {suspendTimeout :: Int} | APISuspendChat {suspendTimeout :: Int}
@@ -1393,11 +1394,24 @@ toView' ev = do
withStore' :: (DB.Connection -> IO a) -> CM a withStore' :: (DB.Connection -> IO a) -> CM a
withStore' action = withStore $ liftIO . action withStore' action = withStore $ liftIO . action
{-# INLINE withStore' #-}
withFastStore' :: (DB.Connection -> IO a) -> CM a
withFastStore' action = withFastStore $ liftIO . action
{-# INLINE withFastStore' #-}
withStore :: (DB.Connection -> ExceptT StoreError IO a) -> CM a withStore :: (DB.Connection -> ExceptT StoreError IO a) -> CM a
withStore action = do withStore = withStorePriority False
{-# INLINE withStore #-}
withFastStore :: (DB.Connection -> ExceptT StoreError IO a) -> CM a
withFastStore = withStorePriority True
{-# INLINE withFastStore #-}
withStorePriority :: Bool -> (DB.Connection -> ExceptT StoreError IO a) -> CM a
withStorePriority priority action = do
ChatController {chatStore} <- ask ChatController {chatStore} <- ask
liftIOEither $ withTransaction chatStore (runExceptT . withExceptT ChatErrorStore . action) `E.catches` handleDBErrors liftIOEither $ withTransactionPriority chatStore priority (runExceptT . withExceptT ChatErrorStore . action) `E.catches` handleDBErrors
withStoreBatch :: Traversable t => (DB.Connection -> t (IO (Either ChatError a))) -> CM' (t (Either ChatError a)) withStoreBatch :: Traversable t => (DB.Connection -> t (IO (Either ChatError a))) -> CM' (t (Either ChatError a))
withStoreBatch actions = do withStoreBatch actions = do
+23 -6
View File
@@ -648,6 +648,7 @@ testGroupSameName :: HasCallStack => FilePath -> IO ()
testGroupSameName = testGroupSameName =
testChat2 aliceProfile bobProfile $ testChat2 aliceProfile bobProfile $
\alice _ -> do \alice _ -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -1844,6 +1845,7 @@ testGroupLink :: HasCallStack => FilePath -> IO ()
testGroupLink = testGroupLink =
testChatCfg3 testCfgGroupLinkViaContact aliceProfile bobProfile cathProfile $ testChatCfg3 testCfgGroupLinkViaContact aliceProfile bobProfile cathProfile $
\alice bob cath -> do \alice bob cath -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -1947,6 +1949,7 @@ testGroupLinkDeleteGroupRejoin :: HasCallStack => FilePath -> IO ()
testGroupLinkDeleteGroupRejoin = testGroupLinkDeleteGroupRejoin =
testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $ testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2003,6 +2006,7 @@ testGroupLinkContactUsed :: HasCallStack => FilePath -> IO ()
testGroupLinkContactUsed = testGroupLinkContactUsed =
testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $ testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2151,6 +2155,7 @@ testGroupLinkUnusedHostContactDeleted =
testChatCfg2 cfg aliceProfile bobProfile $ testChatCfg2 cfg aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
-- create group 1 -- create group 1
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2285,6 +2290,7 @@ testGroupLinkMemberRole :: HasCallStack => FilePath -> IO ()
testGroupLinkMemberRole = testGroupLinkMemberRole =
testChatCfg3 testCfgGroupLinkViaContact aliceProfile bobProfile cathProfile $ testChatCfg3 testCfgGroupLinkViaContact aliceProfile bobProfile cathProfile $
\alice bob cath -> do \alice bob cath -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2420,6 +2426,7 @@ testPlanGroupLinkOkKnown :: HasCallStack => FilePath -> IO ()
testPlanGroupLinkOkKnown = testPlanGroupLinkOkKnown =
testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $ testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2463,6 +2470,7 @@ testPlanHostContactDeletedGroupLinkKnown :: HasCallStack => FilePath -> IO ()
testPlanHostContactDeletedGroupLinkKnown = testPlanHostContactDeletedGroupLinkKnown =
testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $ testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2569,14 +2577,15 @@ testPlanGroupLinkOwn tmp =
testPlanGroupLinkConnecting :: HasCallStack => FilePath -> IO () testPlanGroupLinkConnecting :: HasCallStack => FilePath -> IO ()
testPlanGroupLinkConnecting tmp = do testPlanGroupLinkConnecting tmp = do
-- gLink <- withNewTestChatCfg tmp cfg "alice" aliceProfile $ \alice -> do -- gLink <- withNewTestChatCfg tmp cfg "alice" aliceProfile $ \alice -> do
gLink <- withNewTestChatCfg tmp cfg "alice" aliceProfile $ \a -> withTestOutput a $ \alice -> do gLink <- withNewTestChatCfg tmp cfg "alice" aliceProfile $ \alice -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
alice ##> "/create link #team" alice ##> "/create link #team"
getGroupLink alice "team" GRMember True getGroupLink alice "team" GRMember True
-- withNewTestChatCfg tmp cfg "bob" bobProfile $ \bob -> do -- withNewTestChatCfg tmp cfg "bob" bobProfile $ \bob -> do
withNewTestChatCfg tmp cfg "bob" bobProfile $ \b -> withTestOutput b $ \bob -> do withNewTestChatCfg tmp cfg "bob" bobProfile $ \bob -> do
threadDelay 100000 threadDelay 100000
bob ##> ("/c " <> gLink) bob ##> ("/c " <> gLink)
@@ -2591,14 +2600,14 @@ testPlanGroupLinkConnecting tmp = do
threadDelay 100000 threadDelay 100000
-- withTestChatCfg tmp cfg "alice" $ \alice -> do -- withTestChatCfg tmp cfg "alice" $ \alice -> do
withTestChatCfg tmp cfg "alice" $ \a -> withTestOutput a $ \alice -> do withTestChatCfg tmp cfg "alice" $ \alice -> do
alice alice
<### [ "1 group links active", <### [ "1 group links active",
"#team: group is empty", "#team: group is empty",
"bob (Bob): accepting request to join group #team..." "bob (Bob): accepting request to join group #team..."
] ]
-- withTestChatCfg tmp cfg "bob" $ \bob -> do -- withTestChatCfg tmp cfg "bob" $ \bob -> do
withTestChatCfg tmp cfg "bob" $ \b -> withTestOutput b $ \bob -> do withTestChatCfg tmp cfg "bob" $ \bob -> do
threadDelay 500000 threadDelay 500000
bob ##> ("/_connect plan 1 " <> gLink) bob ##> ("/_connect plan 1 " <> gLink)
bob <## "group link: connecting" bob <## "group link: connecting"
@@ -2615,8 +2624,8 @@ testPlanGroupLinkConnecting tmp = do
testPlanGroupLinkLeaveRejoin :: HasCallStack => FilePath -> IO () testPlanGroupLinkLeaveRejoin :: HasCallStack => FilePath -> IO ()
testPlanGroupLinkLeaveRejoin = testPlanGroupLinkLeaveRejoin =
testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $ testChatCfg2 testCfgGroupLinkViaContact aliceProfile bobProfile $
-- \alice bob -> do \alice bob -> do
\a b -> withTestOutput a $ \alice -> withTestOutput b $ \bob -> do threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2705,6 +2714,7 @@ testGroupLinkNoContact :: HasCallStack => FilePath -> IO ()
testGroupLinkNoContact = testGroupLinkNoContact =
testChat3 aliceProfile bobProfile cathProfile $ testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do \alice bob cath -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -2928,6 +2938,7 @@ testGroupLinkNoContactMemberRole :: HasCallStack => FilePath -> IO ()
testGroupLinkNoContactMemberRole = testGroupLinkNoContactMemberRole =
testChat3 aliceProfile bobProfile cathProfile $ testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do \alice bob cath -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -3041,6 +3052,7 @@ testGroupLinkNoContactInviteeIncognito :: HasCallStack => FilePath -> IO ()
testGroupLinkNoContactInviteeIncognito = testGroupLinkNoContactInviteeIncognito =
testChat2 aliceProfile bobProfile $ testChat2 aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -3145,6 +3157,7 @@ testPlanGroupLinkNoContactKnown :: HasCallStack => FilePath -> IO ()
testPlanGroupLinkNoContactKnown = testPlanGroupLinkNoContactKnown =
testChat2 aliceProfile bobProfile $ testChat2 aliceProfile bobProfile $
\alice bob -> do \alice bob -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -3180,6 +3193,7 @@ testPlanGroupLinkNoContactKnown =
testPlanGroupLinkNoContactConnecting :: HasCallStack => FilePath -> IO () testPlanGroupLinkNoContactConnecting :: HasCallStack => FilePath -> IO ()
testPlanGroupLinkNoContactConnecting tmp = do testPlanGroupLinkNoContactConnecting tmp = do
gLink <- withNewTestChat tmp "alice" aliceProfile $ \alice -> do gLink <- withNewTestChat tmp "alice" aliceProfile $ \alice -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -3226,6 +3240,7 @@ testPlanGroupLinkNoContactConnecting tmp = do
testPlanGroupLinkNoContactConnectingSlow :: HasCallStack => FilePath -> IO () testPlanGroupLinkNoContactConnectingSlow :: HasCallStack => FilePath -> IO ()
testPlanGroupLinkNoContactConnectingSlow tmp = do testPlanGroupLinkNoContactConnectingSlow tmp = do
gLink <- withNewTestChatCfg tmp testCfgSlow "alice" aliceProfile $ \alice -> do gLink <- withNewTestChatCfg tmp testCfgSlow "alice" aliceProfile $ \alice -> do
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -4123,6 +4138,7 @@ testMemberContactIncognito =
testChatCfg3 testCfgGroupLinkViaContact aliceProfile bobProfile cathProfile $ testChatCfg3 testCfgGroupLinkViaContact aliceProfile bobProfile cathProfile $
\alice bob cath -> do \alice bob cath -> do
-- create group, bob joins incognito -- create group, bob joins incognito
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"
@@ -5371,6 +5387,7 @@ testMembershipProfileUpdateNextGroupMessage =
testChat3 aliceProfile bobProfile cathProfile $ testChat3 aliceProfile bobProfile cathProfile $
\alice bob cath -> do \alice bob cath -> do
-- create group 1 -- create group 1
threadDelay 100000
alice ##> "/g team" alice ##> "/g team"
alice <## "group #team is created" alice <## "group #team is created"
alice <## "to add members use /a team <name> or /create link #team" alice <## "to add members use /a team <name> or /create link #team"