diff options
-rw-r--r-- | Remote/External.hs | 20 | ||||
-rw-r--r-- | Remote/External/Types.hs | 8 | ||||
-rw-r--r-- | doc/design/external_special_remote_protocol.mdwn | 17 |
3 files changed, 31 insertions, 14 deletions
diff --git a/Remote/External.hs b/Remote/External.hs index 1cf199e99..5a09d1de0 100644 --- a/Remote/External.hs +++ b/Remote/External.hs @@ -169,6 +169,8 @@ handleRequest external req mp responsehandler = handleRequest' :: ExternalLock -> External -> Request -> Maybe MeterUpdate -> (Response -> Maybe (Annex a)) -> Annex a handleRequest' lck external req mp responsehandler = do + when (needsPREPARE req) $ + checkPrepared lck external sendMessage lck external req loop where @@ -230,15 +232,13 @@ fromExternal lck external extractor a = void $ liftIO $ atomically $ swapTMVar v st {- Handle initial protocol startup; check the VERSION - - the remote sends, and send it the PREPARE request. -} + - the remote sends. -} receiveMessage lck external (const Nothing) (checkVersion lck external) (const Nothing) - handleRequest' lck external PREPARE Nothing $ \resp -> - case resp of - PREPARE_SUCCESS -> Just $ run st - _ -> Nothing + + run st run st = a $ extractor st v = externalState external @@ -259,6 +259,7 @@ startExternal externaltype = liftIO $ do { externalSend = hin , externalReceive = hout , externalPid = pid + , externalPrepared = False } stopExternal :: External -> Annex () @@ -282,6 +283,15 @@ checkVersion lck external (VERSION v) = Just $ else sendMessage lck external (ERROR "unsupported VERSION") checkVersion _ _ _ = Nothing +checkPrepared :: ExternalLock -> External -> Annex () +checkPrepared lck external = + fromExternal lck external externalPrepared $ \prepared -> + unless prepared $ + handleRequest' lck external PREPARE Nothing $ \resp -> + case resp of + PREPARE_SUCCESS -> Just noop + _ -> Nothing + {- Caches the cost in the git config to avoid needing to start up an - external special remote every time time just to ask it what its - cost is. -} diff --git a/Remote/External/Types.hs b/Remote/External/Types.hs index 873c5c438..4000f3f49 100644 --- a/Remote/External/Types.hs +++ b/Remote/External/Types.hs @@ -18,6 +18,7 @@ module Remote.External.Types ( Sendable(..), Receivable(..), Request(..), + needsPREPARE, Response(..), RemoteRequest(..), RemoteResponse(..), @@ -60,6 +61,7 @@ data ExternalState = ExternalState { externalSend :: Handle , externalReceive :: Handle , externalPid :: ProcessHandle + , externalPrepared :: Bool } -- Constructor is not exported, and only created by newExternal. @@ -98,6 +100,12 @@ data Request | REMOVE Key deriving (Show) +-- Does PREPARE need to have been sent before this request? +needsPREPARE :: Request -> Bool +needsPREPARE PREPARE = False +needsPREPARE INITREMOTE = False +needsPREPARE _ = True + instance Sendable Request where formatMessage PREPARE = ["PREPARE"] formatMessage INITREMOTE = ["INITREMOTE"] diff --git a/doc/design/external_special_remote_protocol.mdwn b/doc/design/external_special_remote_protocol.mdwn index 0e67a4909..cede16e16 100644 --- a/doc/design/external_special_remote_protocol.mdwn +++ b/doc/design/external_special_remote_protocol.mdwn @@ -36,8 +36,9 @@ the version of the protocol it is using. VERSION 1 -Once it knows the version, git-annex will send a message telling the -special remote to start up. +Once it knows the version, git-annex will generally +send a message telling the special remote to start up. +(Or it might send a INITREMOTE, so don't hardcode this order.) PREPARE @@ -84,17 +85,15 @@ send one of the corresponding replies listed in the next section. The following requests *must* all be supported by the special remote. -* `PREPARE` - Tells the special remote it's time to prepare itself to be used. - Only run once, at startup, always immediately after the special remote - sends VERSION. * `INITREMOTE` - Request that the remote initialized itself. This is where any one-time + Request that the remote initialize itself. This is where any one-time setup tasks can be done, for example creating an Amazon S3 bucket. - (PREPARE is still sent before this.) - Note: This may be run repeatedly, as a remote is initialized in + Note: This may be run repeatedly over time, as a remote is initialized in different repositories, or as the configuration of a remote is changed. So any one-time setup tasks should be done idempotently. +* `PREPARE` + Tells the special remote it's time to prepare itself to be used. + Only INITREMOTE can come before this. * `TRANSFER STORE|RETRIEVE Key File` Requests the transfer of a key. For Send, the File is the file to upload; for Receive the File is where to store the download. |