refactor upload with zimple gzip approach - progress bar broken

This commit is contained in:
Lucy Cifferello
2022-09-14 12:58:07 -06:00
parent 89ad420a2a
commit 99c4777715
3 changed files with 30 additions and 70 deletions

1
.gitignore vendored
View File

@@ -38,3 +38,4 @@ start9-registry.aux
start9-registry.ps start9-registry.ps
shell.nix shell.nix
testdata/ testdata/
lbuild.sh

View File

@@ -17,12 +17,11 @@ import Codec.Archive.Zip.Conduit.Zip (ZipOptions (..), zipFileData, zipStream)
import Conduit ( import Conduit (
ConduitT, ConduitT,
MonadResource, MonadResource,
awaitForever,
foldC, foldC,
runConduit, runConduit,
runResourceT, runResourceT,
sinkHandle, sinkFileCautious,
sinkNull, sourceFile,
yield, yield,
(.|), (.|),
) )
@@ -50,6 +49,7 @@ import Data.ByteArray.Encoding (
import Data.ByteString.Char8 qualified as B8 import Data.ByteString.Char8 qualified as B8
import Data.ByteString.Lazy qualified as LB import Data.ByteString.Lazy qualified as LB
import Data.Conduit.Process (readProcess) import Data.Conduit.Process (readProcess)
import Data.Conduit.Zlib (gzip)
import Data.Default import Data.Default
import Data.Functor.Contravariant (contramap) import Data.Functor.Contravariant (contramap)
import Data.HashMap.Internal.Strict ( import Data.HashMap.Internal.Strict (
@@ -64,6 +64,7 @@ import Data.String.Interpolate.IsString (
i, i,
) )
import Data.Text (toLower) import Data.Text (toLower)
import Data.Text qualified as T
import Data.Time (getTimeZone, utcToLocalTime) import Data.Time (getTimeZone, utcToLocalTime)
import Dhall ( import Dhall (
Encoder (embed), Encoder (embed),
@@ -98,6 +99,7 @@ import Network.HTTP.Simple (
httpLBS, httpLBS,
parseRequest, parseRequest,
setRequestBody, setRequestBody,
setRequestBodyFile,
setRequestBodyJSON, setRequestBodyJSON,
setRequestBodySource, setRequestBodySource,
setRequestHeaders, setRequestHeaders,
@@ -186,7 +188,6 @@ import Startlude (
panic, panic,
show, show,
snd, snd,
stdout,
unlessM, unlessM,
void, void,
when, when,
@@ -205,10 +206,12 @@ import System.Directory (
getFileSize, getFileSize,
getHomeDirectory, getHomeDirectory,
listDirectory, listDirectory,
removeFile,
) )
import System.FilePath ( import System.FilePath (
takeDirectory, takeDirectory,
takeExtension, takeExtension,
(<.>),
(</>), (</>),
) )
import System.ProgressBar ( import System.ProgressBar (
@@ -590,28 +593,40 @@ upload (Upload name mpkg shouldIndex) = do
sfs2prog StreamFileStatus{..} = Progress (fromIntegral readSoFar) (fromIntegral fileSize) () sfs2prog StreamFileStatus{..} = Progress (fromIntegral readSoFar) (fromIntegral fileSize) ()
-- stream read file
-- stream zip file
-- stream zip into request body
-- store on server uncomressed?
eosUpload :: EosUpload -> IO () eosUpload :: EosUpload -> IO ()
eosUpload (EosUpload name img version) = do eosUpload (EosUpload name img version) = do
PublishCfgRepo{..} <- findNameInCfg name PublishCfgRepo{..} <- findNameInCfg name
size <- getFileSize img
noBody <- noBody <-
parseRequest ("POST " <> show publishCfgRepoLocation <> "/admin/v0/eos-upload") parseRequest ("POST " <> show publishCfgRepoLocation <> "/admin/v0/eos-upload")
<&> setRequestHeaders [("accept", "text/plain")] <&> setRequestHeaders [("accept", "text/plain")]
<&> setRequestHeaders [("Content-Type", "application/octet-stream")]
<&> setRequestHeaders [("Content-Encoding", "gzip")] <&> setRequestHeaders [("Content-Encoding", "gzip")]
<&> applyBasicAuth (B8.pack publishCfgRepoUser) (B8.pack publishCfgRepoPass) <&> applyBasicAuth (B8.pack publishCfgRepoUser) (B8.pack publishCfgRepoPass)
hash <- hashFile @_ @SHA256 img hash <- hashFile @_ @SHA256 img
bar <- newProgressBar defStyle 30 (Progress 0 (fromIntegral size) ()) -- let z = (createZipEntry img (Just $ fromIntegral size) .| (zipStream zipOptions))
body <- observedStreamFile (updateProgress bar . const . sfs2prog) img let compressedFilePath = img <.> "gz"
let r = liftIO $ runResourceT $ runConduit $ (createZipEntry img (Just $ fromIntegral size) .| void (zipStream zipOptions)) .| sinkHandle stdout runResourceT $
runConduit $
sourceFile img
.| gzip
.| sinkFileCautious compressedFilePath
gSize <- getFileSize compressedFilePath
bar <- newProgressBar defStyle 30 (Progress 0 (fromIntegral gSize) ())
body <- observedStreamFile (updateProgress bar . const . sfs2prog) $ compressedFilePath
let withBody = setRequestBody body noBody let withBody = setRequestBody body noBody
let withQParams = let withQParams =
setRequestQueryString setRequestQueryString
[("version", Just $ show version), ("hash", Just $ convertToBase Base16 hash)] [("version", Just $ show version), ("hash", Just $ convertToBase Base16 hash)]
withBody withBody
let withSource = setRequestBodySource (fromIntegral size) (r) withQParams -- let withSource = setRequestBodySource (fromIntegral size) _ withQParams
let req = setRequestBodyFile compressedFilePath withQParams
manager <- newTlsManager manager <- newTlsManager
res <- runReaderT (httpLbs withSource) manager res <- runReaderT (httpLbs req) manager
removeFile $ compressedFilePath
if getResponseStatus res == status200 if getResponseStatus res == status200
then -- no output is successful then -- no output is successful
pure () pure ()
@@ -625,13 +640,14 @@ eosUpload (EosUpload name img version) = do
zipOptions = zipOptions =
ZipOptions ZipOptions
{ zipOpt64 = True { zipOpt64 = True
, zipOptCompressLevel = 0 , zipOptCompressLevel = 6
, zipOptInfo = ZipInfo{zipComment = encodeUtf8 "zipped eos image"} , zipOptInfo = ZipInfo{zipComment = encodeUtf8 "zipped eos image"}
} }
createZipEntry :: createZipEntry ::
MonadResource m => MonadResource m =>
FilePath -> FilePath ->
Maybe Word64 -> Maybe Word64 ->
-- ZipData m ->
ConduitT () (ZipEntry, ZipData m) m () ConduitT () (ZipEntry, ZipData m) m ()
createZipEntry path size = do createZipEntry path size = do
let d = zipFileData img let d = zipFileData img
@@ -639,7 +655,7 @@ eosUpload (EosUpload name img version) = do
localTimeZone <- liftIO $ getTimeZone utcTime localTimeZone <- liftIO $ getTimeZone utcTime
let zipEntry = let zipEntry =
ZipEntry ZipEntry
{ zipEntryName = Right $ encodeUtf8 $ show path { zipEntryName = Left $ T.pack "eos.img.gz"
, zipEntryTime = utcToLocalTime localTimeZone utcTime , zipEntryTime = utcToLocalTime localTimeZone utcTime
, zipEntrySize = size , zipEntrySize = size
, zipEntryExternalAttributes = Nothing , zipEntryExternalAttributes = Nothing
@@ -647,11 +663,6 @@ eosUpload (EosUpload name img version) = do
yield (zipEntry, d) yield (zipEntry, d)
_yieldFinal :: Monad m => ConduitT (ZipEntry, ZipData m) B8.ByteString m Word64 -> ConduitT () B8.ByteString m ()
_yieldFinal consumer = awaitForever $ \_ -> do
yield consumer .| sinkNull
index :: String -> String -> Version -> IO () index :: String -> String -> Version -> IO ()
index name pkg v = performHttp name "POST" [i|/admin/v0/index|] (IndexPkgReq (PkgId $ toS pkg) v) index name pkg v = performHttp name "POST" [i|/admin/v0/index|] (IndexPkgReq (PkgId $ toS pkg) v)

View File

@@ -5,27 +5,9 @@
module Handler.Admin where module Handler.Admin where
import Codec.Archive.Zip.Conduit.Zip (
ZipData (ZipDataSource),
ZipEntry (
ZipEntry,
zipEntryExternalAttributes,
zipEntryName,
zipEntrySize,
zipEntryTime
),
ZipInfo (..),
ZipOptions (..),
zipStream,
)
import Conduit ( import Conduit (
ConduitT,
MonadUnliftIO,
fuseUpstream,
runConduit, runConduit,
sinkFile, sinkFile,
sinkFileBS,
yield,
(.|), (.|),
) )
import Control.Monad.Extra import Control.Monad.Extra
@@ -41,7 +23,6 @@ import Data.Aeson (
(.:?), (.:?),
(.=), (.=),
) )
import Data.ByteString (ByteString)
import Data.HashMap.Internal.Strict ( import Data.HashMap.Internal.Strict (
HashMap, HashMap,
differenceWith, differenceWith,
@@ -109,25 +90,19 @@ import Settings
import Startlude ( import Startlude (
Applicative (pure), Applicative (pure),
Bool (..), Bool (..),
Either (Right),
Eq, Eq,
FilePath,
Int, Int,
Maybe (..), Maybe (..),
Show, Show,
SomeException (..), SomeException (..),
Text, Text,
Word64,
asum, asum,
decodeUtf8,
encodeUtf8,
fromMaybe, fromMaybe,
guarded, guarded,
hush, hush,
isNothing, isNothing,
liftIO, liftIO,
not, not,
readMaybe,
replicate, replicate,
show, show,
toS, toS,
@@ -160,7 +135,6 @@ import Yesod (
delete, delete,
getsYesod, getsYesod,
logError, logError,
lookupHeader,
rawRequestBody, rawRequestBody,
requireCheckJsonBody, requireCheckJsonBody,
runDB, runDB,
@@ -214,42 +188,16 @@ postEosUploadR = do
hash <- case maybeHash of hash <- case maybeHash of
Nothing -> sendResponseStatus status400 ("Missing Hash" :: Text) Nothing -> sendResponseStatus status400 ("Missing Hash" :: Text)
Just h -> pure h Just h -> pure h
-- (maybeSize :: Maybe Word64) <- maybeM (pure Nothing) (pure . readMaybe . decodeUtf8) (lookupHeader "Content-Length")
resourcesTemp <- getsYesod $ (</> "temp") . resourcesDir . appSettings resourcesTemp <- getsYesod $ (</> "temp") . resourcesDir . appSettings
createDirectoryIfMissing True resourcesTemp createDirectoryIfMissing True resourcesTemp
withTempDirectory resourcesTemp "neweos" $ \dir -> do withTempDirectory resourcesTemp "neweos" $ \dir -> do
let path = dir </> "eos" <.> "img" let path = dir </> "eos" <.> "img"
runConduit $ rawRequestBody .| sinkFile path runConduit $ rawRequestBody .| sinkFile path
-- void . runConduit $ createZipEntry path maybeSize rawRequestBody .| (zipStream zipOptions `fuseUpstream` sinkFileBS path)
void . runDB $ upsert (EosHash version hash) [EosHashHash =. hash] void . runDB $ upsert (EosHash version hash) [EosHashHash =. hash]
let targetPath = root </> show version let targetPath = root </> show version
removePathForcibly targetPath removePathForcibly targetPath
createDirectoryIfMissing True targetPath createDirectoryIfMissing True targetPath
renameDirectory dir targetPath renameDirectory dir targetPath
where
zipOptions =
ZipOptions
{ zipOpt64 = True
, zipOptCompressLevel = -1
, zipOptInfo = ZipInfo{zipComment = encodeUtf8 "zipped eos image"}
}
createZipEntry ::
(MonadUnliftIO m) =>
FilePath ->
Maybe Word64 ->
ConduitT () ByteString m () ->
ConduitT () (ZipEntry, ZipData m) m ()
createZipEntry path size dataSource = do
utcTime <- liftIO getCurrentTime
localTimeZone <- liftIO $ getTimeZone utcTime
let zipEntry =
ZipEntry
{ zipEntryName = Right $ encodeUtf8 $ show path
, zipEntryTime = utcToLocalTime localTimeZone utcTime
, zipEntrySize = size
, zipEntryExternalAttributes = Nothing
}
yield (zipEntry, ZipDataSource dataSource)
data IndexPkgReq = IndexPkgReq data IndexPkgReq = IndexPkgReq