cleanup
This commit is contained in:
parent
6fcca2f13e
commit
cf82b0e1ec
1 changed files with 45 additions and 46 deletions
91
Remote/S3.hs
91
Remote/S3.hs
|
@ -40,7 +40,7 @@ import Utility.Metered
|
||||||
import Annex.UUID
|
import Annex.UUID
|
||||||
import Logs.Web
|
import Logs.Web
|
||||||
|
|
||||||
type Bucket = String
|
type BucketName = String
|
||||||
|
|
||||||
remote :: RemoteType
|
remote :: RemoteType
|
||||||
remote = RemoteType {
|
remote = RemoteType {
|
||||||
|
@ -116,7 +116,7 @@ s3Setup' u c = if isIA c then archiveorg else defaulthost
|
||||||
-- this determines the name of the archive.org item.
|
-- this determines the name of the archive.org item.
|
||||||
let bucket = replace " " "-" $ map toLower $
|
let bucket = replace " " "-" $ map toLower $
|
||||||
fromMaybe (error "specify bucket=") $
|
fromMaybe (error "specify bucket=") $
|
||||||
getBucket c
|
getBucketName c
|
||||||
let archiveconfig =
|
let archiveconfig =
|
||||||
-- hS3 does not pass through x-archive-* headers
|
-- hS3 does not pass through x-archive-* headers
|
||||||
M.mapKeys (replace "x-archive-" "x-amz-") $
|
M.mapKeys (replace "x-archive-" "x-amz-") $
|
||||||
|
@ -143,7 +143,7 @@ prepareStore r = resourcePrepare (const $ s3Action r False) $ \(conn, bucket) ->
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
store :: (AWSConnection, Bucket) -> Remote -> Key -> MeterUpdate -> FilePath -> IO (AWSResult ())
|
store :: (AWSConnection, BucketName) -> Remote -> Key -> MeterUpdate -> FilePath -> IO (AWSResult ())
|
||||||
store (conn, bucket) r k p file = do
|
store (conn, bucket) r k p file = do
|
||||||
error "TODO"
|
error "TODO"
|
||||||
{-
|
{-
|
||||||
|
@ -208,7 +208,7 @@ s3Bool :: AWSResult () -> Annex Bool
|
||||||
s3Bool (Right _) = return True
|
s3Bool (Right _) = return True
|
||||||
s3Bool (Left e) = s3Warning e
|
s3Bool (Left e) = s3Warning e
|
||||||
|
|
||||||
s3Action :: Remote -> a -> ((AWSConnection, Bucket) -> Annex a) -> Annex a
|
s3Action :: Remote -> a -> ((AWSConnection, BucketName) -> Annex a) -> Annex a
|
||||||
s3Action r noconn action = do
|
s3Action r noconn action = do
|
||||||
let bucket = M.lookup "bucket" $ config r
|
let bucket = M.lookup "bucket" $ config r
|
||||||
conn <- s3Connection (config r) (uuid r)
|
conn <- s3Connection (config r) (uuid r)
|
||||||
|
@ -220,28 +220,13 @@ bucketFile :: Remote -> Key -> FilePath
|
||||||
bucketFile r = munge . key2file
|
bucketFile r = munge . key2file
|
||||||
where
|
where
|
||||||
munge s = case M.lookup "mungekeys" c of
|
munge s = case M.lookup "mungekeys" c of
|
||||||
Just "ia" -> iaMunge $ filePrefix c ++ s
|
Just "ia" -> iaMunge $ getFilePrefix c ++ s
|
||||||
_ -> filePrefix c ++ s
|
_ -> getFilePrefix c ++ s
|
||||||
c = config r
|
c = config r
|
||||||
|
|
||||||
filePrefix :: RemoteConfig -> String
|
bucketKey :: Remote -> BucketName -> Key -> S3Object
|
||||||
filePrefix = M.findWithDefault "" "fileprefix"
|
|
||||||
|
|
||||||
bucketKey :: Remote -> Bucket -> Key -> S3Object
|
|
||||||
bucketKey r bucket k = S3Object bucket (bucketFile r k) "" [] L.empty
|
bucketKey r bucket k = S3Object bucket (bucketFile r k) "" [] L.empty
|
||||||
|
|
||||||
{- Internet Archive limits filenames to a subset of ascii,
|
|
||||||
- with no whitespace. Other characters are xml entity
|
|
||||||
- encoded. -}
|
|
||||||
iaMunge :: String -> String
|
|
||||||
iaMunge = (>>= munge)
|
|
||||||
where
|
|
||||||
munge c
|
|
||||||
| isAsciiUpper c || isAsciiLower c || isNumber c = [c]
|
|
||||||
| c `elem` "_-.\"" = [c]
|
|
||||||
| isSpace c = []
|
|
||||||
| otherwise = "&" ++ show (ord c) ++ ";"
|
|
||||||
|
|
||||||
{- Generate the bucket if it does not already exist, including creating the
|
{- Generate the bucket if it does not already exist, including creating the
|
||||||
- UUID file within the bucket.
|
- UUID file within the bucket.
|
||||||
-
|
-
|
||||||
|
@ -257,18 +242,18 @@ genBucket c u = do
|
||||||
where
|
where
|
||||||
go _ (Right True) = noop
|
go _ (Right True) = noop
|
||||||
go h _ = do
|
go h _ = do
|
||||||
v <- sendS3Handle h (S3.getBucket bucket)
|
v <- tryS3 $ sendS3Handle h (S3.getBucket bucket)
|
||||||
case v of
|
case v of
|
||||||
Right _ -> noop
|
Right _ -> noop
|
||||||
Left _ -> do
|
Left _ -> do
|
||||||
showAction $ "creating bucket in " ++ datacenter
|
showAction $ "creating bucket in " ++ datacenter
|
||||||
void $ mustSucceed $ sendS3Handle h $
|
void $ sendS3Handle h $
|
||||||
S3.PutBucket bucket Nothing $
|
S3.PutBucket bucket Nothing $
|
||||||
AWS.mkLocationConstraint $
|
AWS.mkLocationConstraint $
|
||||||
T.pack datacenter
|
T.pack datacenter
|
||||||
writeUUIDFile c u h
|
writeUUIDFile c u h
|
||||||
|
|
||||||
bucket = T.pack $ fromJust $ getBucket c
|
bucket = T.pack $ fromJust $ getBucketName c
|
||||||
datacenter = fromJust $ M.lookup "datacenter" c
|
datacenter = fromJust $ M.lookup "datacenter" c
|
||||||
|
|
||||||
{- Writes the UUID to an annex-uuid file within the bucket.
|
{- Writes the UUID to an annex-uuid file within the bucket.
|
||||||
|
@ -284,11 +269,11 @@ writeUUIDFile c u h = do
|
||||||
case v of
|
case v of
|
||||||
Left e -> throwM e
|
Left e -> throwM e
|
||||||
Right True -> noop
|
Right True -> noop
|
||||||
Right False -> void $ mustSucceed $ sendS3Handle h mkobject
|
Right False -> void $ sendS3Handle h mkobject
|
||||||
where
|
where
|
||||||
file = T.pack $ uuidFile c
|
file = T.pack $ uuidFile c
|
||||||
uuidb = L.fromChunks [T.encodeUtf8 $ T.pack $ fromUUID u]
|
uuidb = L.fromChunks [T.encodeUtf8 $ T.pack $ fromUUID u]
|
||||||
bucket = T.pack $ fromJust $ getBucket c
|
bucket = T.pack $ fromJust $ getBucketName c
|
||||||
|
|
||||||
-- TODO: add headers from getXheaders
|
-- TODO: add headers from getXheaders
|
||||||
-- (See https://github.com/aristidb/aws/issues/119)
|
-- (See https://github.com/aristidb/aws/issues/119)
|
||||||
|
@ -303,17 +288,17 @@ checkUUIDFile c u h = tryNonAsync $ check <$> get
|
||||||
get = liftIO
|
get = liftIO
|
||||||
. runResourceT
|
. runResourceT
|
||||||
. either (pure . Left) (Right <$$> AWS.loadToMemory)
|
. either (pure . Left) (Right <$$> AWS.loadToMemory)
|
||||||
=<< sendS3Handle h (S3.getObject bucket file)
|
=<< tryS3 (sendS3Handle h (S3.getObject bucket file))
|
||||||
check (Right (S3.GetObjectMemoryResponse _meta rsp)) =
|
check (Right (S3.GetObjectMemoryResponse _meta rsp)) =
|
||||||
responseStatus rsp == ok200 && responseBody rsp == uuidb
|
responseStatus rsp == ok200 && responseBody rsp == uuidb
|
||||||
check (Left _S3Error) = False
|
check (Left _S3Error) = False
|
||||||
|
|
||||||
bucket = T.pack $ fromJust $ getBucket c
|
bucket = T.pack $ fromJust $ getBucketName c
|
||||||
file = T.pack $ uuidFile c
|
file = T.pack $ uuidFile c
|
||||||
uuidb = L.fromChunks [T.encodeUtf8 $ T.pack $ fromUUID u]
|
uuidb = L.fromChunks [T.encodeUtf8 $ T.pack $ fromUUID u]
|
||||||
|
|
||||||
uuidFile :: RemoteConfig -> FilePath
|
uuidFile :: RemoteConfig -> FilePath
|
||||||
uuidFile c = filePrefix c ++ "annex-uuid"
|
uuidFile c = getFilePrefix c ++ "annex-uuid"
|
||||||
|
|
||||||
s3Connection :: RemoteConfig -> UUID -> Annex (Maybe AWSConnection)
|
s3Connection :: RemoteConfig -> UUID -> Annex (Maybe AWSConnection)
|
||||||
s3Connection c u = go =<< getRemoteCredPairFor "S3" c (AWS.creds u)
|
s3Connection c u = go =<< getRemoteCredPairFor "S3" c (AWS.creds u)
|
||||||
|
@ -332,24 +317,16 @@ data S3Handle = S3Handle Manager AWS.Configuration (S3.S3Configuration AWS.Norma
|
||||||
{- Sends a request to S3 and gets back the response.
|
{- Sends a request to S3 and gets back the response.
|
||||||
-
|
-
|
||||||
- Note that pureAws's use of ResourceT is bypassed here;
|
- Note that pureAws's use of ResourceT is bypassed here;
|
||||||
- the response should be processed while the S3Handle is still open,
|
- the response should be fully processed while the S3Handle
|
||||||
- eg within a call to withS3Handle.
|
- is still open, eg within a call to withS3Handle.
|
||||||
-}
|
-}
|
||||||
sendS3Handle
|
sendS3Handle
|
||||||
:: (AWS.Transaction req res, AWS.ServiceConfiguration req ~ S3.S3Configuration)
|
:: (AWS.Transaction req res, AWS.ServiceConfiguration req ~ S3.S3Configuration)
|
||||||
=> S3Handle
|
=> S3Handle
|
||||||
-> req
|
-> req
|
||||||
-> Annex (Either S3.S3Error res)
|
-> Annex res
|
||||||
sendS3Handle (S3Handle manager awscfg s3cfg) req = safely $ liftIO $
|
sendS3Handle (S3Handle manager awscfg s3cfg) req = liftIO $
|
||||||
runResourceT $ AWS.pureAws awscfg s3cfg manager req
|
runResourceT $ AWS.pureAws awscfg s3cfg manager req
|
||||||
where
|
|
||||||
safely a = (Right <$> a) `catch` (pure . Left)
|
|
||||||
|
|
||||||
mustSucceed :: Annex (Either S3.S3Error res) -> Annex res
|
|
||||||
mustSucceed a = a >>= either s3Error return
|
|
||||||
|
|
||||||
s3Error :: S3.S3Error -> a
|
|
||||||
s3Error (S3.S3Error { S3.s3ErrorMessage = m }) = error $ "S3 error: " ++ T.unpack m
|
|
||||||
|
|
||||||
withS3Handle :: RemoteConfig -> UUID -> (S3Handle -> Annex a) -> Annex a
|
withS3Handle :: RemoteConfig -> UUID -> (S3Handle -> Annex a) -> Annex a
|
||||||
withS3Handle c u a = do
|
withS3Handle c u a = do
|
||||||
|
@ -383,8 +360,15 @@ s3Configuration c = (S3.s3 proto endpoint False) { S3.s3Port = port }
|
||||||
[(p, _)] -> p
|
[(p, _)] -> p
|
||||||
_ -> error $ "bad S3 port value: " ++ s
|
_ -> error $ "bad S3 port value: " ++ s
|
||||||
|
|
||||||
getBucket :: RemoteConfig -> Maybe Bucket
|
tryS3 :: Annex a -> Annex (Either S3.S3Error a)
|
||||||
getBucket = M.lookup "bucket"
|
tryS3 a = (Right <$> a) `catch` (pure . Left)
|
||||||
|
|
||||||
|
s3Error :: S3.S3Error -> a
|
||||||
|
s3Error (S3.S3Error { S3.s3ErrorMessage = m }) =
|
||||||
|
error $ "S3 error: " ++ T.unpack m
|
||||||
|
|
||||||
|
getBucketName :: RemoteConfig -> Maybe BucketName
|
||||||
|
getBucketName = M.lookup "bucket"
|
||||||
|
|
||||||
getStorageClass :: RemoteConfig -> S3.StorageClass
|
getStorageClass :: RemoteConfig -> S3.StorageClass
|
||||||
getStorageClass c = case fromJust $ M.lookup "storageclass" c of
|
getStorageClass c = case fromJust $ M.lookup "storageclass" c of
|
||||||
|
@ -396,6 +380,21 @@ getXheaders = filter isxheader . M.assocs
|
||||||
where
|
where
|
||||||
isxheader (h, _) = "x-amz-" `isPrefixOf` h
|
isxheader (h, _) = "x-amz-" `isPrefixOf` h
|
||||||
|
|
||||||
|
getFilePrefix :: RemoteConfig -> String
|
||||||
|
getFilePrefix = M.findWithDefault "" "fileprefix"
|
||||||
|
|
||||||
|
{- Internet Archive limits filenames to a subset of ascii,
|
||||||
|
- with no whitespace. Other characters are xml entity
|
||||||
|
- encoded. -}
|
||||||
|
iaMunge :: String -> String
|
||||||
|
iaMunge = (>>= munge)
|
||||||
|
where
|
||||||
|
munge c
|
||||||
|
| isAsciiUpper c || isAsciiLower c || isNumber c = [c]
|
||||||
|
| c `elem` "_-.\"" = [c]
|
||||||
|
| isSpace c = []
|
||||||
|
| otherwise = "&" ++ show (ord c) ++ ";"
|
||||||
|
|
||||||
{- Hostname to use for archive.org S3. -}
|
{- Hostname to use for archive.org S3. -}
|
||||||
iaHost :: HostName
|
iaHost :: HostName
|
||||||
iaHost = "s3.us.archive.org"
|
iaHost = "s3.us.archive.org"
|
||||||
|
@ -406,10 +405,10 @@ isIA c = maybe False isIAHost (M.lookup "host" c)
|
||||||
isIAHost :: HostName -> Bool
|
isIAHost :: HostName -> Bool
|
||||||
isIAHost h = ".archive.org" `isSuffixOf` map toLower h
|
isIAHost h = ".archive.org" `isSuffixOf` map toLower h
|
||||||
|
|
||||||
iaItemUrl :: Bucket -> URLString
|
iaItemUrl :: BucketName -> URLString
|
||||||
iaItemUrl bucket = "http://archive.org/details/" ++ bucket
|
iaItemUrl bucket = "http://archive.org/details/" ++ bucket
|
||||||
|
|
||||||
iaKeyUrl :: Remote -> Key -> URLString
|
iaKeyUrl :: Remote -> Key -> URLString
|
||||||
iaKeyUrl r k = "http://archive.org/download/" ++ bucket ++ "/" ++ bucketFile r k
|
iaKeyUrl r k = "http://archive.org/download/" ++ bucket ++ "/" ++ bucketFile r k
|
||||||
where
|
where
|
||||||
bucket = fromMaybe "" $ getBucket $ config r
|
bucket = fromMaybe "" $ getBucketName $ config r
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue