mirror of
https://github.com/Start9Labs/registry.git
synced 2026-03-30 11:51:57 +00:00
adds timings
This commit is contained in:
@@ -11,39 +11,39 @@
|
|||||||
{-# LANGUAGE DeriveAnyClass #-}
|
{-# LANGUAGE DeriveAnyClass #-}
|
||||||
|
|
||||||
module Handler.Marketplace where
|
module Handler.Marketplace where
|
||||||
import Startlude hiding ( from
|
import Data.Aeson
|
||||||
, Handler
|
import qualified Data.ByteString.Lazy as BS
|
||||||
|
import qualified Data.HashMap.Strict as HM
|
||||||
|
import Data.List
|
||||||
|
import qualified Data.List.NonEmpty as NE
|
||||||
|
import Data.Semigroup
|
||||||
|
import Data.String.Interpolate.IsString
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Database.Esqueleto.Experimental
|
||||||
|
import Database.Esqueleto.PostgreSQL ( arrayAggDistinct )
|
||||||
|
import Database.Marketplace
|
||||||
|
import qualified Database.Persist as P
|
||||||
|
import Foundation
|
||||||
|
import Lib.Error
|
||||||
|
import Lib.External.AppMgr
|
||||||
|
import Lib.Registry
|
||||||
|
import Lib.Types.AppIndex
|
||||||
|
import Lib.Types.AppIndex ( )
|
||||||
|
import Lib.Types.Category
|
||||||
|
import Lib.Types.Emver
|
||||||
|
import Model
|
||||||
|
import Network.HTTP.Types
|
||||||
|
import Settings
|
||||||
|
import Startlude hiding ( Handler
|
||||||
|
, from
|
||||||
, on
|
, on
|
||||||
, sortOn
|
, sortOn
|
||||||
)
|
)
|
||||||
import Foundation
|
|
||||||
import Yesod.Core
|
|
||||||
import qualified Database.Persist as P
|
|
||||||
import Model
|
|
||||||
import Yesod.Persist.Core
|
|
||||||
import Database.Marketplace
|
|
||||||
import Data.List
|
|
||||||
import Lib.Types.Category
|
|
||||||
import Lib.Types.AppIndex
|
|
||||||
import qualified Data.HashMap.Strict as HM
|
|
||||||
import Lib.Types.Emver
|
|
||||||
import qualified Data.List.NonEmpty as NE
|
|
||||||
import Database.Esqueleto.Experimental
|
|
||||||
import Lib.Error
|
|
||||||
import Network.HTTP.Types
|
|
||||||
import Lib.Registry
|
|
||||||
import Settings
|
|
||||||
import System.FilePath.Posix
|
import System.FilePath.Posix
|
||||||
import Lib.External.AppMgr
|
|
||||||
import Data.Aeson
|
|
||||||
import qualified Data.ByteString.Lazy as BS
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import Data.String.Interpolate.IsString
|
|
||||||
import Util.Shared
|
|
||||||
import Lib.Types.AppIndex ( )
|
|
||||||
import UnliftIO.Async
|
import UnliftIO.Async
|
||||||
import Database.Esqueleto.PostgreSQL ( arrayAggDistinct )
|
import Util.Shared
|
||||||
import Data.Semigroup
|
import Yesod.Core
|
||||||
|
import Yesod.Persist.Core
|
||||||
|
|
||||||
type URL = Text
|
type URL = Text
|
||||||
newtype CategoryRes = CategoryRes {
|
newtype CategoryRes = CategoryRes {
|
||||||
@@ -55,15 +55,16 @@ instance ToContent CategoryRes where
|
|||||||
toContent = toContent . toJSON
|
toContent = toContent . toJSON
|
||||||
instance ToTypedContent CategoryRes where
|
instance ToTypedContent CategoryRes where
|
||||||
toTypedContent = toTypedContent . toJSON
|
toTypedContent = toTypedContent . toJSON
|
||||||
data ServiceRes = ServiceRes
|
data ServiceRes = ServiceRes
|
||||||
{ serviceResIcon :: URL
|
{ serviceResIcon :: URL
|
||||||
, serviceResManifest :: Maybe Data.Aeson.Value -- ServiceManifest
|
, serviceResManifest :: Maybe Data.Aeson.Value -- ServiceManifest
|
||||||
, serviceResCategories :: [CategoryTitle]
|
, serviceResCategories :: [CategoryTitle]
|
||||||
, serviceResInstructions :: URL
|
, serviceResInstructions :: URL
|
||||||
, serviceResLicense :: URL
|
, serviceResLicense :: URL
|
||||||
, serviceResVersions :: [Version]
|
, serviceResVersions :: [Version]
|
||||||
, serviceResDependencyInfo :: HM.HashMap AppIdentifier DependencyInfo
|
, serviceResDependencyInfo :: HM.HashMap AppIdentifier DependencyInfo
|
||||||
} deriving (Generic)
|
}
|
||||||
|
deriving Generic
|
||||||
|
|
||||||
newtype ReleaseNotes = ReleaseNotes { unReleaseNotes :: HM.HashMap Version Text }
|
newtype ReleaseNotes = ReleaseNotes { unReleaseNotes :: HM.HashMap Version Text }
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
@@ -89,15 +90,17 @@ instance ToTypedContent ServiceRes where
|
|||||||
toTypedContent = toTypedContent . toJSON
|
toTypedContent = toTypedContent . toJSON
|
||||||
data DependencyInfo = DependencyInfo
|
data DependencyInfo = DependencyInfo
|
||||||
{ dependencyInfoTitle :: AppIdentifier
|
{ dependencyInfoTitle :: AppIdentifier
|
||||||
, dependencyInfoIcon :: URL
|
, dependencyInfoIcon :: URL
|
||||||
} deriving (Eq, Show)
|
}
|
||||||
|
deriving (Eq, Show)
|
||||||
instance ToJSON DependencyInfo where
|
instance ToJSON DependencyInfo where
|
||||||
toJSON DependencyInfo {..} = object ["icon" .= dependencyInfoIcon, "title" .= dependencyInfoTitle]
|
toJSON DependencyInfo {..} = object ["icon" .= dependencyInfoIcon, "title" .= dependencyInfoTitle]
|
||||||
|
|
||||||
data ServiceListRes = ServiceListRes {
|
data ServiceListRes = ServiceListRes
|
||||||
serviceListResCategories :: [CategoryTitle]
|
{ serviceListResCategories :: [CategoryTitle]
|
||||||
, serviceListResServices :: [ServiceAvailable]
|
, serviceListResServices :: [ServiceAvailable]
|
||||||
} deriving (Show)
|
}
|
||||||
|
deriving Show
|
||||||
instance ToJSON ServiceListRes where
|
instance ToJSON ServiceListRes where
|
||||||
toJSON ServiceListRes {..} =
|
toJSON ServiceListRes {..} =
|
||||||
object ["categories" .= serviceListResCategories, "services" .= serviceListResServices]
|
object ["categories" .= serviceListResCategories, "services" .= serviceListResServices]
|
||||||
@@ -107,12 +110,13 @@ instance ToTypedContent ServiceListRes where
|
|||||||
toTypedContent = toTypedContent . toJSON
|
toTypedContent = toTypedContent . toJSON
|
||||||
|
|
||||||
data ServiceAvailable = ServiceAvailable
|
data ServiceAvailable = ServiceAvailable
|
||||||
{ serviceAvailableId :: AppIdentifier
|
{ serviceAvailableId :: AppIdentifier
|
||||||
, serviceAvailableTitle :: Text
|
, serviceAvailableTitle :: Text
|
||||||
, serviceAvailableVersion :: Version
|
, serviceAvailableVersion :: Version
|
||||||
, serviceAvailableIcon :: URL
|
, serviceAvailableIcon :: URL
|
||||||
, serviceAvailableDescShort :: Text
|
, serviceAvailableDescShort :: Text
|
||||||
} deriving (Show)
|
}
|
||||||
|
deriving Show
|
||||||
instance ToJSON ServiceAvailable where
|
instance ToJSON ServiceAvailable where
|
||||||
toJSON ServiceAvailable {..} = object
|
toJSON ServiceAvailable {..} = object
|
||||||
[ "id" .= serviceAvailableId
|
[ "id" .= serviceAvailableId
|
||||||
@@ -144,18 +148,19 @@ instance ToTypedContent VersionLatestRes where
|
|||||||
data OrderArrangement = ASC | DESC
|
data OrderArrangement = ASC | DESC
|
||||||
deriving (Eq, Show, Read)
|
deriving (Eq, Show, Read)
|
||||||
data ServiceListDefaults = ServiceListDefaults
|
data ServiceListDefaults = ServiceListDefaults
|
||||||
{ serviceListOrder :: OrderArrangement
|
{ serviceListOrder :: OrderArrangement
|
||||||
, serviceListPageLimit :: Int64 -- the number of items per page
|
, serviceListPageLimit :: Int64 -- the number of items per page
|
||||||
, serviceListPageNumber :: Int64 -- the page you are on
|
, serviceListPageNumber :: Int64 -- the page you are on
|
||||||
, serviceListCategory :: Maybe CategoryTitle
|
, serviceListCategory :: Maybe CategoryTitle
|
||||||
, serviceListQuery :: Text
|
, serviceListQuery :: Text
|
||||||
}
|
}
|
||||||
deriving (Eq, Show, Read)
|
deriving (Eq, Show, Read)
|
||||||
data EosRes = EosRes
|
data EosRes = EosRes
|
||||||
{ eosResVersion :: Version
|
{ eosResVersion :: Version
|
||||||
, eosResHeadline :: Text
|
, eosResHeadline :: Text
|
||||||
, eosResReleaseNotes :: ReleaseNotes
|
, eosResReleaseNotes :: ReleaseNotes
|
||||||
} deriving (Eq, Show, Generic)
|
}
|
||||||
|
deriving (Eq, Show, Generic)
|
||||||
instance ToJSON EosRes where
|
instance ToJSON EosRes where
|
||||||
toJSON EosRes {..} =
|
toJSON EosRes {..} =
|
||||||
object ["version" .= eosResVersion, "headline" .= eosResHeadline, "release-notes" .= eosResReleaseNotes]
|
object ["version" .= eosResVersion, "headline" .= eosResHeadline, "release-notes" .= eosResReleaseNotes]
|
||||||
@@ -165,9 +170,10 @@ instance ToTypedContent EosRes where
|
|||||||
toTypedContent = toTypedContent . toJSON
|
toTypedContent = toTypedContent . toJSON
|
||||||
|
|
||||||
data PackageVersion = PackageVersion
|
data PackageVersion = PackageVersion
|
||||||
{ packageVersionId :: AppIdentifier
|
{ packageVersionId :: AppIdentifier
|
||||||
, packageVersionVersion :: VersionRange
|
, packageVersionVersion :: VersionRange
|
||||||
} deriving (Show)
|
}
|
||||||
|
deriving Show
|
||||||
instance FromJSON PackageVersion where
|
instance FromJSON PackageVersion where
|
||||||
parseJSON = withObject "package version" $ \o -> do
|
parseJSON = withObject "package version" $ \o -> do
|
||||||
packageVersionId <- o .: "id"
|
packageVersionId <- o .: "id"
|
||||||
@@ -207,8 +213,9 @@ getReleaseNotesR = do
|
|||||||
case lookup "id" getParameters of
|
case lookup "id" getParameters of
|
||||||
Nothing -> sendResponseStatus status400 ("expected query param \"id\" to exist" :: Text)
|
Nothing -> sendResponseStatus status400 ("expected query param \"id\" to exist" :: Text)
|
||||||
Just package -> do
|
Just package -> do
|
||||||
(service, _ ) <- runDB $ fetchLatestApp package >>= errOnNothing status404 "package not found"
|
(service, _) <- runDB $ fetchLatestApp (AppIdentifier package) >>= errOnNothing status404
|
||||||
(_ , mappedVersions) <- fetchAllAppVersions (entityKey service)
|
"package not found"
|
||||||
|
(_, mappedVersions) <- fetchAllAppVersions (entityKey service)
|
||||||
pure mappedVersions
|
pure mappedVersions
|
||||||
|
|
||||||
getVersionLatestR :: Handler VersionLatestRes
|
getVersionLatestR :: Handler VersionLatestRes
|
||||||
@@ -225,15 +232,20 @@ getVersionLatestR = do
|
|||||||
$ VersionLatestRes
|
$ VersionLatestRes
|
||||||
$ HM.union
|
$ HM.union
|
||||||
( HM.fromList
|
( HM.fromList
|
||||||
$ (\v ->
|
$ (\v -> (sAppAppId $ entityVal $ fst v, Just $ sVersionNumber $ entityVal $ snd v))
|
||||||
( sAppAppId $ entityVal $ fst v :: AppIdentifier
|
|
||||||
, Just $ sVersionNumber $ entityVal $ snd v
|
|
||||||
)
|
|
||||||
)
|
|
||||||
<$> catMaybes found
|
<$> catMaybes found
|
||||||
)
|
)
|
||||||
$ HM.fromList packageList
|
$ HM.fromList packageList
|
||||||
|
|
||||||
|
time :: MonadIO m => Text -> m a -> m a
|
||||||
|
time label m = do
|
||||||
|
start <- liftIO getCurrentTime
|
||||||
|
res <- m
|
||||||
|
end <- liftIO getCurrentTime
|
||||||
|
putStrLn $ label <> show (diffUTCTime end start)
|
||||||
|
pure res
|
||||||
|
|
||||||
|
|
||||||
getPackageListR :: Handler ServiceAvailableRes
|
getPackageListR :: Handler ServiceAvailableRes
|
||||||
getPackageListR = do
|
getPackageListR = do
|
||||||
getParameters <- reqGetParams <$> getRequest
|
getParameters <- reqGetParams <$> getRequest
|
||||||
@@ -267,14 +279,19 @@ getPackageListR = do
|
|||||||
Just c -> case readMaybe $ toS c of
|
Just c -> case readMaybe $ toS c of
|
||||||
Nothing -> sendResponseStatus status400 ("could not read per-page" :: Text)
|
Nothing -> sendResponseStatus status400 ("could not read per-page" :: Text)
|
||||||
Just l -> pure l
|
Just l -> pure l
|
||||||
query <- T.filter (not . isSpace) . fromMaybe (serviceListQuery defaults) <$> lookupGetParam "query"
|
query <- time "filter" $ T.filter (not . isSpace) . fromMaybe (serviceListQuery defaults) <$> lookupGetParam
|
||||||
filteredServices <- runDB $ searchServices category limit' ((page - 1) * limit') query
|
"query"
|
||||||
|
filteredServices <- time "search services" $ runDB $ searchServices category
|
||||||
|
limit'
|
||||||
|
((page - 1) * limit')
|
||||||
|
query
|
||||||
let filteredServices' = sAppAppId . entityVal <$> filteredServices
|
let filteredServices' = sAppAppId . entityVal <$> filteredServices
|
||||||
settings <- getsYesod appSettings
|
settings <- getsYesod appSettings
|
||||||
packageMetadata <- runDB $ fetchPackageMetadata filteredServices'
|
packageMetadata <- time "metadata" $ runDB $ fetchPackageMetadata filteredServices'
|
||||||
$logInfo $ show packageMetadata
|
$logInfo $ show packageMetadata
|
||||||
serviceDetailResult <- liftIO
|
serviceDetailResult <- time "service details" $ liftIO $ mapConcurrently
|
||||||
$ mapConcurrently (getServiceDetails settings packageMetadata Nothing) filteredServices'
|
(getServiceDetails settings packageMetadata Nothing)
|
||||||
|
filteredServices'
|
||||||
let (_, services) = partitionEithers serviceDetailResult
|
let (_, services) = partitionEithers serviceDetailResult
|
||||||
pure $ ServiceAvailableRes services
|
pure $ ServiceAvailableRes services
|
||||||
-- if null errors
|
-- if null errors
|
||||||
@@ -286,12 +303,15 @@ getPackageListR = do
|
|||||||
Right (packages :: [PackageVersion]) -> do
|
Right (packages :: [PackageVersion]) -> do
|
||||||
-- for each item in list get best available from version range
|
-- for each item in list get best available from version range
|
||||||
settings <- getsYesod appSettings
|
settings <- getsYesod appSettings
|
||||||
availableServicesResult <- liftIO $ mapConcurrently (getPackageDetails settings) packages
|
availableServicesResult <- time "availableServicesResult" $ liftIO $ mapConcurrently
|
||||||
|
(getPackageDetails settings)
|
||||||
|
packages
|
||||||
-- @TODO fix _ error
|
-- @TODO fix _ error
|
||||||
let (_, availableServices) = partitionEithers availableServicesResult
|
let (_, availableServices) = partitionEithers availableServicesResult
|
||||||
packageMetadata <- runDB $ fetchPackageMetadata (snd <$> availableServices)
|
packageMetadata <- time "metadata2" $ runDB $ fetchPackageMetadata (snd <$> availableServices)
|
||||||
serviceDetailResult <- liftIO
|
serviceDetailResult <- time "service details 2" $ liftIO $ mapConcurrently
|
||||||
$ mapConcurrently (uncurry $ getServiceDetails settings packageMetadata) availableServices
|
(uncurry $ getServiceDetails settings packageMetadata)
|
||||||
|
availableServices
|
||||||
-- @TODO fix _ error
|
-- @TODO fix _ error
|
||||||
let (_, services) = partitionEithers serviceDetailResult
|
let (_, services) = partitionEithers serviceDetailResult
|
||||||
pure $ ServiceAvailableRes services
|
pure $ ServiceAvailableRes services
|
||||||
@@ -304,6 +324,9 @@ getPackageListR = do
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
where
|
where
|
||||||
getPackageDetails :: (MonadIO m)
|
getPackageDetails :: (MonadIO m)
|
||||||
=> AppSettings
|
=> AppSettings
|
||||||
@@ -313,7 +336,7 @@ getPackageListR = do
|
|||||||
let appId = packageVersionId pv
|
let appId = packageVersionId pv
|
||||||
let spec = packageVersionVersion pv
|
let spec = packageVersionVersion pv
|
||||||
let appExt = Extension (show appId) :: Extension "s9pk"
|
let appExt = Extension (show appId) :: Extension "s9pk"
|
||||||
getBestVersion ((</> "apps") . resourcesDir $ settings) appExt spec >>= \case
|
time "best version" $ getBestVersion ((</> "apps") . resourcesDir $ settings) appExt spec >>= \case
|
||||||
Nothing ->
|
Nothing ->
|
||||||
pure
|
pure
|
||||||
$ Left
|
$ Left
|
||||||
@@ -442,7 +465,7 @@ fetchLatestApp appId = selectOne $ do
|
|||||||
pure (service, version)
|
pure (service, version)
|
||||||
|
|
||||||
fetchLatestAppAtVersion :: MonadIO m
|
fetchLatestAppAtVersion :: MonadIO m
|
||||||
=> Text
|
=> AppIdentifier
|
||||||
-> Version
|
-> Version
|
||||||
-> ReaderT SqlBackend m (Maybe (P.Entity SApp, P.Entity SVersion))
|
-> ReaderT SqlBackend m (Maybe (P.Entity SApp, P.Entity SVersion))
|
||||||
fetchLatestAppAtVersion appId version' = selectOne $ do
|
fetchLatestAppAtVersion appId version' = selectOne $ do
|
||||||
|
|||||||
Reference in New Issue
Block a user