core, ios: mark files to receive from NSE, receive marked files on chat start (#2218)
This commit is contained in:
parent
17bdd2a1d2
commit
4d700d113d
@ -1324,6 +1324,8 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
|||||||
if active(user) {
|
if active(user) {
|
||||||
m.updateGroup(groupInfo)
|
m.updateGroup(groupInfo)
|
||||||
}
|
}
|
||||||
|
case let .rcvFileAccepted(user, aChatItem): // usually rcvFileAccepted is a response, but it's also an event for XFTP files auto-accepted from NSE
|
||||||
|
chatItemSimpleUpdate(user, aChatItem)
|
||||||
case let .rcvFileStart(user, aChatItem):
|
case let .rcvFileStart(user, aChatItem):
|
||||||
chatItemSimpleUpdate(user, aChatItem)
|
chatItemSimpleUpdate(user, aChatItem)
|
||||||
case let .rcvFileComplete(user, aChatItem):
|
case let .rcvFileComplete(user, aChatItem):
|
||||||
|
@ -272,28 +272,25 @@ func receivedMsgNtf(_ res: ChatResponse) async -> (String, NSENotification)? {
|
|||||||
ntfBadgeCountGroupDefault.set(max(0, ntfBadgeCountGroupDefault.get() - 1))
|
ntfBadgeCountGroupDefault.set(max(0, ntfBadgeCountGroupDefault.get() - 1))
|
||||||
}
|
}
|
||||||
if case .image = cItem.content.msgContent {
|
if case .image = cItem.content.msgContent {
|
||||||
if let file = cItem.file,
|
if let file = cItem.file,
|
||||||
file.fileProtocol == .smp,
|
file.fileSize <= MAX_IMAGE_SIZE_AUTO_RCV,
|
||||||
file.fileSize <= MAX_IMAGE_SIZE_AUTO_RCV,
|
privacyAcceptImagesGroupDefault.get() {
|
||||||
privacyAcceptImagesGroupDefault.get() {
|
cItem = autoReceiveFile(file) ?? cItem
|
||||||
cItem = apiReceiveFile(fileId: file.fileId)?.chatItem ?? cItem
|
}
|
||||||
}
|
|
||||||
} else if case .video = cItem.content.msgContent {
|
} else if case .video = cItem.content.msgContent {
|
||||||
if let file = cItem.file,
|
if let file = cItem.file,
|
||||||
file.fileProtocol == .smp,
|
|
||||||
file.fileSize <= MAX_VIDEO_SIZE_AUTO_RCV,
|
file.fileSize <= MAX_VIDEO_SIZE_AUTO_RCV,
|
||||||
privacyAcceptImagesGroupDefault.get() {
|
privacyAcceptImagesGroupDefault.get() {
|
||||||
cItem = apiReceiveFile(fileId: file.fileId)?.chatItem ?? cItem
|
cItem = autoReceiveFile(file) ?? cItem
|
||||||
}
|
}
|
||||||
} else if case .voice = cItem.content.msgContent { // TODO check inlineFileMode != IFMSent
|
} else if case .voice = cItem.content.msgContent { // TODO check inlineFileMode != IFMSent
|
||||||
if let file = cItem.file,
|
if let file = cItem.file,
|
||||||
file.fileProtocol == .smp,
|
|
||||||
file.fileSize <= MAX_IMAGE_SIZE,
|
file.fileSize <= MAX_IMAGE_SIZE,
|
||||||
file.fileSize > MAX_VOICE_MESSAGE_SIZE_INLINE_SEND,
|
file.fileSize > MAX_VOICE_MESSAGE_SIZE_INLINE_SEND,
|
||||||
privacyAcceptImagesGroupDefault.get() {
|
privacyAcceptImagesGroupDefault.get() {
|
||||||
cItem = apiReceiveFile(fileId: file.fileId)?.chatItem ?? cItem
|
cItem = autoReceiveFile(file) ?? cItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ntf: NSENotification = cInfo.ntfsEnabled ? .nse(notification: createMessageReceivedNtf(user, cInfo, cItem)) : .empty
|
let ntf: NSENotification = cInfo.ntfsEnabled ? .nse(notification: createMessageReceivedNtf(user, cInfo, cItem)) : .empty
|
||||||
return cItem.showMutableNotification ? (aChatItem.chatId, ntf) : nil
|
return cItem.showMutableNotification ? (aChatItem.chatId, ntf) : nil
|
||||||
case let .rcvFileSndCancelled(_, aChatItem, _):
|
case let .rcvFileSndCancelled(_, aChatItem, _):
|
||||||
@ -401,6 +398,22 @@ func apiReceiveFile(fileId: Int64, inline: Bool? = nil) -> AChatItem? {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func apiSetFileToReceive(fileId: Int64) {
|
||||||
|
let r = sendSimpleXCmd(.setFileToReceive(fileId: fileId))
|
||||||
|
if case .cmdOk = r { return }
|
||||||
|
logger.error("setFileToReceive error: \(responseError(r))")
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoReceiveFile(_ file: CIFile) -> ChatItem? {
|
||||||
|
switch file.fileProtocol {
|
||||||
|
case .smp:
|
||||||
|
return apiReceiveFile(fileId: file.fileId)?.chatItem
|
||||||
|
case .xftp:
|
||||||
|
apiSetFileToReceive(fileId: file.fileId)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setNetworkConfig(_ cfg: NetCfg) throws {
|
func setNetworkConfig(_ cfg: NetCfg) throws {
|
||||||
let r = sendSimpleXCmd(.apiSetNetworkConfig(networkConfig: cfg))
|
let r = sendSimpleXCmd(.apiSetNetworkConfig(networkConfig: cfg))
|
||||||
if case .cmdOk = r { return }
|
if case .cmdOk = r { return }
|
||||||
|
@ -100,6 +100,7 @@ public enum ChatCommand {
|
|||||||
case apiChatRead(type: ChatType, id: Int64, itemRange: (Int64, Int64))
|
case apiChatRead(type: ChatType, id: Int64, itemRange: (Int64, Int64))
|
||||||
case apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool)
|
case apiChatUnread(type: ChatType, id: Int64, unreadChat: Bool)
|
||||||
case receiveFile(fileId: Int64, inline: Bool?)
|
case receiveFile(fileId: Int64, inline: Bool?)
|
||||||
|
case setFileToReceive(fileId: Int64)
|
||||||
case cancelFile(fileId: Int64)
|
case cancelFile(fileId: Int64)
|
||||||
case showVersion
|
case showVersion
|
||||||
case string(String)
|
case string(String)
|
||||||
@ -206,6 +207,7 @@ public enum ChatCommand {
|
|||||||
return "/freceive \(fileId) inline=\(onOff(inline))"
|
return "/freceive \(fileId) inline=\(onOff(inline))"
|
||||||
}
|
}
|
||||||
return "/freceive \(fileId)"
|
return "/freceive \(fileId)"
|
||||||
|
case let .setFileToReceive(fileId): return "/_set_file_to_receive \(fileId)"
|
||||||
case let .cancelFile(fileId): return "/fcancel \(fileId)"
|
case let .cancelFile(fileId): return "/fcancel \(fileId)"
|
||||||
case .showVersion: return "/version"
|
case .showVersion: return "/version"
|
||||||
case let .string(str): return str
|
case let .string(str): return str
|
||||||
@ -302,6 +304,7 @@ public enum ChatCommand {
|
|||||||
case .apiChatRead: return "apiChatRead"
|
case .apiChatRead: return "apiChatRead"
|
||||||
case .apiChatUnread: return "apiChatUnread"
|
case .apiChatUnread: return "apiChatUnread"
|
||||||
case .receiveFile: return "receiveFile"
|
case .receiveFile: return "receiveFile"
|
||||||
|
case .setFileToReceive: return "setFileToReceive"
|
||||||
case .cancelFile: return "cancelFile"
|
case .cancelFile: return "cancelFile"
|
||||||
case .showVersion: return "showVersion"
|
case .showVersion: return "showVersion"
|
||||||
case .string: return "console command"
|
case .string: return "console command"
|
||||||
|
@ -91,6 +91,7 @@ library
|
|||||||
Simplex.Chat.Migrations.M20230328_files_protocol
|
Simplex.Chat.Migrations.M20230328_files_protocol
|
||||||
Simplex.Chat.Migrations.M20230402_protocol_servers
|
Simplex.Chat.Migrations.M20230402_protocol_servers
|
||||||
Simplex.Chat.Migrations.M20230411_extra_xftp_file_descriptions
|
Simplex.Chat.Migrations.M20230411_extra_xftp_file_descriptions
|
||||||
|
Simplex.Chat.Migrations.M20230420_rcv_files_to_receive
|
||||||
Simplex.Chat.Mobile
|
Simplex.Chat.Mobile
|
||||||
Simplex.Chat.Mobile.WebRTC
|
Simplex.Chat.Mobile.WebRTC
|
||||||
Simplex.Chat.Options
|
Simplex.Chat.Options
|
||||||
|
@ -225,7 +225,9 @@ startChatController subConns enableExpireCIs startXFTPWorkers = do
|
|||||||
then Just <$> async (subscribeUsers users)
|
then Just <$> async (subscribeUsers users)
|
||||||
else pure Nothing
|
else pure Nothing
|
||||||
atomically . writeTVar s $ Just (a1, a2)
|
atomically . writeTVar s $ Just (a1, a2)
|
||||||
when startXFTPWorkers startXFTP
|
when startXFTPWorkers $ do
|
||||||
|
startXFTP
|
||||||
|
void $ forkIO $ startFilesToReceive users
|
||||||
startCleanupManager
|
startCleanupManager
|
||||||
when enableExpireCIs $ startExpireCIs users
|
when enableExpireCIs $ startExpireCIs users
|
||||||
pure a1
|
pure a1
|
||||||
@ -257,6 +259,22 @@ subscribeUsers users = do
|
|||||||
subscribe :: [User] -> m ()
|
subscribe :: [User] -> m ()
|
||||||
subscribe = mapM_ $ runExceptT . subscribeUserConnections Agent.subscribeConnections
|
subscribe = mapM_ $ runExceptT . subscribeUserConnections Agent.subscribeConnections
|
||||||
|
|
||||||
|
startFilesToReceive :: forall m. ChatMonad' m => [User] -> m ()
|
||||||
|
startFilesToReceive users = do
|
||||||
|
let (us, us') = partition activeUser users
|
||||||
|
startReceive us
|
||||||
|
startReceive us'
|
||||||
|
where
|
||||||
|
startReceive :: [User] -> m ()
|
||||||
|
startReceive = mapM_ $ runExceptT . startReceiveUserFiles
|
||||||
|
|
||||||
|
startReceiveUserFiles :: forall m. ChatMonad m => User -> m ()
|
||||||
|
startReceiveUserFiles user = do
|
||||||
|
filesToReceive <- withStore' (`getRcvFilesToReceive` user)
|
||||||
|
forM_ filesToReceive $ \ft ->
|
||||||
|
flip catchError (toView . CRChatError (Just user)) $
|
||||||
|
toView =<< receiveFile' user ft Nothing Nothing
|
||||||
|
|
||||||
restoreCalls :: ChatMonad' m => m ()
|
restoreCalls :: ChatMonad' m => m ()
|
||||||
restoreCalls = do
|
restoreCalls = do
|
||||||
savedCalls <- fromRight [] <$> runExceptT (withStore' $ \db -> getCalls db)
|
savedCalls <- fromRight [] <$> runExceptT (withStore' $ \db -> getCalls db)
|
||||||
@ -1385,13 +1403,11 @@ processChatCommand = \case
|
|||||||
ReceiveFile fileId rcvInline_ filePath_ -> withUser $ \_ ->
|
ReceiveFile fileId rcvInline_ filePath_ -> withUser $ \_ ->
|
||||||
withChatLock "receiveFile" . procCmd $ do
|
withChatLock "receiveFile" . procCmd $ do
|
||||||
(user, ft) <- withStore $ \db -> getRcvFileTransferById db fileId
|
(user, ft) <- withStore $ \db -> getRcvFileTransferById db fileId
|
||||||
(CRRcvFileAccepted user <$> acceptFileReceive user ft rcvInline_ filePath_) `catchError` processError user ft
|
receiveFile' user ft rcvInline_ filePath_
|
||||||
where
|
SetFileToReceive fileId -> withUser $ \_ -> do
|
||||||
processError user ft = \case
|
withChatLock "setFileToReceive" . procCmd $ do
|
||||||
-- TODO AChatItem in Cancelled events
|
withStore' (`setRcvFileToReceive` fileId)
|
||||||
ChatErrorAgent (SMP SMP.AUTH) _ -> pure $ CRRcvFileAcceptedSndCancelled user ft
|
ok_
|
||||||
ChatErrorAgent (CONN DUPLICATE) _ -> pure $ CRRcvFileAcceptedSndCancelled user ft
|
|
||||||
e -> throwError e
|
|
||||||
CancelFile fileId -> withUser $ \user@User {userId} ->
|
CancelFile fileId -> withUser $ \user@User {userId} ->
|
||||||
withChatLock "cancelFile" . procCmd $
|
withChatLock "cancelFile" . procCmd $
|
||||||
withStore (\db -> getFileTransfer db user fileId) >>= \case
|
withStore (\db -> getFileTransfer db user fileId) >>= \case
|
||||||
@ -1904,6 +1920,16 @@ toFSFilePath :: ChatMonad m => FilePath -> m FilePath
|
|||||||
toFSFilePath f =
|
toFSFilePath f =
|
||||||
maybe f (</> f) <$> (readTVarIO =<< asks filesFolder)
|
maybe f (</> f) <$> (readTVarIO =<< asks filesFolder)
|
||||||
|
|
||||||
|
receiveFile' :: ChatMonad m => User -> RcvFileTransfer -> Maybe Bool -> Maybe FilePath -> m ChatResponse
|
||||||
|
receiveFile' user ft rcvInline_ filePath_ = do
|
||||||
|
(CRRcvFileAccepted user <$> acceptFileReceive user ft rcvInline_ filePath_) `catchError` processError
|
||||||
|
where
|
||||||
|
processError = \case
|
||||||
|
-- TODO AChatItem in Cancelled events
|
||||||
|
ChatErrorAgent (SMP SMP.AUTH) _ -> pure $ CRRcvFileAcceptedSndCancelled user ft
|
||||||
|
ChatErrorAgent (CONN DUPLICATE) _ -> pure $ CRRcvFileAcceptedSndCancelled user ft
|
||||||
|
e -> throwError e
|
||||||
|
|
||||||
acceptFileReceive :: forall m. ChatMonad m => User -> RcvFileTransfer -> Maybe Bool -> Maybe FilePath -> m AChatItem
|
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
|
acceptFileReceive user@User {userId} RcvFileTransfer {fileId, xftpRcvFile, fileInvitation = FileInvitation {fileName = fName, fileConnReq, fileInline, fileSize}, fileStatus, grpMemberId} rcvInline_ filePath_ = do
|
||||||
unless (fileStatus == RFSNew) $ case fileStatus of
|
unless (fileStatus == RFSNew) $ case fileStatus of
|
||||||
@ -4668,6 +4694,7 @@ chatCommandP =
|
|||||||
("/image_forward " <|> "/imgf ") *> (ForwardImage <$> chatNameP' <* A.space <*> A.decimal),
|
("/image_forward " <|> "/imgf ") *> (ForwardImage <$> chatNameP' <* A.space <*> A.decimal),
|
||||||
("/fdescription " <|> "/fd") *> (SendFileDescription <$> chatNameP' <* A.space <*> filePath),
|
("/fdescription " <|> "/fd") *> (SendFileDescription <$> chatNameP' <* A.space <*> filePath),
|
||||||
("/freceive " <|> "/fr ") *> (ReceiveFile <$> A.decimal <*> optional (" inline=" *> onOffP) <*> optional (A.space *> filePath)),
|
("/freceive " <|> "/fr ") *> (ReceiveFile <$> A.decimal <*> optional (" inline=" *> onOffP) <*> optional (A.space *> filePath)),
|
||||||
|
"/_set_file_to_receive " *> (SetFileToReceive <$> A.decimal),
|
||||||
("/fcancel " <|> "/fc ") *> (CancelFile <$> A.decimal),
|
("/fcancel " <|> "/fc ") *> (CancelFile <$> A.decimal),
|
||||||
("/fstatus " <|> "/fs ") *> (FileStatus <$> A.decimal),
|
("/fstatus " <|> "/fs ") *> (FileStatus <$> A.decimal),
|
||||||
"/simplex" $> ConnectSimplex,
|
"/simplex" $> ConnectSimplex,
|
||||||
|
@ -346,6 +346,7 @@ data ChatCommand
|
|||||||
| ForwardImage ChatName FileTransferId
|
| ForwardImage ChatName FileTransferId
|
||||||
| SendFileDescription ChatName FilePath
|
| SendFileDescription ChatName FilePath
|
||||||
| ReceiveFile {fileId :: FileTransferId, fileInline :: Maybe Bool, filePath :: Maybe FilePath}
|
| ReceiveFile {fileId :: FileTransferId, fileInline :: Maybe Bool, filePath :: Maybe FilePath}
|
||||||
|
| SetFileToReceive FileTransferId
|
||||||
| CancelFile FileTransferId
|
| CancelFile FileTransferId
|
||||||
| FileStatus FileTransferId
|
| FileStatus FileTransferId
|
||||||
| ShowProfile -- UserId (not used in UI)
|
| ShowProfile -- UserId (not used in UI)
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
|
||||||
|
module Simplex.Chat.Migrations.M20230420_rcv_files_to_receive where
|
||||||
|
|
||||||
|
import Database.SQLite.Simple (Query)
|
||||||
|
import Database.SQLite.Simple.QQ (sql)
|
||||||
|
|
||||||
|
m20230420_rcv_files_to_receive :: Query
|
||||||
|
m20230420_rcv_files_to_receive =
|
||||||
|
[sql|
|
||||||
|
ALTER TABLE rcv_files ADD COLUMN to_receive INTEGER;
|
||||||
|
|]
|
||||||
|
|
||||||
|
down_m20230420_rcv_files_to_receive :: Query
|
||||||
|
down_m20230420_rcv_files_to_receive =
|
||||||
|
[sql|
|
||||||
|
ALTER TABLE rcv_files DROP COLUMN to_receive;
|
||||||
|
|]
|
@ -229,7 +229,8 @@ CREATE TABLE rcv_files(
|
|||||||
file_descr_id INTEGER NULL
|
file_descr_id INTEGER NULL
|
||||||
REFERENCES xftp_file_descriptions ON DELETE SET NULL,
|
REFERENCES xftp_file_descriptions ON DELETE SET NULL,
|
||||||
agent_rcv_file_id BLOB NULL,
|
agent_rcv_file_id BLOB NULL,
|
||||||
agent_rcv_file_deleted INTEGER DEFAULT 0 CHECK(agent_rcv_file_deleted NOT NULL)
|
agent_rcv_file_deleted INTEGER DEFAULT 0 CHECK(agent_rcv_file_deleted NOT NULL),
|
||||||
|
to_receive INTEGER
|
||||||
);
|
);
|
||||||
CREATE TABLE snd_file_chunks(
|
CREATE TABLE snd_file_chunks(
|
||||||
file_id INTEGER NOT NULL,
|
file_id INTEGER NOT NULL,
|
||||||
|
@ -190,6 +190,8 @@ module Simplex.Chat.Store
|
|||||||
acceptRcvInlineFT,
|
acceptRcvInlineFT,
|
||||||
startRcvInlineFT,
|
startRcvInlineFT,
|
||||||
xftpAcceptRcvFT,
|
xftpAcceptRcvFT,
|
||||||
|
setRcvFileToReceive,
|
||||||
|
getRcvFilesToReceive,
|
||||||
setRcvFTAgentDeleted,
|
setRcvFTAgentDeleted,
|
||||||
updateRcvFileStatus,
|
updateRcvFileStatus,
|
||||||
createRcvFileChunk,
|
createRcvFileChunk,
|
||||||
@ -302,7 +304,7 @@ import Data.Text (Text)
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
||||||
import Data.Time (addUTCTime)
|
import Data.Time (addUTCTime)
|
||||||
import Data.Time.Clock (UTCTime (..), getCurrentTime)
|
import Data.Time.Clock (UTCTime (..), getCurrentTime, nominalDay)
|
||||||
import Data.Time.LocalTime (TimeZone, getCurrentTimeZone)
|
import Data.Time.LocalTime (TimeZone, getCurrentTimeZone)
|
||||||
import Data.Type.Equality
|
import Data.Type.Equality
|
||||||
import Database.SQLite.Simple (NamedParam (..), Only (..), Query (..), SQLError, (:.) (..))
|
import Database.SQLite.Simple (NamedParam (..), Only (..), Query (..), SQLError, (:.) (..))
|
||||||
@ -370,6 +372,7 @@ import Simplex.Chat.Migrations.M20230321_agent_file_deleted
|
|||||||
import Simplex.Chat.Migrations.M20230328_files_protocol
|
import Simplex.Chat.Migrations.M20230328_files_protocol
|
||||||
import Simplex.Chat.Migrations.M20230402_protocol_servers
|
import Simplex.Chat.Migrations.M20230402_protocol_servers
|
||||||
import Simplex.Chat.Migrations.M20230411_extra_xftp_file_descriptions
|
import Simplex.Chat.Migrations.M20230411_extra_xftp_file_descriptions
|
||||||
|
import Simplex.Chat.Migrations.M20230420_rcv_files_to_receive
|
||||||
import Simplex.Chat.Protocol
|
import Simplex.Chat.Protocol
|
||||||
import Simplex.Chat.Types
|
import Simplex.Chat.Types
|
||||||
import Simplex.Chat.Util (week)
|
import Simplex.Chat.Util (week)
|
||||||
@ -443,7 +446,8 @@ schemaMigrations =
|
|||||||
("20230321_agent_file_deleted", m20230321_agent_file_deleted, Just down_m20230321_agent_file_deleted),
|
("20230321_agent_file_deleted", m20230321_agent_file_deleted, Just down_m20230321_agent_file_deleted),
|
||||||
("20230328_files_protocol", m20230328_files_protocol, Just down_m20230328_files_protocol),
|
("20230328_files_protocol", m20230328_files_protocol, Just down_m20230328_files_protocol),
|
||||||
("20230402_protocol_servers", m20230402_protocol_servers, Just down_m20230402_protocol_servers),
|
("20230402_protocol_servers", m20230402_protocol_servers, Just down_m20230402_protocol_servers),
|
||||||
("20230411_extra_xftp_file_descriptions", m20230411_extra_xftp_file_descriptions, Just down_m20230411_extra_xftp_file_descriptions)
|
("20230411_extra_xftp_file_descriptions", m20230411_extra_xftp_file_descriptions, Just down_m20230411_extra_xftp_file_descriptions),
|
||||||
|
("20230420_rcv_files_to_receive", m20230420_rcv_files_to_receive, Just down_m20230420_rcv_files_to_receive)
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | The list of migrations in ascending order by date
|
-- | The list of migrations in ascending order by date
|
||||||
@ -3216,6 +3220,31 @@ acceptRcvFT_ db User {userId} fileId filePath rcvFileInline currentTs = do
|
|||||||
"UPDATE rcv_files SET rcv_file_inline = ?, file_status = ?, updated_at = ? WHERE file_id = ?"
|
"UPDATE rcv_files SET rcv_file_inline = ?, file_status = ?, updated_at = ? WHERE file_id = ?"
|
||||||
(rcvFileInline, FSAccepted, currentTs, fileId)
|
(rcvFileInline, FSAccepted, currentTs, fileId)
|
||||||
|
|
||||||
|
setRcvFileToReceive :: DB.Connection -> FileTransferId -> IO ()
|
||||||
|
setRcvFileToReceive db fileId = do
|
||||||
|
currentTs <- getCurrentTime
|
||||||
|
DB.execute
|
||||||
|
db
|
||||||
|
"UPDATE rcv_files SET to_receive = 1, updated_at = ? WHERE file_id = ?"
|
||||||
|
(currentTs, fileId)
|
||||||
|
|
||||||
|
getRcvFilesToReceive :: DB.Connection -> User -> IO [RcvFileTransfer]
|
||||||
|
getRcvFilesToReceive db user@User {userId} = do
|
||||||
|
cutoffTs <- addUTCTime (- (2 * nominalDay)) <$> getCurrentTime
|
||||||
|
fileIds :: [Int64] <-
|
||||||
|
map fromOnly
|
||||||
|
<$> DB.query
|
||||||
|
db
|
||||||
|
[sql|
|
||||||
|
SELECT r.file_id
|
||||||
|
FROM rcv_files r
|
||||||
|
JOIN files f ON f.file_id = r.file_id
|
||||||
|
WHERE f.user_id = ? AND r.file_status = ?
|
||||||
|
AND r.to_receive = 1 AND r.created_at > ?
|
||||||
|
|]
|
||||||
|
(userId, FSNew, cutoffTs)
|
||||||
|
rights <$> mapM (runExceptT . getRcvFileTransfer db user) fileIds
|
||||||
|
|
||||||
setRcvFTAgentDeleted :: DB.Connection -> FileTransferId -> IO ()
|
setRcvFTAgentDeleted :: DB.Connection -> FileTransferId -> IO ()
|
||||||
setRcvFTAgentDeleted db fileId = do
|
setRcvFTAgentDeleted db fileId = do
|
||||||
currentTs <- getCurrentTime
|
currentTs <- getCurrentTime
|
||||||
|
@ -65,6 +65,7 @@ chatFileTests = do
|
|||||||
it "with changed XFTP config: send and receive file" testXFTPWithChangedConfig
|
it "with changed XFTP config: send and receive file" testXFTPWithChangedConfig
|
||||||
it "with relative paths: send and receive file" testXFTPWithRelativePaths
|
it "with relative paths: send and receive file" testXFTPWithRelativePaths
|
||||||
xit' "continue receiving file after restart" testXFTPContinueRcv
|
xit' "continue receiving file after restart" testXFTPContinueRcv
|
||||||
|
it "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
|
||||||
|
|
||||||
@ -1233,6 +1234,40 @@ testXFTPContinueRcv tmp = do
|
|||||||
where
|
where
|
||||||
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"}
|
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}, tempDir = Just "./tests/tmp"}
|
||||||
|
|
||||||
|
testXFTPMarkToReceive :: HasCallStack => FilePath -> IO ()
|
||||||
|
testXFTPMarkToReceive = do
|
||||||
|
testChatCfg2 cfg aliceProfile bobProfile $ \alice bob -> do
|
||||||
|
withXFTPServer $ do
|
||||||
|
connectUsers alice bob
|
||||||
|
|
||||||
|
alice #> "/f @bob ./tests/fixtures/test.pdf"
|
||||||
|
alice <## "use /fc 1 to cancel sending"
|
||||||
|
bob <# "alice> sends file test.pdf (266.0 KiB / 272376 bytes)"
|
||||||
|
bob <## "use /fr 1 [<dir>/ | <path>] to receive it"
|
||||||
|
-- alice <## "started sending file 1 (test.pdf) to bob" -- TODO "started uploading" ?
|
||||||
|
alice <## "completed uploading file 1 (test.pdf) for bob"
|
||||||
|
bob #$> ("/_set_file_to_receive 1", id, "ok")
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
bob
|
||||||
|
<### [ "1 contacts connected (use /cs for the list)",
|
||||||
|
"started receiving file 1 (test.pdf) from alice",
|
||||||
|
"saving file 1 from alice to test.pdf"
|
||||||
|
]
|
||||||
|
bob <## "completed receiving file 1 (test.pdf) from alice"
|
||||||
|
|
||||||
|
src <- B.readFile "./tests/fixtures/test.pdf"
|
||||||
|
dest <- B.readFile "./tests/tmp/bob_files/test.pdf"
|
||||||
|
dest `shouldBe` src
|
||||||
|
where
|
||||||
|
cfg = testCfg {xftpFileConfig = Just $ XFTPFileConfig {minFileSize = 0}}
|
||||||
|
|
||||||
testXFTPRcvError :: HasCallStack => FilePath -> IO ()
|
testXFTPRcvError :: HasCallStack => FilePath -> IO ()
|
||||||
testXFTPRcvError tmp = do
|
testXFTPRcvError tmp = do
|
||||||
withXFTPServer $ do
|
withXFTPServer $ do
|
||||||
|
Loading…
Reference in New Issue
Block a user