cli: add --user-display-name option

Selects or creates the active user non-interactively:
- no active user: create one with the given display name
- active user with matching localDisplayName: continue
- active user with different name: exit with error

Mutually exclusive with --create-bot-display-name.
This commit is contained in:
shum
2026-05-04 12:41:55 +00:00
parent 8d45c2cca9
commit e0b6bf114b
3 changed files with 41 additions and 22 deletions
+24 -17
View File
@@ -19,6 +19,7 @@ import Control.Monad.Except
import Control.Monad.Reader
import qualified Data.ByteString.Char8 as B
import Data.List (find)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
import Data.Time.Clock (getCurrentTime)
@@ -43,7 +44,7 @@ import Text.Read (readMaybe)
import UnliftIO.Async
simplexChatCore :: ChatConfig -> ChatOpts -> (User -> ChatController -> IO ()) -> IO ()
simplexChatCore cfg@ChatConfig {confirmMigrations, testView, chatHooks} opts@ChatOpts {coreOptions = coreOptions@CoreChatOpts {dbOptions, logAgent, yesToUpMigrations, migrationBackupPath, maintenance}, createBot} chat =
simplexChatCore cfg@ChatConfig {confirmMigrations, testView, chatHooks} opts@ChatOpts {coreOptions = coreOptions@CoreChatOpts {dbOptions, logAgent, yesToUpMigrations, migrationBackupPath, maintenance}, createBot, userDisplayName} chat =
case logAgent of
Just level -> do
setLogLevel level
@@ -58,10 +59,14 @@ simplexChatCore cfg@ChatConfig {confirmMigrations, testView, chatHooks} opts@Cha
run db@ChatDatabase {chatStore} = do
users <- withTransaction chatStore getUsers
u_ <- selectActiveUser coreOptions chatStore users
forM_ ((,) <$> userDisplayName <*> u_) $ \(name, User {localDisplayName}) ->
when (localDisplayName /= name) $ do
putStrLn $ "Active user display name " <> show localDisplayName <> " does not match --user-display-name " <> show name
exitFailure
let backgroundMode = maintenance
cc <- newChatController db u_ cfg opts backgroundMode
forM_ (preStartHook chatHooks) ($ cc)
u <- maybe (noMaintenance >> createActiveUser cc coreOptions createBot) pure u_
u <- maybe (noMaintenance >> createActiveUser cc coreOptions createBot userDisplayName) pure u_
unless testView $ putStrLn $ "Current user: " <> userStr u
runSimplexChat cfg opts u cc chat
noMaintenance = when maintenance $ do
@@ -116,24 +121,26 @@ selectActiveUser CoreChatOpts {chatRelay} st users
let user = users !! (n - 1)
in Just <$> withTransaction st (`setActiveUser` user)
createActiveUser :: ChatController -> CoreChatOpts -> Maybe CreateBotOpts -> IO User
createActiveUser cc CoreChatOpts {chatRelay} = \case
createActiveUser :: ChatController -> CoreChatOpts -> Maybe CreateBotOpts -> Maybe Text -> IO User
createActiveUser cc CoreChatOpts {chatRelay} createBot_ userDisplayName_ = case createBot_ of
Just CreateBotOpts {botDisplayName, allowFiles} -> do
let preferences = if allowFiles then Nothing else Just emptyChatPrefs {files = Just FilesPreference {allow = FANo}}
createUser exitFailure $ (mkProfile botDisplayName) {peerType = Just CPTBot, preferences}
Nothing
| chatRelay -> do
putStrLn
"No chat relay user profile found, it will be created now.\n\
\Please choose chat relay display name."
loop
| otherwise -> do
putStrLn
"No user profiles found, it will be created now.\n\
\Please choose your display name.\n\
\It will be sent to your contacts when you connect.\n\
\It is only stored on your device and you can change it later."
loop
Nothing -> case userDisplayName_ of
Just displayName -> createUser exitFailure $ mkProfile displayName
Nothing
| chatRelay -> do
putStrLn
"No chat relay user profile found, it will be created now.\n\
\Please choose chat relay display name."
loop
| otherwise -> do
putStrLn
"No user profiles found, it will be created now.\n\
\Please choose your display name.\n\
\It will be sent to your contacts when you connect.\n\
\It is only stored on your device and you can change it later."
loop
where
loop = do
displayName <- T.pack <$> withPrompt "display name: " getLine
+2 -1
View File
@@ -271,7 +271,8 @@ mobileChatOpts dbOptions =
autoAcceptFileSize = 0,
muteNotifications = True,
markRead = False,
createBot = Nothing
createBot = Nothing,
userDisplayName = Nothing
}
defaultMobileConfig :: ChatConfig
+15 -4
View File
@@ -22,7 +22,7 @@ where
import Control.Logger.Simple (LogLevel (..))
import qualified Data.Attoparsec.ByteString.Char8 as A
import qualified Data.ByteString.Char8 as B
import Data.Maybe (fromMaybe)
import Data.Maybe (fromMaybe, isJust)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
@@ -50,7 +50,8 @@ data ChatOpts = ChatOpts
autoAcceptFileSize :: Integer,
muteNotifications :: Bool,
markRead :: Bool,
createBot :: Maybe CreateBotOpts
createBot :: Maybe CreateBotOpts,
userDisplayName :: Maybe Text
}
data CoreChatOpts = CoreChatOpts
@@ -402,6 +403,13 @@ chatOptsP appDir defaultDbName = do
( long "create-bot-allow-files"
<> help "Flag for created bot to allow files (only allowed together with --create-bot option)"
)
userDisplayName <-
optional $
strOption
( long "user-display-name"
<> metavar "NAME"
<> help "Use existing active user with this display name, or create one on the first start (incompatible with --create-bot-display-name)"
)
pure
ChatOpts
{ coreOptions,
@@ -417,10 +425,13 @@ chatOptsP appDir defaultDbName = do
muteNotifications,
markRead,
createBot = case createBotDisplayName of
Just botDisplayName -> Just CreateBotOpts {botDisplayName, allowFiles = createBotAllowFiles}
Just botDisplayName
| isJust userDisplayName -> error "--user-display-name and --create-bot-display-name are mutually exclusive"
| otherwise -> Just CreateBotOpts {botDisplayName, allowFiles = createBotAllowFiles}
Nothing
| createBotAllowFiles -> error "--create-bot-allow-files option requires --create-bot-name option"
| otherwise -> Nothing
| otherwise -> Nothing,
userDisplayName
}
parseProtocolServers :: ProtocolTypeI p => ReadM [ProtoServerWithAuth p]