Compare commits

..

6 Commits

Author SHA1 Message Date
Evgeny Poberezkin e9a443e049 rename option 2024-11-30 20:40:30 +00:00
Evgeny Poberezkin 486c19c1d6 pass ChatOpts 2024-11-30 20:33:29 +00:00
Evgeny Poberezkin 271f0dc6c1 simplify, make passed user active 2024-11-30 20:29:38 +00:00
Evgeny Poberezkin ecbcf05218 Merge branch 'feature/cli_support_non_interactive_mode' of github.com:reply2future/simplex-chat into reply2future-feature/cli_support_non_interactive_mode 2024-11-30 20:19:12 +00:00
mervyn 2dc9c85cf2 refactor(cli): move display-name option to ChatOpts in CLI 2024-11-19 07:48:01 +08:00
mervyn 587e0a18a9 feat(cli): add display-name option to cli 2024-11-19 07:48:01 +08:00
18 changed files with 196 additions and 158 deletions
+18 -18
View File
@@ -148,11 +148,11 @@
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; };
6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; };
642BA82D2CE50495005E9412 /* NewServerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 642BA82C2CE50495005E9412 /* NewServerView.swift */; };
642BA8332CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA82E2CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B.a */; };
642BA8332CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA82E2CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14.a */; };
642BA8342CEB3D4B005E9412 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA82F2CEB3D4B005E9412 /* libffi.a */; };
642BA8352CEB3D4B005E9412 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA8302CEB3D4B005E9412 /* libgmp.a */; };
642BA8362CEB3D4B005E9412 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA8312CEB3D4B005E9412 /* libgmpxx.a */; };
642BA8372CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA8322CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B-ghc9.6.3.a */; };
642BA8372CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 642BA8322CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14-ghc9.6.3.a */; };
6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; };
643B3B4E2CCFD6400083A2CF /* OperatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 643B3B4D2CCFD6400083A2CF /* OperatorView.swift */; };
6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; };
@@ -496,11 +496,11 @@
6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = "<group>"; };
6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = "<group>"; };
642BA82C2CE50495005E9412 /* NewServerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewServerView.swift; sourceTree = "<group>"; };
642BA82E2CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B.a"; sourceTree = "<group>"; };
642BA82E2CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14.a"; sourceTree = "<group>"; };
642BA82F2CEB3D4B005E9412 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
642BA8302CEB3D4B005E9412 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
642BA8312CEB3D4B005E9412 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
642BA8322CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B-ghc9.6.3.a"; sourceTree = "<group>"; };
642BA8322CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14-ghc9.6.3.a"; sourceTree = "<group>"; };
6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = "<group>"; };
643B3B4D2CCFD6400083A2CF /* OperatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatorView.swift; sourceTree = "<group>"; };
6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = "<group>"; };
@@ -672,8 +672,8 @@
CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */,
642BA8342CEB3D4B005E9412 /* libffi.a in Frameworks */,
642BA8352CEB3D4B005E9412 /* libgmp.a in Frameworks */,
642BA8372CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B-ghc9.6.3.a in Frameworks */,
642BA8332CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B.a in Frameworks */,
642BA8372CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14-ghc9.6.3.a in Frameworks */,
642BA8332CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14.a in Frameworks */,
642BA8362CEB3D4B005E9412 /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -754,8 +754,8 @@
642BA82F2CEB3D4B005E9412 /* libffi.a */,
642BA8302CEB3D4B005E9412 /* libgmp.a */,
642BA8312CEB3D4B005E9412 /* libgmpxx.a */,
642BA8322CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B-ghc9.6.3.a */,
642BA82E2CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.3-ELfYrsBTXJJ5vBEIgQ1y2B.a */,
642BA8322CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14-ghc9.6.3.a */,
642BA82E2CEB3D4B005E9412 /* libHSsimplex-chat-6.2.0.1-3FFlorLJSLlCbWWiG2Vp14.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -1931,7 +1931,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1980,7 +1980,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -2021,7 +2021,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@@ -2041,7 +2041,7 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
@@ -2066,7 +2066,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -2103,7 +2103,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -2140,7 +2140,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2191,7 +2191,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2242,7 +2242,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2276,7 +2276,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 249;
CURRENT_PROJECT_VERSION = 247;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
+4 -4
View File
@@ -24,11 +24,11 @@ android.nonTransitiveRClass=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11
android.version_name=6.2-beta.3
android.version_code=254
android.version_name=6.2-beta.1
android.version_code=252
desktop.version_name=6.2-beta.3
desktop.version_code=78
desktop.version_name=6.2-beta.1
desktop.version_code=76
kotlin.version=1.9.23
gradle.plugin.version=8.2.0
@@ -76,6 +76,7 @@ mkChatOpts BroadcastBotOpts {coreOptions} =
ChatOpts
{ coreOptions,
deviceName = Nothing,
userDisplayName = Nothing,
chatCmd = "",
chatCmdDelay = 3,
chatCmdLog = CCLNone,
@@ -85,6 +85,7 @@ mkChatOpts DirectoryOpts {coreOptions} =
ChatOpts
{ coreOptions,
deviceName = Nothing,
userDisplayName = Nothing,
chatCmd = "",
chatCmdDelay = 3,
chatCmdLog = CCLNone,
+1 -1
View File
@@ -1,5 +1,5 @@
name: simplex-chat
version: 6.2.0.3
version: 6.2.0.1
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
+1 -1
View File
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
version: 6.2.0.3
version: 6.2.0.1
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
+9 -9
View File
@@ -1250,13 +1250,13 @@ processChatCommand' vr = \case
when (size' > 0) $ copyChunks r w size'
APIUserRead userId -> withUserId userId $ \user -> withFastStore' (`setUserChatsRead` user) >> ok user
UserRead -> withUser $ \User {userId} -> processChatCommand $ APIUserRead userId
APIChatRead chatRef@(ChatRef cType chatId) -> withUser $ \_ -> case cType of
APIChatRead chatRef@(ChatRef cType chatId) fromToIds -> withUser $ \_ -> case cType of
CTDirect -> do
user <- withFastStore $ \db -> getUserByContactId db chatId
ts <- liftIO getCurrentTime
timedItems <- withFastStore' $ \db -> do
timedItems <- getDirectUnreadTimedItems db user chatId
updateDirectChatItemsRead db user chatId
timedItems <- getDirectUnreadTimedItems db user chatId fromToIds
updateDirectChatItemsRead db user chatId fromToIds
setDirectChatItemsDeleteAt db user chatId timedItems ts
forM_ timedItems $ \(itemId, deleteAt) -> startProximateTimedItemThread user (chatRef, itemId) deleteAt
ok user
@@ -1264,14 +1264,14 @@ processChatCommand' vr = \case
user <- withFastStore $ \db -> getUserByGroupId db chatId
ts <- liftIO getCurrentTime
timedItems <- withFastStore' $ \db -> do
timedItems <- getGroupUnreadTimedItems db user chatId
updateGroupChatItemsRead db user chatId
timedItems <- getGroupUnreadTimedItems db user chatId fromToIds
updateGroupChatItemsRead db user chatId fromToIds
setGroupChatItemsDeleteAt db user chatId timedItems ts
forM_ timedItems $ \(itemId, deleteAt) -> startProximateTimedItemThread user (chatRef, itemId) deleteAt
ok user
CTLocal -> do
user <- withFastStore $ \db -> getUserByNoteFolderId db chatId
withFastStore' $ \db -> updateLocalChatItemsRead db user chatId
withFastStore' $ \db -> updateLocalChatItemsRead db user chatId fromToIds
ok user
CTContactRequest -> pure $ chatCmdError Nothing "not supported"
CTContactConnection -> pure $ chatCmdError Nothing "not supported"
@@ -1471,7 +1471,7 @@ processChatCommand' vr = \case
withCurrentCall contactId $ \user ct Call {chatItemId, callState} -> case callState of
CallInvitationReceived {} -> do
let aciContent = ACIContent SMDRcv $ CIRcvCall CISCallRejected 0
withFastStore' $ \db -> setDirectChatItemRead db user contactId chatItemId
withFastStore' $ \db -> updateDirectChatItemsRead db user contactId $ Just (chatItemId, chatItemId)
timed_ <- contactCITimed ct
updateDirectChatItemView user ct chatItemId aciContent False False timed_ Nothing
forM_ (timed_ >>= timedDeleteAt') $
@@ -1487,7 +1487,7 @@ processChatCommand' vr = \case
callState' = CallOfferSent {localCallType = callType, peerCallType, localCallSession = rtcSession, sharedKey}
aciContent = ACIContent SMDRcv $ CIRcvCall CISCallAccepted 0
(SndMessage {msgId}, _) <- sendDirectContactMessage user ct (XCallOffer callId offer)
withFastStore' $ \db -> setDirectChatItemRead db user contactId chatItemId
withFastStore' $ \db -> updateDirectChatItemsRead db user contactId $ Just (chatItemId, chatItemId)
updateDirectChatItemView user ct chatItemId aciContent False False Nothing $ Just msgId
pure $ Just call {callState = callState'}
_ -> throwChatError . CECallState $ callStateTag callState
@@ -8277,7 +8277,7 @@ chatCommandP =
"/_forward " *> (APIForwardChatItems <$> chatRefP <* A.space <*> chatRefP <*> _strP <*> sendMessageTTLP),
"/_read user " *> (APIUserRead <$> A.decimal),
"/read user" $> UserRead,
"/_read chat " *> (APIChatRead <$> chatRefP),
"/_read chat " *> (APIChatRead <$> chatRefP <*> optional (A.space *> ((,) <$> ("from=" *> A.decimal) <* A.space <*> ("to=" *> A.decimal)))),
"/_read chat items " *> (APIChatItemsRead <$> chatRefP <*> _strP),
"/_unread chat " *> (APIChatUnread <$> chatRefP <* A.space <*> onOffP),
"/_delete " *> (APIDeleteChat <$> chatRefP <*> chatDeleteMode),
+1 -1
View File
@@ -309,7 +309,7 @@ data ChatCommand
| APIForwardChatItems {toChatRef :: ChatRef, fromChatRef :: ChatRef, chatItemIds :: NonEmpty ChatItemId, ttl :: Maybe Int}
| APIUserRead UserId
| UserRead
| APIChatRead ChatRef
| APIChatRead ChatRef (Maybe (ChatItemId, ChatItemId))
| APIChatItemsRead ChatRef (NonEmpty ChatItemId)
| APIChatUnread ChatRef Bool
| APIDeleteChat ChatRef ChatDeleteMode -- currently delete mode settings are only applied to direct chats
+20 -15
View File
@@ -23,31 +23,30 @@ import Simplex.Chat
import Simplex.Chat.Controller
import Simplex.Chat.Options (ChatOpts (..), CoreChatOpts (..))
import Simplex.Chat.Store.Profiles
import Simplex.Chat.Types
import Simplex.Chat.Types (User (..), Profile (..), NewUser (..), LocalProfile (..))
import Simplex.Chat.View (serializeChatResponse)
import Simplex.Messaging.Agent.Store.SQLite (SQLiteStore, withTransaction, MigrationConfirmation (..))
import Simplex.Messaging.Agent.Store.SQLite (SQLiteStore, withTransaction)
import System.Exit (exitFailure)
import System.IO (hFlush, stdout)
import Text.Read (readMaybe)
import UnliftIO.Async
simplexChatCore :: ChatConfig -> ChatOpts -> (User -> ChatController -> IO ()) -> IO ()
simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, dbKey, logAgent, yesToUpMigrations}} chat =
simplexChatCore cfg@ChatConfig {confirmMigrations, testView} opts@ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, dbKey, logAgent}} chat =
case logAgent of
Just level -> do
setLogLevel level
withGlobalLogging logCfg initRun
_ -> initRun
where
initRun = createChatDatabase dbFilePrefix dbKey False confirm' >>= either exit run
confirm' = if confirmMigrations == MCConsole && yesToUpMigrations then MCYesUp else confirmMigrations
initRun = createChatDatabase dbFilePrefix dbKey False confirmMigrations >>= either exit run
exit e = do
putStrLn $ "Error opening database: " <> show e
exitFailure
run db@ChatDatabase {chatStore} = do
u_ <- getSelectActiveUser chatStore
u_ <- getSelectActiveUser chatStore opts
cc <- newChatController db u_ cfg opts False
u <- maybe (createActiveUser cc) pure u_
u <- maybe (createActiveUser cc opts) pure u_
unless testView $ putStrLn $ "Current user: " <> userStr u
runSimplexChat opts u cc chat
@@ -65,12 +64,16 @@ sendChatCmdStr cc s = runReaderT (execChatCommand Nothing . encodeUtf8 $ T.pack
sendChatCmd :: ChatController -> ChatCommand -> IO ChatResponse
sendChatCmd cc cmd = runReaderT (execChatCommand' cmd) cc
getSelectActiveUser :: SQLiteStore -> IO (Maybe User)
getSelectActiveUser st = do
getSelectActiveUser :: SQLiteStore -> ChatOpts -> IO (Maybe User)
getSelectActiveUser st ChatOpts {userDisplayName} = do
users <- withTransaction st getUsers
case find activeUser users of
Just u -> pure $ Just u
Nothing -> selectUser users
case userDisplayName of
Just name ->
forM (find (\User {localDisplayName} -> localDisplayName == name) users) $ \u ->
if activeUser u then pure u else withTransaction st (`setActiveUser` u)
Nothing -> case find activeUser users of
Just u -> pure $ Just u
Nothing -> selectUser users
where
selectUser :: [User] -> IO (Maybe User)
selectUser = \case
@@ -91,8 +94,8 @@ getSelectActiveUser st = do
let user = users !! (n - 1)
in Just <$> withTransaction st (`setActiveUser` user)
createActiveUser :: ChatController -> IO User
createActiveUser cc = do
createActiveUser :: ChatController -> ChatOpts -> IO User
createActiveUser cc ChatOpts {userDisplayName = name} = do
putStrLn
"No user profiles found, it will be created now.\n\
\Please choose your display name.\n\
@@ -101,7 +104,9 @@ createActiveUser cc = do
loop
where
loop = do
displayName <- T.pack <$> getWithPrompt "display name"
displayName <- case name of
Just n | not (T.null n) -> pure n
_ -> T.pack <$> getWithPrompt "display name"
let profile = Just Profile {displayName, fullName = "", image = Nothing, contactLink = Nothing, preferences = Nothing}
execChatCommand' (CreateActiveUser NewUser {profile, pastTimestamp = False}) `runReaderT` cc >>= \case
CRActiveUser user -> pure user
+1
View File
@@ -202,6 +202,7 @@ mobileChatOpts dbFilePrefix =
yesToUpMigrations = False
},
deviceName = Nothing,
userDisplayName = Nothing,
chatCmd = "",
chatCmdDelay = 3,
chatCmdLog = CCLNone,
+10
View File
@@ -35,10 +35,12 @@ import Simplex.Messaging.Parsers (parseAll)
import Simplex.Messaging.Protocol (ProtoServerWithAuth, ProtocolTypeI, SMPServerWithAuth, XFTPServerWithAuth)
import Simplex.Messaging.Transport.Client (SocksProxyWithAuth (..), SocksAuth (..), defaultSocksProxyWithAuth)
import System.FilePath (combine)
import Simplex.Chat.Types (ContactName)
data ChatOpts = ChatOpts
{ coreOptions :: CoreChatOpts,
deviceName :: Maybe Text,
userDisplayName :: Maybe ContactName,
chatCmd :: String,
chatCmdDelay :: Int,
chatCmdLog :: ChatCmdLog,
@@ -286,6 +288,13 @@ chatOptsP appDir defaultDbFileName = do
<> metavar "DEVICE"
<> help "Device name to use in connections with remote hosts and controller"
)
userDisplayName <-
optional $
strOption
( long "user-display-name"
<> metavar "DISPLAY_NAME"
<> help "Create new or switch to existing user profile with this display name."
)
chatCmd <-
strOption
( long "execute"
@@ -375,6 +384,7 @@ chatOptsP appDir defaultDbFileName = do
pure
ChatOpts
{ coreOptions,
userDisplayName,
deviceName,
chatCmd,
chatCmdDelay,
+2 -2
View File
@@ -73,11 +73,11 @@ import UnliftIO.Directory (copyFile, createDirectoryIfMissing, doesDirectoryExis
-- when acting as host
minRemoteCtrlVersion :: AppVersion
minRemoteCtrlVersion = AppVersion [6, 2, 0, 3]
minRemoteCtrlVersion = AppVersion [6, 2, 0, 1]
-- when acting as controller
minRemoteHostVersion :: AppVersion
minRemoteHostVersion = AppVersion [6, 2, 0, 3]
minRemoteHostVersion = AppVersion [6, 2, 0, 1]
currentAppVersion :: AppVersion
currentAppVersion = AppVersion SC.version
+119 -104
View File
@@ -62,7 +62,6 @@ module Simplex.Chat.Store.Messages
updateDirectChatItemsRead,
getDirectUnreadTimedItems,
updateDirectChatItemsReadList,
setDirectChatItemRead,
setDirectChatItemsDeleteAt,
updateGroupChatItemsRead,
getGroupUnreadTimedItems,
@@ -1671,61 +1670,61 @@ toChatItemRef = \case
(itemId, Nothing, Nothing, Just folderId) -> Right (ChatRef CTLocal folderId, itemId)
(itemId, _, _, _) -> Left $ SEBadChatItem itemId Nothing
updateDirectChatItemsRead :: DB.Connection -> User -> ContactId -> IO ()
updateDirectChatItemsRead db User {userId} contactId = do
updateDirectChatItemsRead :: DB.Connection -> User -> ContactId -> Maybe (ChatItemId, ChatItemId) -> IO ()
updateDirectChatItemsRead db User {userId} contactId itemsRange_ = do
currentTs <- getCurrentTime
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, contactId, CISRcvNew)
case itemsRange_ of
Just (fromItemId, toItemId) ->
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, contactId, fromItemId, toItemId, CISRcvNew)
_ ->
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, contactId, CISRcvNew)
getDirectUnreadTimedItems :: DB.Connection -> User -> ContactId -> IO [(ChatItemId, Int)]
getDirectUnreadTimedItems db User {userId} contactId =
DB.query
db
[sql|
SELECT chat_item_id, timed_ttl
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_status = ? AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
|]
(userId, contactId, CISRcvNew)
getDirectUnreadTimedItems :: DB.Connection -> User -> ContactId -> Maybe (ChatItemId, ChatItemId) -> IO [(ChatItemId, Int)]
getDirectUnreadTimedItems db User {userId} contactId itemsRange_ = case itemsRange_ of
Just (fromItemId, toItemId) ->
DB.query
db
[sql|
SELECT chat_item_id, timed_ttl
FROM chat_items
WHERE user_id = ? AND contact_id = ?
AND chat_item_id >= ? AND chat_item_id <= ?
AND item_status = ?
AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
AND (item_live IS NULL OR item_live = ?)
|]
(userId, contactId, fromItemId, toItemId, CISRcvNew, False)
_ ->
DB.query
db
[sql|
SELECT chat_item_id, timed_ttl
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_status = ? AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
|]
(userId, contactId, CISRcvNew)
updateDirectChatItemsReadList :: DB.Connection -> User -> ContactId -> NonEmpty ChatItemId -> IO [(ChatItemId, Int)]
updateDirectChatItemsReadList db user@User {userId} contactId itemIds = do
currentTs <- getCurrentTime
catMaybes . L.toList <$> mapM (getUpdateDirectItem currentTs) itemIds
updateDirectChatItemsReadList db user contactId itemIds = do
catMaybes . L.toList <$> mapM getUpdateDirectItem itemIds
where
getUpdateDirectItem currentTs itemId = do
ttl_ <- maybeFirstRow fromOnly getUnreadTimedItem
setDirectChatItemRead_ db user contactId itemId currentTs
pure $ (itemId,) <$> ttl_
where
getUnreadTimedItem =
DB.query
db
[sql|
SELECT timed_ttl
FROM chat_items
WHERE user_id = ? AND contact_id = ? AND item_status = ? AND chat_item_id = ? AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
|]
(userId, contactId, CISRcvNew, itemId)
setDirectChatItemRead :: DB.Connection -> User -> ContactId -> ChatItemId -> IO ()
setDirectChatItemRead db user contactId itemId =
setDirectChatItemRead_ db user contactId itemId =<< getCurrentTime
setDirectChatItemRead_ :: DB.Connection -> User -> ContactId -> ChatItemId -> UTCTime -> IO ()
setDirectChatItemRead_ db User {userId} contactId itemId currentTs =
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND contact_id = ? AND item_status = ? AND chat_item_id = ?
|]
(CISRcvRead, currentTs, userId, contactId, CISRcvNew, itemId)
getUpdateDirectItem chatItemId = do
let itemsRange = Just (chatItemId, chatItemId)
timedItem <- maybeFirstRow id $ getDirectUnreadTimedItems db user contactId itemsRange
updateDirectChatItemsRead db user contactId itemsRange
pure timedItem
setDirectChatItemsDeleteAt :: DB.Connection -> User -> ContactId -> [(ChatItemId, Int)] -> UTCTime -> IO [(ChatItemId, UTCTime)]
setDirectChatItemsDeleteAt db User {userId} contactId itemIds currentTs = forM itemIds $ \(chatItemId, ttl) -> do
@@ -1736,55 +1735,61 @@ setDirectChatItemsDeleteAt db User {userId} contactId itemIds currentTs = forM i
(deleteAt, userId, contactId, chatItemId)
pure (chatItemId, deleteAt)
updateGroupChatItemsRead :: DB.Connection -> User -> GroupId -> IO ()
updateGroupChatItemsRead db User {userId} groupId = do
updateGroupChatItemsRead :: DB.Connection -> User -> GroupId -> Maybe (ChatItemId, ChatItemId) -> IO ()
updateGroupChatItemsRead db User {userId} groupId itemsRange_ = do
currentTs <- getCurrentTime
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND group_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, groupId, CISRcvNew)
case itemsRange_ of
Just (fromItemId, toItemId) ->
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND group_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, groupId, fromItemId, toItemId, CISRcvNew)
_ ->
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND group_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, groupId, CISRcvNew)
getGroupUnreadTimedItems :: DB.Connection -> User -> GroupId -> IO [(ChatItemId, Int)]
getGroupUnreadTimedItems db User {userId} groupId =
DB.query
db
[sql|
SELECT chat_item_id, timed_ttl
FROM chat_items
WHERE user_id = ? AND group_id = ? AND item_status = ? AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
|]
(userId, groupId, CISRcvNew)
getGroupUnreadTimedItems :: DB.Connection -> User -> GroupId -> Maybe (ChatItemId, ChatItemId) -> IO [(ChatItemId, Int)]
getGroupUnreadTimedItems db User {userId} groupId itemsRange_ = case itemsRange_ of
Just (fromItemId, toItemId) ->
DB.query
db
[sql|
SELECT chat_item_id, timed_ttl
FROM chat_items
WHERE user_id = ? AND group_id = ?
AND chat_item_id >= ? AND chat_item_id <= ?
AND item_status = ?
AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
AND (item_live IS NULL OR item_live = ?)
|]
(userId, groupId, fromItemId, toItemId, CISRcvNew, False)
_ ->
DB.query
db
[sql|
SELECT chat_item_id, timed_ttl
FROM chat_items
WHERE user_id = ? AND group_id = ? AND item_status = ? AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
|]
(userId, groupId, CISRcvNew)
updateGroupChatItemsReadList :: DB.Connection -> User -> GroupId -> NonEmpty ChatItemId -> IO [(ChatItemId, Int)]
updateGroupChatItemsReadList db User {userId} groupId itemIds = do
currentTs <- getCurrentTime
catMaybes . L.toList <$> mapM (getUpdateGroupItem currentTs) itemIds
updateGroupChatItemsReadList db user groupId itemIds = do
catMaybes . L.toList <$> mapM getUpdateGroupItem itemIds
where
getUpdateGroupItem currentTs itemId = do
ttl_ <- maybeFirstRow fromOnly getUnreadTimedItem
setItemRead
pure $ (itemId,) <$> ttl_
where
getUnreadTimedItem =
DB.query
db
[sql|
SELECT timed_ttl
FROM chat_items
WHERE user_id = ? AND group_id = ? AND item_status = ? AND chat_item_id = ? AND timed_ttl IS NOT NULL AND timed_delete_at IS NULL
|]
(userId, groupId, CISRcvNew, itemId)
setItemRead =
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND group_id = ? AND item_status = ? AND chat_item_id = ?
|]
(CISRcvRead, currentTs, userId, groupId, CISRcvNew, itemId)
getUpdateGroupItem chatItemId = do
let itemsRange = Just (chatItemId, chatItemId)
timedItem <- maybeFirstRow id $ getGroupUnreadTimedItems db user groupId itemsRange
updateGroupChatItemsRead db user groupId itemsRange
pure timedItem
setGroupChatItemsDeleteAt :: DB.Connection -> User -> GroupId -> [(ChatItemId, Int)] -> UTCTime -> IO [(ChatItemId, UTCTime)]
setGroupChatItemsDeleteAt db User {userId} groupId itemIds currentTs = forM itemIds $ \(chatItemId, ttl) -> do
@@ -1795,16 +1800,26 @@ setGroupChatItemsDeleteAt db User {userId} groupId itemIds currentTs = forM item
(deleteAt, userId, groupId, chatItemId)
pure (chatItemId, deleteAt)
updateLocalChatItemsRead :: DB.Connection -> User -> NoteFolderId -> IO ()
updateLocalChatItemsRead db User {userId} noteFolderId = do
updateLocalChatItemsRead :: DB.Connection -> User -> NoteFolderId -> Maybe (ChatItemId, ChatItemId) -> IO ()
updateLocalChatItemsRead db User {userId} noteFolderId itemsRange_ = do
currentTs <- getCurrentTime
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND note_folder_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, noteFolderId, CISRcvNew)
case itemsRange_ of
Just (fromItemId, toItemId) ->
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND note_folder_id = ? AND chat_item_id >= ? AND chat_item_id <= ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, noteFolderId, fromItemId, toItemId, CISRcvNew)
_ ->
DB.execute
db
[sql|
UPDATE chat_items SET item_status = ?, updated_at = ?
WHERE user_id = ? AND note_folder_id = ? AND item_status = ?
|]
(CISRcvRead, currentTs, userId, noteFolderId, CISRcvNew)
type MaybeCIFIleRow = (Maybe Int64, Maybe String, Maybe Integer, Maybe FilePath, Maybe C.SbKey, Maybe C.CbNonce, Maybe ACIFileStatus, Maybe FileProtocol)
+1 -2
View File
@@ -3,7 +3,6 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -165,7 +164,7 @@ runTerminalOutput ct cc@ChatController {outputQ, showLiveItems, logFilePath} Cha
(True, CISRcvNew) -> do
let itemId = chatItemId' ci
chatRef = chatInfoToRef chat
void $ runReaderT (runExceptT $ processChatCommand (APIChatItemsRead chatRef [itemId])) cc
void $ runReaderT (runExceptT $ processChatCommand (APIChatRead chatRef (Just (itemId, itemId)))) cc
_ -> pure ()
logResponse path s = withFile path AppendMode $ \h -> mapM_ (hPutStrLn h . unStyle) s
getRemoteUser rhId =
+1
View File
@@ -74,6 +74,7 @@ testOpts =
ChatOpts
{ coreOptions = testCoreOpts,
deviceName = Nothing,
userDisplayName = Nothing,
chatCmd = "",
chatCmdDelay = 3,
chatCmdLog = CCLNone,
+2
View File
@@ -217,6 +217,8 @@ testAddContact = versionTestMatrix2 runTestAddContact
-- search
alice #$> ("/_get chat @2 count=100 search=ello ther", chat, [(1, "hello there 🙂"), (0, "hello there")])
-- read messages
alice #$> ("/_read chat @2 from=1 to=100", id, "ok")
bob #$> ("/_read chat @2 from=1 to=100", id, "ok")
alice #$> ("/_read chat @2", id, "ok")
bob #$> ("/_read chat @2", id, "ok")
alice #$> ("/read user", id, "ok")
+3
View File
@@ -353,6 +353,9 @@ testGroupShared alice bob cath checkMessages directConnections = do
bob #$> ("/_get chat #1 count=100", chat, groupFeatures <> [(0, "connected"), (0, "added cath (Catherine)"), (0, "connected"), (0, "hello"), (1, "hi there"), (0, "hey team")])
cath @@@ [("@bob", "hey"), ("#team", "hey team"), ("@alice", "received invitation to join group team as admin")]
cath #$> ("/_get chat #1 count=100", chat, groupFeatures <> [(0, "connected"), (0, "connected"), (0, "hello"), (0, "hi there"), (1, "hey team")])
alice #$> ("/_read chat #1 from=1 to=100", id, "ok")
bob #$> ("/_read chat #1 from=1 to=100", id, "ok")
cath #$> ("/_read chat #1 from=1 to=100", id, "ok")
alice #$> ("/_read chat #1", id, "ok")
bob #$> ("/_read chat #1", id, "ok")
cath #$> ("/_read chat #1", id, "ok")
+1 -1
View File
@@ -41,7 +41,7 @@ testNotes tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
alice ##> "/? keep"
alice <# "* keep in mind"
alice #$> ("/_read chat *1", id, "ok")
alice #$> ("/_read chat *1 from=1 to=100", id, "ok")
alice ##> "/_unread chat *1 on"
alice <## "ok"