support direct file invitations without contact requests (#1076)
This commit is contained in:
committed by
GitHub
parent
a8ef92a933
commit
a615dbec91
@@ -259,6 +259,15 @@ processChatCommand = \case
|
||||
setActive $ ActiveC c
|
||||
pure . CRNewChatItem $ AChatItem SCTDirect SMDSnd (DirectChat ct) ci
|
||||
where
|
||||
-- This method creates file invitation without connection request - it has to be accepted with x.acpt.file.inv message sent back to the contact
|
||||
-- setupSndFileTransfer' :: Contact -> m (Maybe (FileInvitation, CIFile 'MDSnd))
|
||||
-- setupSndFileTransfer' ct = forM file_ $ \file -> do
|
||||
-- (fileSize, chSize) <- checkSndFile file
|
||||
-- let fileName = takeFileName file
|
||||
-- fileInvitation = FileInvitation {fileName, fileSize, fileConnReq = Nothing}
|
||||
-- fileId <- withStore' $ \db -> createSndDirectFileTransfer db userId ct file fileInvitation chSize
|
||||
-- let ciFile = CIFile {fileId, fileName, fileSize, filePath = Just file, fileStatus = CIFSSndStored}
|
||||
-- pure (fileInvitation, ciFile)
|
||||
setupSndFileTransfer :: Contact -> m (Maybe (FileInvitation, CIFile 'MDSnd))
|
||||
setupSndFileTransfer ct = forM file_ $ \file -> do
|
||||
(fileSize, chSize) <- checkSndFile file
|
||||
@@ -1121,30 +1130,37 @@ acceptFileReceive user@User {userId} RcvFileTransfer {fileId, fileInvitation = F
|
||||
_ -> throwChatError $ CEFileAlreadyReceiving fName
|
||||
case fileConnReq of
|
||||
-- direct file protocol
|
||||
Just connReq ->
|
||||
Just connReq -> do
|
||||
-- [async agent commands] keep command synchronous, but process error
|
||||
tryError (withAgent $ \a -> joinConnection a True connReq . directMessage $ XFileAcpt fName) >>= \case
|
||||
Right agentConnId -> do
|
||||
filePath <- getRcvFilePath filePath_ fName
|
||||
withStore $ \db -> acceptRcvFileTransfer db user fileId agentConnId ConnJoined filePath
|
||||
Left e -> throwError e
|
||||
-- group file protocol
|
||||
Nothing ->
|
||||
case grpMemberId of
|
||||
Nothing -> throwChatError $ CEFileInternal "group member not found for file transfer"
|
||||
Just memId -> do
|
||||
(GroupInfo {groupId}, GroupMember {activeConn}) <- withStore $ \db -> getGroupAndMember db user memId
|
||||
agentConnId <- withAgent $ \a -> joinConnection a True connReq . directMessage $ XFileAcpt fName
|
||||
filePath <- getRcvFilePath filePath_ fName
|
||||
withStore $ \db -> acceptRcvFileTransfer db user fileId agentConnId ConnJoined filePath
|
||||
-- group & direct file protocol
|
||||
Nothing -> do
|
||||
chatRef <- withStore $ \db -> getChatRefByFileId db user fileId
|
||||
case (chatRef, grpMemberId) of
|
||||
(ChatRef CTDirect contactId, Nothing) -> do
|
||||
ct <- withStore $ \db -> getContact db userId contactId
|
||||
(msg, ci) <- acceptFile
|
||||
void $ sendDirectContactMessage ct msg
|
||||
pure ci
|
||||
(ChatRef CTGroup groupId, Just memId) -> do
|
||||
GroupMember {activeConn} <- withStore $ \db -> getGroupMember db user groupId memId
|
||||
case activeConn of
|
||||
Just conn -> do
|
||||
sharedMsgId <- withStore $ \db -> getSharedMsgIdByFileId db userId fileId
|
||||
-- [async agent commands] keep command synchronous, but process error
|
||||
(agentConnId, fileInvConnReq) <- withAgent $ \a -> createConnection a True SCMInvitation
|
||||
filePath <- getRcvFilePath filePath_ fName
|
||||
ci <- withStore $ \db -> acceptRcvFileTransfer db user fileId agentConnId ConnNew filePath
|
||||
void $ sendDirectMessage conn (XFileAcptInv sharedMsgId fileInvConnReq fName) (GroupId groupId)
|
||||
(msg, ci) <- acceptFile
|
||||
void $ sendDirectMessage conn msg $ GroupId groupId
|
||||
pure ci
|
||||
_ -> throwChatError $ CEFileInternal "member connection not active"
|
||||
_ -> throwChatError $ CEFileInternal "invalid chat ref for file transfer"
|
||||
where
|
||||
acceptFile :: m (ChatMsgEvent, AChatItem)
|
||||
acceptFile = do
|
||||
sharedMsgId <- withStore $ \db -> getSharedMsgIdByFileId db userId fileId
|
||||
(agentConnId, fileInvConnReq) <- withAgent $ \a -> createConnection a True SCMInvitation
|
||||
filePath <- getRcvFilePath filePath_ fName
|
||||
ci <- withStore (\db -> acceptRcvFileTransfer db user fileId agentConnId ConnNew filePath)
|
||||
pure (XFileAcptInv sharedMsgId fileInvConnReq fName, ci)
|
||||
getRcvFilePath :: Maybe FilePath -> String -> m FilePath
|
||||
getRcvFilePath fPath_ fn = case fPath_ of
|
||||
Nothing ->
|
||||
@@ -1416,6 +1432,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
|
||||
-- TODO discontinue XFile
|
||||
XFile fInv -> processFileInvitation' ct fInv msg msgMeta
|
||||
XFileCancel sharedMsgId -> xFileCancel ct sharedMsgId msgMeta
|
||||
XFileAcptInv sharedMsgId fileConnReq fName -> xFileAcptInv ct sharedMsgId fileConnReq fName msgMeta
|
||||
XInfo p -> xInfo ct p
|
||||
XGrpInv gInv -> processGroupInvitation ct gInv msg msgMeta
|
||||
XInfoProbe probe -> xInfoProbe ct probe
|
||||
@@ -1956,6 +1973,18 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
|
||||
cancelRcvFileTransfer user ft
|
||||
toView $ CRRcvFileSndCancelled ft
|
||||
|
||||
xFileAcptInv :: Contact -> SharedMsgId -> ConnReqInvitation -> String -> MsgMeta -> m ()
|
||||
xFileAcptInv ct sharedMsgId fileConnReq fName msgMeta = do
|
||||
checkIntegrityCreateItem (CDDirectRcv ct) msgMeta
|
||||
fileId <- withStore $ \db -> getDirectFileIdBySharedMsgId db user ct sharedMsgId
|
||||
(FileTransferMeta {fileName, cancelled}, _) <- withStore (\db -> getSndFileTransfer db user fileId)
|
||||
-- [async agent commands] no continuation needed, but command should be asynchronous for stability
|
||||
if fName == fileName
|
||||
then unless cancelled $ do
|
||||
connIds <- joinAgentConnectionAsync user True fileConnReq $ directMessage XOk
|
||||
withStore' $ \db -> createSndDirectFTConnection db user fileId connIds
|
||||
else messageError "x.file.acpt.inv: fileName is different from expected"
|
||||
|
||||
xFileCancelGroup :: GroupInfo -> GroupMember -> SharedMsgId -> MsgMeta -> m ()
|
||||
xFileCancelGroup g@GroupInfo {groupId} mem@GroupMember {memberId} sharedMsgId msgMeta = do
|
||||
checkIntegrityCreateItem (CDGroupRcv g mem) msgMeta
|
||||
@@ -1977,17 +2006,12 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
|
||||
checkIntegrityCreateItem (CDGroupRcv g m) msgMeta
|
||||
fileId <- withStore $ \db -> getGroupFileIdBySharedMsgId db userId groupId sharedMsgId
|
||||
(FileTransferMeta {fileName, cancelled}, _) <- withStore (\db -> getSndFileTransfer db user fileId)
|
||||
unless cancelled $
|
||||
if fName == fileName
|
||||
then
|
||||
tryError
|
||||
-- [async agent commands] no continuation needed, but command should be asynchronous for stability
|
||||
(joinAgentConnectionAsync user True fileConnReq . directMessage $ XOk)
|
||||
>>= \case
|
||||
Right connIds ->
|
||||
withStore' $ \db -> createSndGroupFileTransferConnection db user fileId connIds m
|
||||
Left e -> throwError e
|
||||
else messageError "x.file.acpt.inv: fileName is different from expected"
|
||||
if fName == fileName
|
||||
then unless cancelled $ do
|
||||
-- [async agent commands] no continuation needed, but command should be asynchronous for stability
|
||||
connIds <- joinAgentConnectionAsync user True fileConnReq $ directMessage XOk
|
||||
withStore' $ \db -> createSndGroupFileTransferConnection db user fileId connIds m
|
||||
else messageError "x.file.acpt.inv: fileName is different from expected"
|
||||
|
||||
groupMsgToView :: GroupInfo -> GroupMember -> ChatItem 'CTGroup 'MDRcv -> MsgMeta -> m ()
|
||||
groupMsgToView gInfo m ci msgMeta = do
|
||||
|
||||
@@ -106,6 +106,8 @@ module Simplex.Chat.Store
|
||||
matchSentProbe,
|
||||
mergeContactRecords,
|
||||
createSndFileTransfer,
|
||||
createSndDirectFileTransfer,
|
||||
createSndDirectFTConnection,
|
||||
createSndGroupFileTransfer,
|
||||
createSndGroupFileTransferConnection,
|
||||
updateFileCancelled,
|
||||
@@ -113,6 +115,7 @@ module Simplex.Chat.Store
|
||||
getSharedMsgIdByFileId,
|
||||
getFileIdBySharedMsgId,
|
||||
getGroupFileIdBySharedMsgId,
|
||||
getDirectFileIdBySharedMsgId,
|
||||
getChatRefByFileId,
|
||||
updateSndFileStatus,
|
||||
createSndFileChunk,
|
||||
@@ -2001,6 +2004,25 @@ createSndFileTransfer db userId Contact {contactId} filePath FileInvitation {fil
|
||||
(fileId, fileStatus, connId, currentTs, currentTs)
|
||||
pure fileId
|
||||
|
||||
createSndDirectFileTransfer :: DB.Connection -> UserId -> Contact -> FilePath -> FileInvitation -> Integer -> IO Int64
|
||||
createSndDirectFileTransfer db userId Contact {contactId} filePath FileInvitation {fileName, fileSize} chunkSize = do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO files (user_id, contact_id, file_name, file_path, file_size, chunk_size, ci_file_status, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?)"
|
||||
(userId, contactId, fileName, filePath, fileSize, chunkSize, CIFSSndStored, currentTs, currentTs)
|
||||
insertedRowId db
|
||||
|
||||
createSndDirectFTConnection :: DB.Connection -> User -> Int64 -> (CommandId, ConnId) -> IO ()
|
||||
createSndDirectFTConnection db user@User {userId} fileId (cmdId, acId) = do
|
||||
currentTs <- getCurrentTime
|
||||
Connection {connId} <- createSndFileConnection_ db userId fileId acId
|
||||
setCommandConnId db user cmdId connId
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO snd_files (file_id, file_status, connection_id, created_at, updated_at) VALUES (?,?,?,?,?)"
|
||||
(fileId, FSAccepted, connId, currentTs, currentTs)
|
||||
|
||||
createSndGroupFileTransfer :: DB.Connection -> UserId -> GroupInfo -> FilePath -> FileInvitation -> Integer -> IO Int64
|
||||
createSndGroupFileTransfer db userId GroupInfo {groupId} filePath FileInvitation {fileName, fileSize} chunkSize = do
|
||||
currentTs <- getCurrentTime
|
||||
@@ -2069,6 +2091,19 @@ getGroupFileIdBySharedMsgId db userId groupId sharedMsgId =
|
||||
|]
|
||||
(userId, groupId, sharedMsgId)
|
||||
|
||||
getDirectFileIdBySharedMsgId :: DB.Connection -> User -> Contact -> SharedMsgId -> ExceptT StoreError IO Int64
|
||||
getDirectFileIdBySharedMsgId db User {userId} Contact {contactId} sharedMsgId =
|
||||
ExceptT . firstRow fromOnly (SEFileIdNotFoundBySharedMsgId sharedMsgId) $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT f.file_id
|
||||
FROM files f
|
||||
JOIN chat_items i ON i.chat_item_id = f.chat_item_id
|
||||
WHERE i.user_id = ? AND i.contact_id = ? AND i.shared_msg_id = ?
|
||||
|]
|
||||
(userId, contactId, sharedMsgId)
|
||||
|
||||
getChatRefByFileId :: DB.Connection -> User -> Int64 -> ExceptT StoreError IO ChatRef
|
||||
getChatRefByFileId db User {userId} fileId =
|
||||
liftIO getChatRef >>= \case
|
||||
|
||||
Reference in New Issue
Block a user