upload progress bars for webdav!
This commit is contained in:
parent
c8751be151
commit
afa2f9c967
4 changed files with 66 additions and 11 deletions
|
@ -19,6 +19,7 @@ module Crypto (
|
||||||
decryptCipher,
|
decryptCipher,
|
||||||
encryptKey,
|
encryptKey,
|
||||||
feedFile,
|
feedFile,
|
||||||
|
feedFileMetered,
|
||||||
feedBytes,
|
feedBytes,
|
||||||
readBytes,
|
readBytes,
|
||||||
encrypt,
|
encrypt,
|
||||||
|
@ -36,6 +37,8 @@ import Common.Annex
|
||||||
import qualified Utility.Gpg as Gpg
|
import qualified Utility.Gpg as Gpg
|
||||||
import Types.Key
|
import Types.Key
|
||||||
import Types.Crypto
|
import Types.Crypto
|
||||||
|
import Types.Remote
|
||||||
|
import Utility.Observed
|
||||||
|
|
||||||
{- The first half of a Cipher is used for HMAC; the remainder
|
{- The first half of a Cipher is used for HMAC; the remainder
|
||||||
- is used as the GPG symmetric encryption passphrase.
|
- is used as the GPG symmetric encryption passphrase.
|
||||||
|
@ -122,6 +125,11 @@ type Reader a = Handle -> IO a
|
||||||
feedFile :: FilePath -> Feeder
|
feedFile :: FilePath -> Feeder
|
||||||
feedFile f h = L.hPut h =<< L.readFile f
|
feedFile f h = L.hPut h =<< L.readFile f
|
||||||
|
|
||||||
|
feedFileMetered :: FilePath -> MeterUpdate -> Feeder
|
||||||
|
feedFileMetered f m to = withBinaryFile f ReadMode $ \h -> do
|
||||||
|
b <- hGetContentsObserved h $ m . toInteger
|
||||||
|
L.hPut to b
|
||||||
|
|
||||||
feedBytes :: L.ByteString -> Feeder
|
feedBytes :: L.ByteString -> Feeder
|
||||||
feedBytes = flip L.hPut
|
feedBytes = flip L.hPut
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ import Remote.Helper.Encryptable
|
||||||
import Remote.Helper.Chunked
|
import Remote.Helper.Chunked
|
||||||
import Crypto
|
import Crypto
|
||||||
import Creds
|
import Creds
|
||||||
|
import Utility.Observed
|
||||||
|
|
||||||
type DavUrl = String
|
type DavUrl = String
|
||||||
type DavUser = B8.ByteString
|
type DavUser = B8.ByteString
|
||||||
|
@ -84,17 +85,21 @@ webdavSetup u c = do
|
||||||
setRemoteCredPair c' (davCreds u)
|
setRemoteCredPair c' (davCreds u)
|
||||||
|
|
||||||
store :: Remote -> Key -> AssociatedFile -> MeterUpdate -> Annex Bool
|
store :: Remote -> Key -> AssociatedFile -> MeterUpdate -> Annex Bool
|
||||||
store r k _f _p = davAction r False $ \(baseurl, user, pass) -> do
|
store r k _f p = metered (Just p) k $ \meterupdate ->
|
||||||
let url = davLocation baseurl k
|
davAction r False $ \(baseurl, user, pass) -> do
|
||||||
f <- inRepo $ gitAnnexLocation k
|
let url = davLocation baseurl k
|
||||||
liftIO $ storeHelper r url user pass =<< L.readFile f
|
f <- inRepo $ gitAnnexLocation k
|
||||||
|
liftIO $ withBinaryFile f ReadMode $ \h -> do
|
||||||
|
b <- hGetContentsObserved h $ meterupdate . toInteger
|
||||||
|
storeHelper r url user pass b
|
||||||
|
|
||||||
storeEncrypted :: Remote -> (Cipher, Key) -> Key -> MeterUpdate -> Annex Bool
|
storeEncrypted :: Remote -> (Cipher, Key) -> Key -> MeterUpdate -> Annex Bool
|
||||||
storeEncrypted r (cipher, enck) k _p = davAction r False $ \(baseurl, user, pass) -> do
|
storeEncrypted r (cipher, enck) k p = metered (Just p) k $ \meterupdate ->
|
||||||
let url = davLocation baseurl enck
|
davAction r False $ \(baseurl, user, pass) -> do
|
||||||
f <- inRepo $ gitAnnexLocation k
|
let url = davLocation baseurl enck
|
||||||
liftIO $ encrypt cipher (feedFile f) $
|
f <- inRepo $ gitAnnexLocation k
|
||||||
readBytes $ storeHelper r url user pass
|
liftIO $ encrypt cipher (feedFileMetered f meterupdate) $
|
||||||
|
readBytes $ storeHelper r url user pass
|
||||||
|
|
||||||
storeHelper :: Remote -> DavUrl -> DavUser -> DavPass -> L.ByteString -> IO Bool
|
storeHelper :: Remote -> DavUrl -> DavUser -> DavPass -> L.ByteString -> IO Bool
|
||||||
storeHelper r urlbase user pass b = catchBoolIO $ do
|
storeHelper r urlbase user pass b = catchBoolIO $ do
|
||||||
|
|
43
Utility/Observed.hs
Normal file
43
Utility/Observed.hs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
module Utility.Observed where
|
||||||
|
|
||||||
|
import qualified Data.ByteString.Lazy as L
|
||||||
|
import qualified Data.ByteString as S
|
||||||
|
import System.IO
|
||||||
|
import System.IO.Unsafe
|
||||||
|
import Foreign.Storable (Storable(sizeOf))
|
||||||
|
|
||||||
|
{- This is like L.hGetContents, but after each chunk is read, an action
|
||||||
|
- is run to observe the size of the chunk.
|
||||||
|
-
|
||||||
|
- Note that the observer is run in unsafeInterleaveIO, which means that
|
||||||
|
- it can be run at any time. It's even possible for observers to run out
|
||||||
|
- of order, as different parts of the ByteString are consumed.
|
||||||
|
-
|
||||||
|
- All the usual caveats about using unsafeInterleaveIO apply to the observers,
|
||||||
|
- so use caution.
|
||||||
|
-}
|
||||||
|
hGetContentsObserved :: Handle -> (Int -> IO ()) -> IO L.ByteString
|
||||||
|
hGetContentsObserved h observe = lazyRead
|
||||||
|
where
|
||||||
|
lazyRead = unsafeInterleaveIO loop
|
||||||
|
|
||||||
|
loop = do
|
||||||
|
c <- S.hGetSome h defaultChunkSize
|
||||||
|
if S.null c
|
||||||
|
then do
|
||||||
|
hClose h
|
||||||
|
return $ L.empty
|
||||||
|
else do
|
||||||
|
observe $ S.length c
|
||||||
|
{- unsafeInterleaveIO causes this to be
|
||||||
|
- deferred until the data is read from the
|
||||||
|
- ByteString. -}
|
||||||
|
cs <- lazyRead
|
||||||
|
return $ L.append (L.fromChunks [c]) cs
|
||||||
|
|
||||||
|
{- Same default chunk size Lazy ByteStrings use. -}
|
||||||
|
defaultChunkSize :: Int
|
||||||
|
defaultChunkSize = 32 * k - chunkOverhead
|
||||||
|
where
|
||||||
|
k = 1024
|
||||||
|
chunkOverhead = 2 * sizeOf (undefined :: Int) -- GHC specific
|
|
@ -10,7 +10,6 @@ This is one of those potentially hidden but time consuming problems.
|
||||||
## downloads
|
## downloads
|
||||||
|
|
||||||
* Watch temp file as it's coming in and use its size.
|
* Watch temp file as it's coming in and use its size.
|
||||||
This is the only option for some special remotes (ie, non-rsync).
|
|
||||||
Can either poll every .5 seconds or so to check file size, or
|
Can either poll every .5 seconds or so to check file size, or
|
||||||
could use inotify. **done**
|
could use inotify. **done**
|
||||||
|
|
||||||
|
@ -23,7 +22,7 @@ the MeterUpdate callback as the upload progresses.
|
||||||
* rsync: **done**
|
* rsync: **done**
|
||||||
* directory: **done**
|
* directory: **done**
|
||||||
* web: Not applicable; does not upload
|
* web: Not applicable; does not upload
|
||||||
* webdav: TODO
|
* webdav: **done**
|
||||||
* S3: TODO
|
* S3: TODO
|
||||||
* bup: TODO
|
* bup: TODO
|
||||||
* hook: Would require the hook interface to somehow do this, which seems
|
* hook: Would require the hook interface to somehow do this, which seems
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue