From 47c6daf0cc1f29da45fa066fa411f34eedb545d4 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Wed, 22 Mar 2023 18:48:38 +0400 Subject: [PATCH] xftp: set app tmp directory (#2054) --- cabal.project | 2 +- scripts/nix/sha256map.nix | 2 +- src/Simplex/Chat.hs | 26 ++++++++---- src/Simplex/Chat/Controller.hs | 1 + stack.yaml | 2 +- tests/ChatClient.hs | 2 +- tests/ChatTests/Files.hs | 74 ++++++++++++++++++++++++++++++++++ 7 files changed, 98 insertions(+), 11 deletions(-) diff --git a/cabal.project b/cabal.project index b3943d990..332ebdc79 100644 --- a/cabal.project +++ b/cabal.project @@ -7,7 +7,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: 7e265e5c59dedaabd0b77ce55d49e0bc6fa92f20 + tag: 0df7733125add475f9de88a362bcd526091f187c source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index 1bf57f9ba..fab104c40 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."7e265e5c59dedaabd0b77ce55d49e0bc6fa92f20" = "162j0187kzwihg0pa91mwqavk93jdx5y5davl7fik8q6svvwqrpq"; + "https://github.com/simplex-chat/simplexmq.git"."0df7733125add475f9de88a362bcd526091f187c" = "09s2dimdq88lm4mb2xcl5vch2qb21llj8ss649vlxpkm69njpyj0"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/kazu-yamamoto/http2.git"."78e18f52295a7f89e828539a03fbcb24931461a3" = "05q165anvv0qrcxqbvq1dlvw0l8gmsa9kl6sazk1mfhz2g0yimdk"; "https://github.com/simplex-chat/direct-sqlcipher.git"."34309410eb2069b029b8fc1872deb1e0db123294" = "0kwkmhyfsn2lixdlgl15smgr1h5gjk7fky6abzh8rng2h5ymnffd"; diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 7464c1f3a..d7963c287 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -78,7 +78,7 @@ import qualified Simplex.Messaging.TMap as TM import Simplex.Messaging.Transport.Client (defaultSocksProxy) import Simplex.Messaging.Util import System.Exit (exitFailure, exitSuccess) -import System.FilePath (combine, splitExtensions, takeFileName) +import System.FilePath (combine, splitExtensions, takeFileName, (>)) import System.IO (Handle, IOMode (..), SeekMode (..), hFlush, openFile, stdout) import Text.Read (readMaybe) import UnliftIO.Async @@ -219,9 +219,15 @@ startChatController subConns enableExpireCIs = do then Just <$> async (subscribeUsers users) else pure Nothing atomically . writeTVar s $ Just (a1, a2) + startXFTP startCleanupManager when enableExpireCIs $ startExpireCIs users pure a1 + startXFTP = do + tmp <- readTVarIO =<< asks tempDirectory + runExceptT (withAgent $ \a -> xftpStartWorkers a tmp) >>= \case + Left e -> liftIO $ print $ "Error starting XFTP workers: " <> show e + Right _ -> pure () startCleanupManager = do cleanupAsync <- asks cleanupManagerAsync readTVarIO cleanupAsync >>= \case @@ -355,6 +361,11 @@ processChatCommand = \case withAgent (`suspendAgent` t) ok_ ResubscribeAllConnections -> withStore' getUsers >>= subscribeUsers >> ok_ + -- has to be called before StartChat + SetTempFolder tf -> do + createDirectoryIfMissing True tf + asks tempDirectory >>= atomically . (`writeTVar` Just tf) + ok_ SetFilesFolder ff -> do createDirectoryIfMissing True ff asks filesFolder >>= atomically . (`writeTVar` Just ff) @@ -535,8 +546,8 @@ processChatCommand = \case let fileName = takeFileName file fileDescr = FileDescr {fileDescrText = "", fileDescrPartNo = 0, fileDescrComplete = False} fInv = xftpFileInvitation fileName fileSize fileDescr - tmp <- readTVarIO =<< asks tempDirectory - aFileId <- withAgent $ \a -> xftpSendFile a (aUserId user) file n tmp + fsFilePath <- toFSFilePath file + aFileId <- withAgent $ \a -> xftpSendFile a (aUserId user) fsFilePath n -- TODO CRSndFileStart event for XFTP ft@FileTransferMeta {fileId} <- withStore' $ \db -> createSndFileTransferXFTP db user contactOrGroup file fInv $ AgentSndFileId aFileId let ciFile = CIFile {fileId, fileName, fileSize, filePath = Just file, fileStatus = CIFSSndStored} @@ -1758,7 +1769,7 @@ callStatusItemContent user Contact {contactId} chatItemId receivedStatus = do -- used during file transfer for actual operations with file system toFSFilePath :: ChatMonad m => FilePath -> m FilePath toFSFilePath f = - maybe f (<> "/" <> f) <$> (readTVarIO =<< asks filesFolder) + maybe f (> f) <$> (readTVarIO =<< asks filesFolder) acceptFileReceive :: forall m. ChatMonad m => User -> RcvFileTransfer -> Maybe Bool -> Maybe FilePath -> m AChatItem acceptFileReceive user@User {userId} RcvFileTransfer {fileId, xftpRcvFile, fileInvitation = FileInvitation {fileName = fName, fileConnReq, fileInline, fileSize}, fileStatus, grpMemberId} rcvInline_ filePath_ = do @@ -1822,8 +1833,7 @@ receiveViaCompleteFD :: ChatMonad m => User -> FileTransferId -> RcvFileDescr -> receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete} = when fileDescrComplete $ do rd <- parseRcvFileDescription fileDescrText - tmp <- readTVarIO =<< asks tempDirectory - aFileId <- withAgent $ \a -> xftpReceiveFile a (aUserId user) rd tmp + aFileId <- withAgent $ \a -> xftpReceiveFile a (aUserId user) rd startReceivingFile user fileId withStore' $ \db -> updateRcvFileAgentId db fileId (AgentRcvFileId aFileId) @@ -2260,7 +2270,8 @@ processAgentMsgRcvFile _corrId aFileId msg = case liveRcvFileTransferPath ft of Nothing -> throwChatError $ CEInternalError "no target path for received XFTP file" Just targetPath -> do - renameFile xftpPath targetPath + fsTargetPath <- toFSFilePath targetPath + renameFile xftpPath fsTargetPath ci <- withStore $ \db -> do liftIO $ do updateRcvFileStatus db fileId FSComplete @@ -4202,6 +4213,7 @@ chatCommandP = "/_app activate" $> APIActivateChat, "/_app suspend " *> (APISuspendChat <$> A.decimal), "/_resubscribe all" $> ResubscribeAllConnections, + "/_temp_folder " *> (SetTempFolder <$> filePath), "/_files_folder " *> (SetFilesFolder <$> filePath), "/_db export " *> (APIExportArchive <$> jsonP), "/_db import " *> (APIImportArchive <$> jsonP), diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 0cb8f8441..a4c77ca88 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -196,6 +196,7 @@ data ChatCommand | APIActivateChat | APISuspendChat {suspendTimeout :: Int} | ResubscribeAllConnections + | SetTempFolder FilePath | SetFilesFolder FilePath | SetIncognito Bool | APIExportArchive ArchiveConfig diff --git a/stack.yaml b/stack.yaml index 4bca20bc3..6e935ec9f 100644 --- a/stack.yaml +++ b/stack.yaml @@ -49,7 +49,7 @@ extra-deps: # - simplexmq-1.0.0@sha256:34b2004728ae396e3ae449cd090ba7410781e2b3cefc59259915f4ca5daa9ea8,8561 # - ../simplexmq - github: simplex-chat/simplexmq - commit: 7e265e5c59dedaabd0b77ce55d49e0bc6fa92f20 + commit: 0df7733125add475f9de88a362bcd526091f187c - github: kazu-yamamoto/http2 commit: 78e18f52295a7f89e828539a03fbcb24931461a3 # - ../direct-sqlcipher diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index 3d782603a..c0107c6f7 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -320,7 +320,7 @@ xftpServerConfig = XFTPServerConfig { xftpPort = xftpTestPort, fileIdSize = 16, - storeLogFile = Nothing, + storeLogFile = Just "tests/tmp/xftp-server-store.log", filesPath = xftpServerFiles, fileSizeQuota = Nothing, allowedChunkSizes = [kb 128, kb 256, mb 1, mb 4], diff --git a/tests/ChatTests/Files.hs b/tests/ChatTests/Files.hs index 396cd4839..8b776fec2 100644 --- a/tests/ChatTests/Files.hs +++ b/tests/ChatTests/Files.hs @@ -50,6 +50,8 @@ chatFileTests = do xit "send and receive file to group, fully asynchronous" testAsyncGroupFileTransfer describe "file transfer over XFTP" $ do it "send and receive file" testXFTPFileTransfer + it "with relative paths: send and receive file" testXFTPWithRelativePaths + it "continue receiving file after restart" testXFTPContinueRcv runTestFileTransfer :: HasCallStack => TestCC -> TestCC -> IO () runTestFileTransfer alice bob = do @@ -940,6 +942,78 @@ testXFTPFileTransfer = where cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"} +testXFTPWithRelativePaths :: HasCallStack => FilePath -> IO () +testXFTPWithRelativePaths = + testChatCfg2 cfg aliceProfile bobProfile $ \alice bob -> do + withXFTPServer $ do + -- agent is passed xftp work directory only on chat start, + -- so for test we work around by stopping and starting chat + alice ##> "/_stop" + alice <## "chat stopped" + alice #$> ("/_files_folder ./tests/fixtures", id, "ok") + alice #$> ("/_temp_folder ./tests/tmp/alice_xftp", id, "ok") + alice ##> "/_start" + alice <## "chat started" + + bob ##> "/_stop" + bob <## "chat stopped" + bob #$> ("/_files_folder ./tests/tmp/bob_files", id, "ok") + bob #$> ("/_temp_folder ./tests/tmp/bob_xftp", id, "ok") + bob ##> "/_start" + bob <## "chat started" + + connectUsers alice bob + + alice #> "/f @bob test.pdf" + alice <## "use /fc 1 to cancel sending" + bob <# "alice> sends file test.pdf (266.0 KiB / 272376 bytes)" + bob <## "use /fr 1 [