mirror of
https://github.com/Start9Labs/registry.git
synced 2026-03-30 19:54:47 +00:00
autohash eos
This commit is contained in:
@@ -90,7 +90,9 @@ import Handler.ErrorLogs
|
|||||||
import Handler.Icons
|
import Handler.Icons
|
||||||
import Handler.Marketplace
|
import Handler.Marketplace
|
||||||
import Handler.Version
|
import Handler.Version
|
||||||
import Lib.PkgRepository ( watchPkgRepoRoot )
|
import Lib.PkgRepository ( watchEosRepoRoot
|
||||||
|
, watchPkgRepoRoot
|
||||||
|
)
|
||||||
import Lib.Ssl
|
import Lib.Ssl
|
||||||
import Model
|
import Model
|
||||||
import Network.HTTP.Types.Header ( hOrigin )
|
import Network.HTTP.Types.Header ( hOrigin )
|
||||||
@@ -129,12 +131,13 @@ makeFoundation appSettings = do
|
|||||||
-- logging function. To get out of this loop, we initially create a
|
-- logging function. To get out of this loop, we initially create a
|
||||||
-- temporary foundation without a real connection pool, get a log function
|
-- temporary foundation without a real connection pool, get a log function
|
||||||
-- from there, and then create the real foundation.
|
-- from there, and then create the real foundation.
|
||||||
let mkFoundation appConnPool appStopFsNotify = RegistryCtx { .. }
|
let mkFoundation appConnPool appStopFsNotifyPkg appStopFsNotifyEos = RegistryCtx { .. }
|
||||||
-- The RegistryCtx {..} syntax is an example of record wild cards. For more
|
-- The RegistryCtx {..} syntax is an example of record wild cards. For more
|
||||||
-- information, see:
|
-- information, see:
|
||||||
-- https://ocharles.org.uk/blog/posts/2014-12-04-record-wildcards.html
|
-- https://ocharles.org.uk/blog/posts/2014-12-04-record-wildcards.html
|
||||||
tempFoundation =
|
tempFoundation = mkFoundation (panic "connPool forced in tempFoundation")
|
||||||
mkFoundation (panic "connPool forced in tempFoundation") (panic "stopFsNotify forced in tempFoundation")
|
(panic "stopFsNotify forced in tempFoundation")
|
||||||
|
(panic "stopFsNotify forced in tempFoundation")
|
||||||
logFunc = messageLoggerSource tempFoundation appLogger
|
logFunc = messageLoggerSource tempFoundation appLogger
|
||||||
|
|
||||||
createDirectoryIfMissing True (errorLogRoot appSettings)
|
createDirectoryIfMissing True (errorLogRoot appSettings)
|
||||||
@@ -143,13 +146,14 @@ makeFoundation appSettings = do
|
|||||||
pool <- flip runLoggingT logFunc
|
pool <- flip runLoggingT logFunc
|
||||||
$ createPostgresqlPool (pgConnStr $ appDatabaseConf appSettings) (pgPoolSize . appDatabaseConf $ appSettings)
|
$ createPostgresqlPool (pgConnStr $ appDatabaseConf appSettings) (pgPoolSize . appDatabaseConf $ appSettings)
|
||||||
|
|
||||||
stop <- runLoggingT (runReaderT (watchPkgRepoRoot pool) appSettings) logFunc
|
stopPkgWatch <- runLoggingT (runReaderT (watchPkgRepoRoot pool) appSettings) logFunc
|
||||||
|
stopEosWatch <- runLoggingT (runReaderT (watchEosRepoRoot pool) appSettings) logFunc
|
||||||
|
|
||||||
-- Preform database migration using application logging settings
|
-- Preform database migration using application logging settings
|
||||||
runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc
|
runLoggingT (runSqlPool (runMigration migrateAll) pool) logFunc
|
||||||
|
|
||||||
-- Return the foundation
|
-- Return the foundation
|
||||||
return $ mkFoundation pool stop
|
return $ mkFoundation pool stopPkgWatch stopEosWatch
|
||||||
|
|
||||||
-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
|
-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
|
||||||
-- applying some additional middlewares.
|
-- applying some additional middlewares.
|
||||||
@@ -315,7 +319,7 @@ startWeb foundation = do
|
|||||||
app <- makeApplication foundation
|
app <- makeApplication foundation
|
||||||
startWeb' app
|
startWeb' app
|
||||||
where
|
where
|
||||||
startWeb' app = (`onException` (appStopFsNotify foundation)) $ do
|
startWeb' app = (`onException` (appStopFsNotifyPkg foundation *> appStopFsNotifyEos foundation)) $ do
|
||||||
let AppSettings {..} = appSettings foundation
|
let AppSettings {..} = appSettings foundation
|
||||||
runLog $ $logInfo $ [i|Launching Tor Web Server on port #{torPort}|]
|
runLog $ $logInfo $ [i|Launching Tor Web Server on port #{torPort}|]
|
||||||
torAction <- async $ runSettings (warpSettings torPort foundation) app
|
torAction <- async $ runSettings (warpSettings torPort foundation) app
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||||
{-# LANGUAGE InstanceSigs #-}
|
{-# LANGUAGE InstanceSigs #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE RankNTypes #-}
|
{-# LANGUAGE RankNTypes #-}
|
||||||
@@ -5,8 +6,10 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-# LANGUAGE TypeApplications #-}
|
{-# LANGUAGE TypeApplications #-}
|
||||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
module Foundation where
|
module Foundation where
|
||||||
|
|
||||||
@@ -42,7 +45,6 @@ import System.Console.ANSI.Codes ( Color(..)
|
|||||||
, ConsoleLayer(Foreground)
|
, ConsoleLayer(Foreground)
|
||||||
, SGR(SetColor)
|
, SGR(SetColor)
|
||||||
)
|
)
|
||||||
import System.FilePath ( (</>) )
|
|
||||||
import Yesod.Persist.Core
|
import Yesod.Persist.Core
|
||||||
|
|
||||||
-- | The foundation datatype for your application. This can be a good place to
|
-- | The foundation datatype for your application. This can be a good place to
|
||||||
@@ -57,15 +59,12 @@ data RegistryCtx = RegistryCtx
|
|||||||
, appWebServerThreadId :: MVar (ThreadId, ThreadId)
|
, appWebServerThreadId :: MVar (ThreadId, ThreadId)
|
||||||
, appShouldRestartWeb :: MVar Bool
|
, appShouldRestartWeb :: MVar Bool
|
||||||
, appConnPool :: ConnectionPool
|
, appConnPool :: ConnectionPool
|
||||||
, appStopFsNotify :: IO Bool
|
, appStopFsNotifyPkg :: IO Bool
|
||||||
|
, appStopFsNotifyEos :: IO Bool
|
||||||
}
|
}
|
||||||
instance Has PkgRepo RegistryCtx where
|
instance Has PkgRepo RegistryCtx where
|
||||||
extract = do
|
extract = transitiveExtract @AppSettings
|
||||||
liftA2 PkgRepo ((</> "apps") . resourcesDir . appSettings) (staticBinDir . appSettings)
|
update = transitiveUpdate @AppSettings
|
||||||
update f ctx =
|
|
||||||
let repo = f $ extract ctx
|
|
||||||
settings = (appSettings ctx) { resourcesDir = pkgRepoFileRoot repo, staticBinDir = pkgRepoAppMgrBin repo }
|
|
||||||
in ctx { appSettings = settings }
|
|
||||||
instance Has a r => Has a (HandlerData r r) where
|
instance Has a r => Has a (HandlerData r r) where
|
||||||
extract = extract . rheSite . handlerEnv
|
extract = extract . rheSite . handlerEnv
|
||||||
update f r =
|
update f r =
|
||||||
@@ -75,6 +74,15 @@ instance Has a r => Has a (HandlerData r r) where
|
|||||||
instance Has AppSettings RegistryCtx where
|
instance Has AppSettings RegistryCtx where
|
||||||
extract = appSettings
|
extract = appSettings
|
||||||
update f ctx = ctx { appSettings = f (appSettings ctx) }
|
update f ctx = ctx { appSettings = f (appSettings ctx) }
|
||||||
|
instance Has EosRepo RegistryCtx where
|
||||||
|
extract = transitiveExtract @AppSettings
|
||||||
|
update = transitiveUpdate @AppSettings
|
||||||
|
|
||||||
|
transitiveExtract :: forall b a c . (Has a b, Has b c) => c -> a
|
||||||
|
transitiveExtract = extract @a . extract @b
|
||||||
|
transitiveUpdate :: forall b a c . (Has a b, Has b c) => (a -> a) -> (c -> c)
|
||||||
|
transitiveUpdate f = update (update @a @b f)
|
||||||
|
|
||||||
|
|
||||||
setWebProcessThreadId :: (ThreadId, ThreadId) -> RegistryCtx -> IO ()
|
setWebProcessThreadId :: (ThreadId, ThreadId) -> RegistryCtx -> IO ()
|
||||||
setWebProcessThreadId tid a = putMVar (appWebServerThreadId a) $ tid
|
setWebProcessThreadId tid a = putMVar (appWebServerThreadId a) $ tid
|
||||||
|
|||||||
@@ -242,17 +242,17 @@ getPackageListR = do
|
|||||||
$ searchServices category query
|
$ searchServices category query
|
||||||
.| zipVersions
|
.| zipVersions
|
||||||
.| zipCategories
|
.| zipCategories
|
||||||
-- empty list since there are no requested packages in this case
|
-- empty list since there are no requested packages in this case
|
||||||
.| filterLatestVersionFromSpec []
|
.| filterLatestVersionFromSpec []
|
||||||
.| filterPkgOsCompatible osPredicate
|
.| filterPkgOsCompatible osPredicate
|
||||||
-- pages start at 1 for some reason. TODO: make pages start at 0
|
-- pages start at 1 for some reason. TODO: make pages start at 0
|
||||||
.| (dropC (limit' * (page - 1)) *> takeC limit')
|
.| (dropC (limit' * (page - 1)) *> takeC limit')
|
||||||
.| sinkList
|
.| sinkList
|
||||||
Just packages' -> do
|
Just packages' -> do
|
||||||
-- for each item in list get best available from version range
|
-- for each item in list get best available from version range
|
||||||
let vMap = (packageReqId &&& packageReqVersion) <$> packages'
|
let vMap = (packageReqId &&& packageReqVersion) <$> packages'
|
||||||
runDB
|
runDB
|
||||||
-- TODO could probably be better with sequenceConduits
|
-- TODO could probably be better with sequenceConduits
|
||||||
. runConduit
|
. runConduit
|
||||||
$ getPkgData (packageReqId <$> packages')
|
$ getPkgData (packageReqId <$> packages')
|
||||||
.| zipVersions
|
.| zipVersions
|
||||||
@@ -354,8 +354,7 @@ getPackageListR = do
|
|||||||
runConduit $ bs .| CL.foldMap LBS.fromStrict
|
runConduit $ bs .| CL.foldMap LBS.fromStrict
|
||||||
icon <- loadIcon pkgId pkgVersion
|
icon <- loadIcon pkgId pkgVersion
|
||||||
deps <- constructDependenciesApiRes dependencies
|
deps <- constructDependenciesApiRes dependencies
|
||||||
pure $ PackageRes { packageResIcon = encodeBase64 icon
|
pure $ PackageRes { packageResIcon = encodeBase64 icon -- pass through raw JSON Value, we have checked its correct parsing above
|
||||||
-- pass through raw JSON Value, we have checked its correct parsing above
|
|
||||||
, packageResManifest = unsafeFromJust . decode $ manifest
|
, packageResManifest = unsafeFromJust . decode $ manifest
|
||||||
, packageResCategories = categoryName <$> pkgCategories
|
, packageResCategories = categoryName <$> pkgCategories
|
||||||
, packageResInstructions = basicRender $ InstructionsR pkgId
|
, packageResInstructions = basicRender $ InstructionsR pkgId
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE TypeApplications #-}
|
{-# LANGUAGE TypeApplications #-}
|
||||||
{-# OPTIONS_GHC -Wno-name-shadowing #-}
|
{-# OPTIONS_GHC -Wno-name-shadowing #-}
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
|
|
||||||
module Lib.PkgRepository where
|
module Lib.PkgRepository where
|
||||||
|
|
||||||
@@ -27,8 +28,14 @@ import Control.Monad.Reader.Has ( Has
|
|||||||
, ask
|
, ask
|
||||||
, asks
|
, asks
|
||||||
)
|
)
|
||||||
|
import Crypto.Hash ( SHA256 )
|
||||||
|
import Crypto.Hash.Conduit ( hashFile )
|
||||||
import Data.Aeson ( eitherDecodeFileStrict' )
|
import Data.Aeson ( eitherDecodeFileStrict' )
|
||||||
import qualified Data.Attoparsec.Text as Atto
|
import qualified Data.Attoparsec.Text as Atto
|
||||||
|
import Data.Attoparsec.Text ( parseOnly )
|
||||||
|
import Data.ByteArray.Encoding ( Base(Base16)
|
||||||
|
, convertToBase
|
||||||
|
)
|
||||||
import Data.ByteString ( readFile
|
import Data.ByteString ( readFile
|
||||||
, writeFile
|
, writeFile
|
||||||
)
|
)
|
||||||
@@ -42,6 +49,8 @@ import Database.Esqueleto.Experimental
|
|||||||
, insertUnique
|
, insertUnique
|
||||||
, runSqlPool
|
, runSqlPool
|
||||||
)
|
)
|
||||||
|
import Database.Persist ( (=.) )
|
||||||
|
import Database.Persist.Class ( upsert )
|
||||||
import Lib.Error ( S9Error(NotFoundE) )
|
import Lib.Error ( S9Error(NotFoundE) )
|
||||||
import qualified Lib.External.AppMgr as AppMgr
|
import qualified Lib.External.AppMgr as AppMgr
|
||||||
import Lib.Types.AppIndex ( PackageManifest(..)
|
import Lib.Types.AppIndex ( PackageManifest(..)
|
||||||
@@ -74,9 +83,11 @@ import Startlude ( ($)
|
|||||||
, Ord(compare)
|
, Ord(compare)
|
||||||
, Show
|
, Show
|
||||||
, SomeException(..)
|
, SomeException(..)
|
||||||
|
, decodeUtf8
|
||||||
, filter
|
, filter
|
||||||
, find
|
, find
|
||||||
, first
|
, first
|
||||||
|
, flip
|
||||||
, for_
|
, for_
|
||||||
, fst
|
, fst
|
||||||
, headMay
|
, headMay
|
||||||
@@ -101,6 +112,7 @@ import System.FilePath ( (<.>)
|
|||||||
, takeBaseName
|
, takeBaseName
|
||||||
, takeDirectory
|
, takeDirectory
|
||||||
, takeExtension
|
, takeExtension
|
||||||
|
, takeFileName
|
||||||
)
|
)
|
||||||
import UnliftIO ( MonadUnliftIO
|
import UnliftIO ( MonadUnliftIO
|
||||||
, askRunInIO
|
, askRunInIO
|
||||||
@@ -137,6 +149,10 @@ data PkgRepo = PkgRepo
|
|||||||
, pkgRepoAppMgrBin :: FilePath
|
, pkgRepoAppMgrBin :: FilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data EosRepo = EosRepo
|
||||||
|
{ eosRepoFileRoot :: FilePath
|
||||||
|
}
|
||||||
|
|
||||||
getVersionsFor :: (MonadIO m, MonadReader r m, Has PkgRepo r, MonadLogger m) => PkgId -> m [Version]
|
getVersionsFor :: (MonadIO m, MonadReader r m, Has PkgRepo r, MonadLogger m) => PkgId -> m [Version]
|
||||||
getVersionsFor pkg = do
|
getVersionsFor pkg = do
|
||||||
root <- asks pkgRepoFileRoot
|
root <- asks pkgRepoFileRoot
|
||||||
@@ -222,7 +238,7 @@ extractPkg pool fp = handle @_ @SomeException cleanup $ do
|
|||||||
|
|
||||||
watchPkgRepoRoot :: (MonadUnliftIO m, MonadReader r m, Has PkgRepo r, MonadLoggerIO m) => ConnectionPool -> m (IO Bool)
|
watchPkgRepoRoot :: (MonadUnliftIO m, MonadReader r m, Has PkgRepo r, MonadLoggerIO m) => ConnectionPool -> m (IO Bool)
|
||||||
watchPkgRepoRoot pool = do
|
watchPkgRepoRoot pool = do
|
||||||
$logInfo "Starting FSNotify Watch Manager"
|
$logInfo "Starting FSNotify Watch Manager: PKG"
|
||||||
root <- asks pkgRepoFileRoot
|
root <- asks pkgRepoFileRoot
|
||||||
runInIO <- askRunInIO
|
runInIO <- askRunInIO
|
||||||
box <- newEmptyMVar @_ @()
|
box <- newEmptyMVar @_ @()
|
||||||
@@ -241,6 +257,36 @@ watchPkgRepoRoot pool = do
|
|||||||
onlyAdded (Modified path _ isDir) = not isDir && takeExtension path == ".s9pk"
|
onlyAdded (Modified path _ isDir) = not isDir && takeExtension path == ".s9pk"
|
||||||
onlyAdded _ = False
|
onlyAdded _ = False
|
||||||
|
|
||||||
|
watchEosRepoRoot :: (MonadUnliftIO m, MonadReader r m, Has EosRepo r, MonadLoggerIO m) => ConnectionPool -> m (IO Bool)
|
||||||
|
watchEosRepoRoot pool = do
|
||||||
|
$logInfo "Starting FSNotify Watch Manager: EOS"
|
||||||
|
root <- asks eosRepoFileRoot
|
||||||
|
runInIO <- askRunInIO
|
||||||
|
box <- newEmptyMVar @_ @()
|
||||||
|
_ <- forkIO $ liftIO $ withManager $ \watchManager -> do
|
||||||
|
stop <- watchTree watchManager root shouldIndex $ \evt -> do
|
||||||
|
let os = eventPath evt
|
||||||
|
void . forkIO $ runInIO $ do
|
||||||
|
indexOs pool os
|
||||||
|
takeMVar box
|
||||||
|
stop
|
||||||
|
pure $ tryPutMVar box ()
|
||||||
|
where
|
||||||
|
shouldIndex :: ActionPredicate
|
||||||
|
shouldIndex (Added path _ isDir) = not isDir && takeExtension path == ".img"
|
||||||
|
shouldIndex (Modified path _ isDir) = not isDir && takeExtension path == ".img"
|
||||||
|
shouldIndex _ = False
|
||||||
|
indexOs :: (MonadUnliftIO m, MonadLoggerIO m) => ConnectionPool -> FilePath -> m ()
|
||||||
|
indexOs pool path = do
|
||||||
|
hash <- hashFile @_ @SHA256 path
|
||||||
|
let hashText = decodeUtf8 $ convertToBase Base16 hash
|
||||||
|
let vText = takeFileName (takeDirectory path)
|
||||||
|
let eVersion = parseOnly parseVersion . T.pack $ vText
|
||||||
|
case eVersion of
|
||||||
|
Left e -> $logError [i|Invalid Version Number (#{vText}): #{e}|]
|
||||||
|
Right version ->
|
||||||
|
void $ flip runSqlPool pool $ upsert (EosHash version hashText) [EosHashHash =. hashText]
|
||||||
|
|
||||||
getManifest :: (MonadResource m, MonadReader r m, Has PkgRepo r)
|
getManifest :: (MonadResource m, MonadReader r m, Has PkgRepo r)
|
||||||
=> PkgId
|
=> PkgId
|
||||||
-> Version
|
-> Version
|
||||||
|
|||||||
@@ -21,11 +21,15 @@ import Data.Yaml ( decodeEither' )
|
|||||||
import Data.Yaml.Config
|
import Data.Yaml.Config
|
||||||
import Database.Persist.Postgresql ( PostgresConf )
|
import Database.Persist.Postgresql ( PostgresConf )
|
||||||
import Network.Wai.Handler.Warp ( HostPreference )
|
import Network.Wai.Handler.Warp ( HostPreference )
|
||||||
import System.FilePath ( (</>) )
|
import System.FilePath ( (</>)
|
||||||
|
, takeDirectory
|
||||||
|
)
|
||||||
import Yesod.Default.Config2 ( configSettingsYml )
|
import Yesod.Default.Config2 ( configSettingsYml )
|
||||||
|
|
||||||
import Control.Monad.Reader.Has ( Has(extract, update) )
|
import Control.Monad.Reader.Has ( Has(extract, update) )
|
||||||
import Lib.PkgRepository ( PkgRepo(..) )
|
import Lib.PkgRepository ( EosRepo(EosRepo, eosRepoFileRoot)
|
||||||
|
, PkgRepo(..)
|
||||||
|
)
|
||||||
import Lib.Types.Emver
|
import Lib.Types.Emver
|
||||||
import Orphans.Emver ( )
|
import Orphans.Emver ( )
|
||||||
-- | Runtime settings to configure this application. These settings can be
|
-- | Runtime settings to configure this application. These settings can be
|
||||||
@@ -62,6 +66,12 @@ instance Has PkgRepo AppSettings where
|
|||||||
extract = liftA2 PkgRepo ((</> "apps") . resourcesDir) staticBinDir
|
extract = liftA2 PkgRepo ((</> "apps") . resourcesDir) staticBinDir
|
||||||
update f r =
|
update f r =
|
||||||
let repo = f $ extract r in r { resourcesDir = pkgRepoFileRoot repo, staticBinDir = pkgRepoAppMgrBin repo }
|
let repo = f $ extract r in r { resourcesDir = pkgRepoFileRoot repo, staticBinDir = pkgRepoAppMgrBin repo }
|
||||||
|
instance Has EosRepo AppSettings where
|
||||||
|
extract = EosRepo . (</> "eos") . resourcesDir
|
||||||
|
update f ctx =
|
||||||
|
let repo = f $ extract ctx
|
||||||
|
settings = ctx { resourcesDir = takeDirectory (eosRepoFileRoot repo) }
|
||||||
|
in settings
|
||||||
|
|
||||||
|
|
||||||
instance FromJSON AppSettings where
|
instance FromJSON AppSettings where
|
||||||
|
|||||||
Reference in New Issue
Block a user