cli: option to auto-accept files (#2540)

* cli: option to auto-accept files

* auto-accept works

* test

* add missing field
This commit is contained in:
Evgeny Poberezkin 2023-06-16 13:43:06 +01:00 committed by GitHub
parent c29c3179a0
commit 46c6f5e615
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 9 deletions

View File

@ -112,6 +112,7 @@ defaultChatConfig =
fileChunkSize = 15780, -- do not change fileChunkSize = 15780, -- do not change
xftpDescrPartSize = 14000, xftpDescrPartSize = 14000,
inlineFiles = defaultInlineFilesConfig, inlineFiles = defaultInlineFilesConfig,
autoAcceptFileSize = 0,
xftpFileConfig = Just defaultXFTPFileConfig, xftpFileConfig = Just defaultXFTPFileConfig,
tempDir = Nothing, tempDir = Nothing,
showReactions = False, showReactions = False,
@ -158,9 +159,9 @@ createChatDatabase filePrefix key confirmMigrations = runExceptT $ do
pure ChatDatabase {chatStore, agentStore} pure ChatDatabase {chatStore, agentStore}
newChatController :: ChatDatabase -> Maybe User -> ChatConfig -> ChatOpts -> Maybe (Notification -> IO ()) -> IO ChatController newChatController :: ChatDatabase -> Maybe User -> ChatConfig -> ChatOpts -> Maybe (Notification -> IO ()) -> IO ChatController
newChatController ChatDatabase {chatStore, agentStore} user cfg@ChatConfig {agentConfig = aCfg, defaultServers, inlineFiles, tempDir} ChatOpts {coreOptions = CoreChatOpts {smpServers, xftpServers, networkConfig, logLevel, logConnections, logServerHosts, logFile, tbqSize}, optFilesFolder, showReactions, allowInstantFiles} sendToast = do newChatController ChatDatabase {chatStore, agentStore} user cfg@ChatConfig {agentConfig = aCfg, defaultServers, inlineFiles, tempDir} ChatOpts {coreOptions = CoreChatOpts {smpServers, xftpServers, networkConfig, logLevel, logConnections, logServerHosts, logFile, tbqSize}, optFilesFolder, showReactions, allowInstantFiles, autoAcceptFileSize} sendToast = do
let inlineFiles' = if allowInstantFiles then inlineFiles else inlineFiles {sendChunks = 0, receiveInstant = False} let inlineFiles' = if allowInstantFiles || autoAcceptFileSize > 0 then inlineFiles else inlineFiles {sendChunks = 0, receiveInstant = False}
config = cfg {logLevel, showReactions, tbqSize, subscriptionEvents = logConnections, hostEvents = logServerHosts, defaultServers = configServers, inlineFiles = inlineFiles'} config = cfg {logLevel, showReactions, tbqSize, subscriptionEvents = logConnections, hostEvents = logServerHosts, defaultServers = configServers, inlineFiles = inlineFiles', autoAcceptFileSize}
sendNotification = fromMaybe (const $ pure ()) sendToast sendNotification = fromMaybe (const $ pure ()) sendToast
firstTime = dbNew chatStore firstTime = dbNew chatStore
activeTo <- newTVarIO ActiveNone activeTo <- newTVarIO ActiveNone
@ -3332,8 +3333,9 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
let ExtMsgContent _ _ itemTTL live_ = mcExtMsgContent mc let ExtMsgContent _ _ itemTTL live_ = mcExtMsgContent mc
timed_ = rcvContactCITimed ct itemTTL timed_ = rcvContactCITimed ct itemTTL
live = fromMaybe False live_ live = fromMaybe False live_
ciFile_ <- processFileInvitation fInv_ content $ \db -> createRcvFileTransfer db userId ct file_ <- processFileInvitation fInv_ content $ \db -> createRcvFileTransfer db userId ct
ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) ciFile_ timed_ live ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) (snd <$> file_) timed_ live
autoAcceptFile file_
whenContactNtfs user ct $ do whenContactNtfs user ct $ do
showMsgToast (c <> "> ") content formattedText showMsgToast (c <> "> ") content formattedText
setActive $ ActiveC c setActive $ ActiveC c
@ -3344,6 +3346,11 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
toView $ CRNewChatItem user (AChatItem SCTDirect SMDRcv (DirectChat ct) ci {reactions}) toView $ CRNewChatItem user (AChatItem SCTDirect SMDRcv (DirectChat ct) ci {reactions})
pure ci pure ci
autoAcceptFile :: Maybe (RcvFileTransfer, CIFile 'MDRcv) -> m ()
autoAcceptFile = mapM_ $ \(ft, CIFile {fileSize}) -> do
ChatConfig {autoAcceptFileSize = sz} <- asks config
when (sz > fileSize) $ receiveFile' user ft Nothing Nothing >>= toView
messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> MsgMeta -> m () messageFileDescription :: Contact -> SharedMsgId -> FileDescr -> MsgMeta -> m ()
messageFileDescription ct@Contact {contactId} sharedMsgId fileDescr msgMeta = do messageFileDescription ct@Contact {contactId} sharedMsgId fileDescr msgMeta = do
checkIntegrityCreateItem (CDDirectRcv ct) msgMeta checkIntegrityCreateItem (CDDirectRcv ct) msgMeta
@ -3380,7 +3387,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
cancelGroupMessageFile _gInfo _m _sharedMsgId _msgMeta = do cancelGroupMessageFile _gInfo _m _sharedMsgId _msgMeta = do
pure () pure ()
processFileInvitation :: Maybe FileInvitation -> MsgContent -> (DB.Connection -> FileInvitation -> Maybe InlineFileMode -> Integer -> ExceptT StoreError IO RcvFileTransfer) -> m (Maybe (CIFile 'MDRcv)) processFileInvitation :: Maybe FileInvitation -> MsgContent -> (DB.Connection -> FileInvitation -> Maybe InlineFileMode -> Integer -> ExceptT StoreError IO RcvFileTransfer) -> m (Maybe (RcvFileTransfer, CIFile 'MDRcv))
processFileInvitation fInv_ mc createRcvFT = forM fInv_ $ \fInv@FileInvitation {fileName, fileSize} -> do processFileInvitation fInv_ mc createRcvFT = forM fInv_ $ \fInv@FileInvitation {fileName, fileSize} -> do
ChatConfig {fileChunkSize} <- asks config ChatConfig {fileChunkSize} <- asks config
inline <- receiveInlineMode fInv (Just mc) fileChunkSize inline <- receiveInlineMode fInv (Just mc) fileChunkSize
@ -3392,7 +3399,7 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
withStore' $ \db -> startRcvInlineFT db user ft fPath inline withStore' $ \db -> startRcvInlineFT db user ft fPath inline
pure (Just fPath, CIFSRcvAccepted) pure (Just fPath, CIFSRcvAccepted)
_ -> pure (Nothing, CIFSRcvInvitation) _ -> pure (Nothing, CIFSRcvInvitation)
pure CIFile {fileId, fileName, fileSize, filePath, fileStatus, fileProtocol} pure (ft, CIFile {fileId, fileName, fileSize, filePath, fileStatus, fileProtocol})
messageUpdate :: Contact -> SharedMsgId -> MsgContent -> RcvMessage -> MsgMeta -> Maybe Int -> Maybe Bool -> m () messageUpdate :: Contact -> SharedMsgId -> MsgContent -> RcvMessage -> MsgMeta -> Maybe Int -> Maybe Bool -> m ()
messageUpdate ct@Contact {contactId, localDisplayName = c} sharedMsgId mc msg@RcvMessage {msgId} msgMeta ttl live_ = do messageUpdate ct@Contact {contactId, localDisplayName = c} sharedMsgId mc msg@RcvMessage {msgId} msgMeta ttl live_ = do
@ -3503,8 +3510,9 @@ processAgentMessageConn user@User {userId} corrId agentConnId agentMessage = do
let ExtMsgContent _ _ itemTTL live_ = mcExtMsgContent mc let ExtMsgContent _ _ itemTTL live_ = mcExtMsgContent mc
timed_ = rcvGroupCITimed gInfo itemTTL timed_ = rcvGroupCITimed gInfo itemTTL
live = fromMaybe False live_ live = fromMaybe False live_
ciFile_ <- processFileInvitation fInv_ content $ \db -> createRcvGroupFileTransfer db userId m file_ <- processFileInvitation fInv_ content $ \db -> createRcvGroupFileTransfer db userId m
ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) ciFile_ timed_ live ChatItem {formattedText} <- newChatItem (CIRcvMsgContent content) (snd <$> file_) timed_ live
autoAcceptFile file_
let g = groupName' gInfo let g = groupName' gInfo
whenGroupNtfs user gInfo $ do whenGroupNtfs user gInfo $ do
showMsgToast ("#" <> g <> " " <> c <> "> ") content formattedText showMsgToast ("#" <> g <> " " <> c <> "> ") content formattedText

View File

@ -103,6 +103,7 @@ data ChatConfig = ChatConfig
fileChunkSize :: Integer, fileChunkSize :: Integer,
xftpDescrPartSize :: Int, xftpDescrPartSize :: Int,
inlineFiles :: InlineFilesConfig, inlineFiles :: InlineFilesConfig,
autoAcceptFileSize :: Integer,
xftpFileConfig :: Maybe XFTPFileConfig, -- Nothing - XFTP is disabled xftpFileConfig :: Maybe XFTPFileConfig, -- Nothing - XFTP is disabled
tempDir :: Maybe FilePath, tempDir :: Maybe FilePath,
showReactions :: Bool, showReactions :: Bool,

View File

@ -130,6 +130,7 @@ mobileChatOpts dbFilePrefix dbKey =
optFilesFolder = Nothing, optFilesFolder = Nothing,
showReactions = False, showReactions = False,
allowInstantFiles = True, allowInstantFiles = True,
autoAcceptFileSize = 0,
muteNotifications = True, muteNotifications = True,
maintenance = True maintenance = True
} }

View File

@ -22,6 +22,7 @@ import qualified Data.ByteString.Char8 as B
import Numeric.Natural (Natural) import Numeric.Natural (Natural)
import Options.Applicative import Options.Applicative
import Simplex.Chat.Controller (ChatLogLevel (..), updateStr, versionNumber, versionString) import Simplex.Chat.Controller (ChatLogLevel (..), updateStr, versionNumber, versionString)
import Simplex.FileTransfer.Description (mb)
import Simplex.Messaging.Client (NetworkConfig (..), defaultNetworkConfig) import Simplex.Messaging.Client (NetworkConfig (..), defaultNetworkConfig)
import Simplex.Messaging.Encoding.String import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (parseAll) import Simplex.Messaging.Parsers (parseAll)
@ -37,6 +38,7 @@ data ChatOpts = ChatOpts
optFilesFolder :: Maybe FilePath, optFilesFolder :: Maybe FilePath,
showReactions :: Bool, showReactions :: Bool,
allowInstantFiles :: Bool, allowInstantFiles :: Bool,
autoAcceptFileSize :: Integer,
muteNotifications :: Bool, muteNotifications :: Bool,
maintenance :: Bool maintenance :: Bool
} }
@ -236,6 +238,15 @@ chatOptsP appDir defaultDbFileName = do
<> short 'f' <> short 'f'
<> help "Send and receive instant files without acceptance" <> help "Send and receive instant files without acceptance"
) )
autoAcceptFileSize <-
flag' (mb 1) (short 'a' <> help "Automatically accept files up to 1MB")
<|> option
auto
( long "auto-accept-files"
<> metavar "FILE_SIZE"
<> help "Automatically accept files up to specified size"
<> value 0
)
muteNotifications <- muteNotifications <-
switch switch
( long "mute" ( long "mute"
@ -256,6 +267,7 @@ chatOptsP appDir defaultDbFileName = do
optFilesFolder, optFilesFolder,
showReactions, showReactions,
allowInstantFiles, allowInstantFiles,
autoAcceptFileSize,
muteNotifications, muteNotifications,
maintenance maintenance
} }

View File

@ -74,6 +74,7 @@ testOpts =
optFilesFolder = Nothing, optFilesFolder = Nothing,
showReactions = True, showReactions = True,
allowInstantFiles = True, allowInstantFiles = True,
autoAcceptFileSize = 0,
muteNotifications = True, muteNotifications = True,
maintenance = False maintenance = False
} }

View File

@ -1,3 +1,4 @@
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PostfixOperators #-} {-# LANGUAGE PostfixOperators #-}
@ -68,6 +69,7 @@ chatFileTests = do
xit' "receive file marked to receive on chat start" testXFTPMarkToReceive xit' "receive file marked to receive on chat start" testXFTPMarkToReceive
it "error receiving file" testXFTPRcvError it "error receiving file" testXFTPRcvError
it "cancel receiving file, repeat receive" testXFTPCancelRcvRepeat it "cancel receiving file, repeat receive" testXFTPCancelRcvRepeat
it "should accept file automatically with CLI option" testAutoAcceptFile
runTestFileTransfer :: HasCallStack => TestCC -> TestCC -> IO () runTestFileTransfer :: HasCallStack => TestCC -> TestCC -> IO ()
runTestFileTransfer alice bob = do runTestFileTransfer alice bob = do
@ -1386,6 +1388,32 @@ testXFTPCancelRcvRepeat =
where where
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"} cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"}
testAutoAcceptFile :: HasCallStack => FilePath -> IO ()
testAutoAcceptFile =
testChatCfgOpts2 cfg opts aliceProfile bobProfile $ \alice bob -> withXFTPServer $ do
connectUsers alice bob
bob ##> "/_files_folder ./tests/tmp/bob_files"
bob <## "ok"
alice #> "/f @bob ./tests/fixtures/test.jpg"
alice <## "use /fc 1 to cancel sending"
alice <## "completed uploading file 1 (test.jpg) for bob"
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
bob <## "saving file 1 from alice to test.jpg"
bob <## "started receiving file 1 (test.jpg) from alice"
bob <## "completed receiving file 1 (test.jpg) from alice"
(bob </)
alice #> "/f @bob ./tests/fixtures/test_1MB.pdf"
alice <## "use /fc 2 to cancel sending"
alice <## "completed uploading file 2 (test_1MB.pdf) for bob"
bob <# "alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes)"
bob <## "use /fr 2 [<dir>/ | <path>] to receive it"
-- no auto accept for large files
(bob </)
where
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"}
opts = (testOpts :: ChatOpts) {autoAcceptFileSize = 200000}
xftpCLI :: [String] -> IO [String] xftpCLI :: [String] -> IO [String]
xftpCLI params = lines <$> capture_ (withArgs params xftpClientCLI) xftpCLI params = lines <$> capture_ (withArgs params xftpClientCLI)