2020-12-09 16:32:29 +00:00
|
|
|
{- git-annex command
|
|
|
|
-
|
|
|
|
- Copyright 2012-2020 Joey Hess <id@joeyh.name>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
2020-12-09 17:21:20 +00:00
|
|
|
module Command.Transferrer where
|
2020-12-09 16:32:29 +00:00
|
|
|
|
|
|
|
import Command
|
|
|
|
import qualified Annex
|
|
|
|
import Annex.Content
|
|
|
|
import Logs.Location
|
|
|
|
import Annex.Transfer
|
|
|
|
import qualified Remote
|
|
|
|
import Utility.SimpleProtocol (dupIoHandles)
|
|
|
|
import qualified Database.Keys
|
|
|
|
import Annex.BranchState
|
|
|
|
import Types.Messages
|
|
|
|
import Annex.TransferrerPool
|
2020-12-09 17:28:16 +00:00
|
|
|
import Types.Transferrer
|
2020-12-09 19:44:00 +00:00
|
|
|
import qualified Utility.SimpleProtocol as Proto
|
2020-12-09 16:32:29 +00:00
|
|
|
|
|
|
|
cmd :: Command
|
2020-12-09 17:21:20 +00:00
|
|
|
cmd = command "transferrer" SectionPlumbing "transfers content"
|
2020-12-09 16:32:29 +00:00
|
|
|
paramNothing (withParams seek)
|
|
|
|
|
|
|
|
seek :: CmdParams -> CommandSeek
|
|
|
|
seek = withNothing (commandAction start)
|
|
|
|
|
|
|
|
start :: CommandStart
|
|
|
|
start = do
|
|
|
|
enableInteractiveBranchAccess
|
|
|
|
(readh, writeh) <- liftIO dupIoHandles
|
2020-12-09 19:44:00 +00:00
|
|
|
let outputwriter v = do
|
|
|
|
hPutStrLn writeh $
|
|
|
|
unwords $ Proto.formatMessage $ TransferOutput v
|
|
|
|
hFlush writeh
|
|
|
|
let outputresponsereader = do
|
|
|
|
l <- hGetLine readh
|
|
|
|
return $ case Proto.parseMessage l of
|
|
|
|
Just (TransferSerializedOutputResponse r) -> Just r
|
|
|
|
Nothing -> Nothing
|
|
|
|
Annex.setOutput $ SerializedOutput outputwriter outputresponsereader
|
2020-12-09 16:32:29 +00:00
|
|
|
runRequests readh writeh runner
|
|
|
|
stop
|
|
|
|
where
|
2020-12-09 19:44:00 +00:00
|
|
|
runner (UploadRequest _ key (TransferAssociatedFile file)) remote =
|
|
|
|
-- This is called by eg, Annex.Transfer.upload,
|
|
|
|
-- so caller is responsible for doing notification,
|
|
|
|
-- and for retrying.
|
|
|
|
upload' (Remote.uuid remote) key file noRetry
|
|
|
|
(Remote.action . Remote.storeKey remote key file)
|
|
|
|
noNotification
|
|
|
|
runner (DownloadRequest _ key (TransferAssociatedFile file)) remote =
|
|
|
|
-- This is called by eg, Annex.Transfer.download
|
|
|
|
-- so caller is responsible for doing notification
|
|
|
|
-- and for retrying.
|
|
|
|
let go p = getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key file $ \t -> do
|
|
|
|
Remote.verifiedAction (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p)
|
|
|
|
in download' (Remote.uuid remote) key file noRetry go
|
|
|
|
noNotification
|
|
|
|
runner (AssistantUploadRequest _ key (TransferAssociatedFile file)) remote =
|
|
|
|
notifyTransfer Upload file $
|
2020-12-09 16:32:29 +00:00
|
|
|
upload' (Remote.uuid remote) key file stdRetry $ \p -> do
|
|
|
|
tryNonAsync (Remote.storeKey remote key file p) >>= \case
|
|
|
|
Left e -> do
|
|
|
|
warning (show e)
|
|
|
|
return False
|
|
|
|
Right () -> do
|
|
|
|
Remote.logStatus remote key InfoPresent
|
|
|
|
return True
|
2020-12-09 19:44:00 +00:00
|
|
|
runner (AssistantDownloadRequest _ key (TransferAssociatedFile file)) remote =
|
|
|
|
notifyTransfer Download file $
|
2020-12-09 16:32:29 +00:00
|
|
|
download' (Remote.uuid remote) key file stdRetry $ \p ->
|
|
|
|
getViaTmp (Remote.retrievalSecurityPolicy remote) (RemoteVerify remote) key file $ \t -> do
|
|
|
|
r <- tryNonAsync (Remote.retrieveKeyFile remote key file (fromRawFilePath t) p) >>= \case
|
|
|
|
Left e -> do
|
|
|
|
warning (show e)
|
|
|
|
return (False, UnVerified)
|
|
|
|
Right v -> return (True, v)
|
|
|
|
-- Make sure we get the current
|
|
|
|
-- associated files data for the key,
|
|
|
|
-- not old cached data.
|
|
|
|
Database.Keys.closeDb
|
|
|
|
return r
|
|
|
|
|
|
|
|
runRequests
|
|
|
|
:: Handle
|
|
|
|
-> Handle
|
|
|
|
-> (TransferRequest -> Remote -> Annex Bool)
|
|
|
|
-> Annex ()
|
|
|
|
runRequests readh writeh a = go Nothing Nothing
|
|
|
|
where
|
|
|
|
go lastremoteoruuid lastremote = unlessM (liftIO $ hIsEOF readh) $ do
|
|
|
|
l <- liftIO $ hGetLine readh
|
2020-12-09 19:44:00 +00:00
|
|
|
case Proto.parseMessage l of
|
|
|
|
Just tr -> do
|
|
|
|
let remoteoruuid = transferRequestRemote tr
|
2020-12-09 16:32:29 +00:00
|
|
|
-- Often the same remote will be used
|
|
|
|
-- repeatedly, so cache the last one to
|
|
|
|
-- avoid looking up repeatedly.
|
|
|
|
mremote <- if lastremoteoruuid == Just remoteoruuid
|
|
|
|
then pure lastremote
|
2020-12-09 19:44:00 +00:00
|
|
|
else case remoteoruuid of
|
|
|
|
TransferRemoteName n ->
|
|
|
|
eitherToMaybe <$> Remote.byName' n
|
|
|
|
TransferRemoteUUID u ->
|
|
|
|
Remote.byUUID u
|
2020-12-09 16:32:29 +00:00
|
|
|
case mremote of
|
|
|
|
Just remote -> do
|
|
|
|
sendresult =<< a tr remote
|
|
|
|
go (Just remoteoruuid) mremote
|
2020-12-09 17:21:20 +00:00
|
|
|
Nothing -> transferrerProtocolError l
|
|
|
|
Nothing -> transferrerProtocolError l
|
2020-12-09 16:32:29 +00:00
|
|
|
|
|
|
|
sendresult b = liftIO $ do
|
2020-12-09 19:44:00 +00:00
|
|
|
hPutStrLn writeh $
|
|
|
|
unwords $ Proto.formatMessage $ TransferResult b
|
2020-12-09 16:32:29 +00:00
|
|
|
hFlush writeh
|