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,
|
||||
encryptKey,
|
||||
feedFile,
|
||||
feedFileMetered,
|
||||
feedBytes,
|
||||
readBytes,
|
||||
encrypt,
|
||||
|
@ -36,6 +37,8 @@ import Common.Annex
|
|||
import qualified Utility.Gpg as Gpg
|
||||
import Types.Key
|
||||
import Types.Crypto
|
||||
import Types.Remote
|
||||
import Utility.Observed
|
||||
|
||||
{- The first half of a Cipher is used for HMAC; the remainder
|
||||
- is used as the GPG symmetric encryption passphrase.
|
||||
|
@ -122,6 +125,11 @@ type Reader a = Handle -> IO a
|
|||
feedFile :: FilePath -> Feeder
|
||||
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 = flip L.hPut
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import Remote.Helper.Encryptable
|
|||
import Remote.Helper.Chunked
|
||||
import Crypto
|
||||
import Creds
|
||||
import Utility.Observed
|
||||
|
||||
type DavUrl = String
|
||||
type DavUser = B8.ByteString
|
||||
|
@ -84,17 +85,21 @@ webdavSetup u c = do
|
|||
setRemoteCredPair c' (davCreds u)
|
||||
|
||||
store :: Remote -> Key -> AssociatedFile -> MeterUpdate -> Annex Bool
|
||||
store r k _f _p = davAction r False $ \(baseurl, user, pass) -> do
|
||||
let url = davLocation baseurl k
|
||||
f <- inRepo $ gitAnnexLocation k
|
||||
liftIO $ storeHelper r url user pass =<< L.readFile f
|
||||
store r k _f p = metered (Just p) k $ \meterupdate ->
|
||||
davAction r False $ \(baseurl, user, pass) -> do
|
||||
let url = davLocation baseurl k
|
||||
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 r (cipher, enck) k _p = davAction r False $ \(baseurl, user, pass) -> do
|
||||
let url = davLocation baseurl enck
|
||||
f <- inRepo $ gitAnnexLocation k
|
||||
liftIO $ encrypt cipher (feedFile f) $
|
||||
readBytes $ storeHelper r url user pass
|
||||
storeEncrypted r (cipher, enck) k p = metered (Just p) k $ \meterupdate ->
|
||||
davAction r False $ \(baseurl, user, pass) -> do
|
||||
let url = davLocation baseurl enck
|
||||
f <- inRepo $ gitAnnexLocation k
|
||||
liftIO $ encrypt cipher (feedFileMetered f meterupdate) $
|
||||
readBytes $ storeHelper r url user pass
|
||||
|
||||
storeHelper :: Remote -> DavUrl -> DavUser -> DavPass -> L.ByteString -> IO Bool
|
||||
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
|
||||
|
||||
* 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
|
||||
could use inotify. **done**
|
||||
|
||||
|
@ -23,7 +22,7 @@ the MeterUpdate callback as the upload progresses.
|
|||
* rsync: **done**
|
||||
* directory: **done**
|
||||
* web: Not applicable; does not upload
|
||||
* webdav: TODO
|
||||
* webdav: **done**
|
||||
* S3: TODO
|
||||
* bup: TODO
|
||||
* hook: Would require the hook interface to somehow do this, which seems
|
||||
|
|
Loading…
Reference in a new issue