mirror of
https://github.com/Start9Labs/registry.git
synced 2026-03-26 02:11:53 +00:00
refactor upload with zimple gzip approach - progress bar broken
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -38,3 +38,4 @@ start9-registry.aux
|
|||||||
start9-registry.ps
|
start9-registry.ps
|
||||||
shell.nix
|
shell.nix
|
||||||
testdata/
|
testdata/
|
||||||
|
lbuild.sh
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user