mirror of
https://github.com/Start9Labs/registry.git
synced 2026-03-30 19:54:47 +00:00
adds icons endpoint
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
/sys/version/appmgr VersionAppMgrR GET --get most recent appmgr version
|
/sys/version/appmgr VersionAppMgrR GET --get most recent appmgr version
|
||||||
/sys/version/torrc VersionTorrcR GET --get most recent torrc version
|
/sys/version/torrc VersionTorrcR GET --get most recent torrc version
|
||||||
|
|
||||||
|
/icons/#PNG IconsR GET -- get icons
|
||||||
!/apps/#S9PK AppR GET --get most recent appId at appversion spec, defaults to >=0.0.0 -- ?spec={semver-spec}
|
!/apps/#S9PK AppR GET --get most recent appId at appversion spec, defaults to >=0.0.0 -- ?spec={semver-spec}
|
||||||
/sys/agent AgentR GET --get most recent agent at appversion -- ?spec={semver-spec}
|
/sys/agent AgentR GET --get most recent agent at appversion -- ?spec={semver-spec}
|
||||||
/sys/appmgr AppMgrR GET --get most recent appmgr at appversion -- ?spec={semver-spec}
|
/sys/appmgr AppMgrR GET --get most recent appmgr at appversion -- ?spec={semver-spec}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ dependencies:
|
|||||||
- process
|
- process
|
||||||
- protolude
|
- protolude
|
||||||
- safe
|
- safe
|
||||||
|
- singletons
|
||||||
- split
|
- split
|
||||||
- template-haskell
|
- template-haskell
|
||||||
- text >=0.11 && <2.0
|
- text >=0.11 && <2.0
|
||||||
|
|||||||
0
resources/icons/bitcoind.png
Normal file
0
resources/icons/bitcoind.png
Normal file
0
resources/sys/agent/0.0.0/agent
Normal file
0
resources/sys/agent/0.0.0/agent
Normal file
@@ -51,6 +51,7 @@ import Yesod.Persist.Core
|
|||||||
-- Don't forget to add new modules to your cabal file!
|
-- Don't forget to add new modules to your cabal file!
|
||||||
import Foundation
|
import Foundation
|
||||||
import Handler.Apps
|
import Handler.Apps
|
||||||
|
import Handler.Icons
|
||||||
import Handler.Version
|
import Handler.Version
|
||||||
import Lib.Ssl
|
import Lib.Ssl
|
||||||
import Model
|
import Model
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ sslPath :: FilePath
|
|||||||
sslPath = "/var/ssl"
|
sslPath = "/var/ssl"
|
||||||
|
|
||||||
resourcesPath :: FilePath
|
resourcesPath :: FilePath
|
||||||
resourcesPath = "/var/www/html/resources"
|
resourcesPath = "./resources" -- "/var/www/html/resources"
|
||||||
|
|
||||||
registryVersion :: AppVersion
|
registryVersion :: AppVersion
|
||||||
registryVersion = fromJust . parseMaybe parseJSON . String . toS . showVersion $ version
|
registryVersion = fromJust . parseMaybe parseJSON . String . toS . showVersion $ version
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import Settings
|
|||||||
-- starts running, such as database connections. Every handler will have
|
-- starts running, such as database connections. Every handler will have
|
||||||
-- access to the data present here.
|
-- access to the data present here.
|
||||||
|
|
||||||
|
|
||||||
data AgentCtx = AgentCtx
|
data AgentCtx = AgentCtx
|
||||||
{ appSettings :: AppSettings
|
{ appSettings :: AppSettings
|
||||||
, appConnPool :: ConnectionPool -- ^ Database connection pool.
|
, appConnPool :: ConnectionPool -- ^ Database connection pool.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
@@ -34,31 +35,29 @@ instance Show FileExtension where
|
|||||||
show (FileExtension f Nothing) = f
|
show (FileExtension f Nothing) = f
|
||||||
show (FileExtension f (Just e)) = f <.> e
|
show (FileExtension f (Just e)) = f <.> e
|
||||||
|
|
||||||
getImageR :: Handler TypedContent
|
|
||||||
getImageR = getApp sysResourceDir "image"
|
|
||||||
|
|
||||||
getAppsManifestR :: Handler TypedContent
|
getAppsManifestR :: Handler TypedContent
|
||||||
getAppsManifestR = respondSource typePlain $ CB.sourceFile appManifestPath .| awaitForever sendChunkBS
|
getAppsManifestR = respondSource typePlain $ CB.sourceFile appManifestPath .| awaitForever sendChunkBS
|
||||||
|
|
||||||
|
getImageR :: Handler TypedContent
|
||||||
|
getImageR = getApp sysResourceDir ("image" :: Extension "")
|
||||||
|
|
||||||
getAgentR :: Handler TypedContent
|
getAgentR :: Handler TypedContent
|
||||||
getAgentR = getApp sysResourceDir "agent"
|
getAgentR = getApp sysResourceDir ("agent" :: Extension "")
|
||||||
|
|
||||||
getAppMgrR :: Handler TypedContent
|
getAppMgrR :: Handler TypedContent
|
||||||
getAppMgrR = getApp sysResourceDir "appmgr"
|
getAppMgrR = getApp sysResourceDir ("appmgr" :: Extension "")
|
||||||
|
|
||||||
getTorrcR :: Handler TypedContent
|
getTorrcR :: Handler TypedContent
|
||||||
getTorrcR = getApp sysResourceDir "torrc"
|
getTorrcR = getApp sysResourceDir ("torrc" :: Extension "")
|
||||||
|
|
||||||
getAppR :: S9PK -> Handler TypedContent
|
getAppR :: Extension "s9pk" -> Handler TypedContent
|
||||||
getAppR (S9PK appId) = getApp appResourceDir appId
|
getAppR = getApp appResourceDir
|
||||||
|
|
||||||
getApp :: FilePath -> FilePath -> Handler TypedContent
|
getApp :: KnownSymbol a => FilePath -> Extension a -> Handler TypedContent
|
||||||
getApp rootDir appId = do
|
getApp rootDir ext = do
|
||||||
spec <- querySpecD mostRecentVersion <$> lookupGetParam "spec"
|
spec <- querySpecD mostRecentVersion <$> lookupGetParam "spec"
|
||||||
reg <- loadRegistry rootDir
|
appVersions <- liftIO $ getAvailableAppVersions rootDir ext
|
||||||
putStrLn ("got registry" :: String)
|
putStrLn $ "valid appversion for " <> (show ext :: String) <> ": " <> show appVersions
|
||||||
let appVersions = registeredAppVersions appId reg
|
|
||||||
putStrLn $ "valid appversion for " <> appId <> ": " <> show (fmap version appVersions)
|
|
||||||
case getSpecifiedAppVersion spec appVersions of
|
case getSpecifiedAppVersion spec appVersions of
|
||||||
Nothing -> notFound
|
Nothing -> notFound
|
||||||
Just (RegisteredAppVersion (_, filePath)) -> do
|
Just (RegisteredAppVersion (_, filePath)) -> do
|
||||||
|
|||||||
26
src/Handler/Icons.hs
Normal file
26
src/Handler/Icons.hs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE TypeApplications #-}
|
||||||
|
|
||||||
|
module Handler.Icons where
|
||||||
|
|
||||||
|
import Startlude
|
||||||
|
|
||||||
|
import Data.Conduit
|
||||||
|
import qualified Data.Conduit.Binary as CB
|
||||||
|
import System.Directory
|
||||||
|
import Yesod.Core
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Lib.Registry
|
||||||
|
|
||||||
|
getIconsR :: Extension "png" -> Handler TypedContent
|
||||||
|
getIconsR ext = do
|
||||||
|
mPng <- liftIO $ getUnversionedFileFromDir iconsResourceDir ext
|
||||||
|
case mPng of
|
||||||
|
Nothing -> notFound
|
||||||
|
Just pngPath -> do
|
||||||
|
putStrLn @Text $ show pngPath
|
||||||
|
exists <- liftIO $ doesFileExist pngPath
|
||||||
|
if exists
|
||||||
|
then respondSource typePlain $ CB.sourceFile pngPath .| awaitForever sendChunkBS
|
||||||
|
else notFound
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
module Handler.Version where
|
module Handler.Version where
|
||||||
|
|
||||||
@@ -16,19 +17,21 @@ getVersionR :: Handler AppVersionRes
|
|||||||
getVersionR = pure . AppVersionRes $ registryVersion
|
getVersionR = pure . AppVersionRes $ registryVersion
|
||||||
|
|
||||||
getVersionAppR :: Text -> Handler (Maybe AppVersionRes)
|
getVersionAppR :: Text -> Handler (Maybe AppVersionRes)
|
||||||
getVersionAppR = getVersionWSpec appResourceDir
|
getVersionAppR appId = getVersionWSpec appResourceDir appExt
|
||||||
|
where
|
||||||
|
appExt = Extension (toS appId) :: Extension "s9pk"
|
||||||
|
|
||||||
getVersionAgentR :: Handler (Maybe AppVersionRes)
|
getVersionAgentR :: Handler (Maybe AppVersionRes)
|
||||||
getVersionAgentR = getVersionWSpec sysResourceDir "agent"
|
getVersionAgentR = getVersionWSpec sysResourceDir ("agent" :: Extension "")
|
||||||
|
|
||||||
getVersionAppMgrR :: Handler (Maybe AppVersionRes)
|
getVersionAppMgrR :: Handler (Maybe AppVersionRes)
|
||||||
getVersionAppMgrR = getVersionWSpec sysResourceDir "appmgr"
|
getVersionAppMgrR = getVersionWSpec sysResourceDir ("appmgr" :: Extension "")
|
||||||
|
|
||||||
getVersionTorrcR :: Handler (Maybe AppVersionRes)
|
getVersionTorrcR :: Handler (Maybe AppVersionRes)
|
||||||
getVersionTorrcR = getVersionWSpec sysResourceDir "torrc"
|
getVersionTorrcR = getVersionWSpec sysResourceDir ("torrc" :: Extension "")
|
||||||
|
|
||||||
getVersionWSpec :: FilePath -> Text -> Handler (Maybe AppVersionRes)
|
getVersionWSpec :: KnownSymbol a => FilePath -> Extension a -> Handler (Maybe AppVersionRes)
|
||||||
getVersionWSpec rootDir appId = do
|
getVersionWSpec rootDir ext = do
|
||||||
spec <- querySpecD mostRecentVersion <$> lookupGetParam "spec"
|
spec <- querySpecD mostRecentVersion <$> lookupGetParam "spec"
|
||||||
appVersions <- registeredAppVersions (toS appId) <$> loadRegistry rootDir
|
appVersions <- liftIO $ getAvailableAppVersions rootDir ext
|
||||||
pure . fmap (AppVersionRes . version) $ getSpecifiedAppVersion spec appVersions
|
pure . fmap (AppVersionRes . version) $ getSpecifiedAppVersion spec appVersions
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE KindSignatures #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE TypeApplications #-}
|
||||||
|
|
||||||
module Lib.Registry where
|
module Lib.Registry where
|
||||||
|
|
||||||
import Startlude hiding (empty, toList)
|
import Startlude
|
||||||
|
|
||||||
import Data.HashMap.Lazy hiding (mapMaybe)
|
import Data.HashMap.Lazy hiding (mapMaybe)
|
||||||
import qualified GHC.Read (Read (..))
|
import qualified GHC.Read (Read (..))
|
||||||
@@ -14,22 +19,6 @@ import Data.Text (isSuffixOf)
|
|||||||
import Constants
|
import Constants
|
||||||
import Lib.Semver
|
import Lib.Semver
|
||||||
import Lib.Types.Semver
|
import Lib.Types.Semver
|
||||||
import Util.Function
|
|
||||||
|
|
||||||
newtype S9PK = S9PK String deriving (Eq)
|
|
||||||
instance Show S9PK where
|
|
||||||
show (S9PK t) = t <.> "s9pk"
|
|
||||||
|
|
||||||
instance Read S9PK where
|
|
||||||
readsPrec _ s = [(S9PK . take (m - n) $ s, "") | toS s9pk `isSuffixOf` toS s]
|
|
||||||
where
|
|
||||||
m = length s
|
|
||||||
s9pk = ".s9pk" :: String
|
|
||||||
n = length s9pk
|
|
||||||
|
|
||||||
instance PathPiece S9PK where
|
|
||||||
fromPathPiece = readMaybe . toS
|
|
||||||
toPathPiece = show
|
|
||||||
|
|
||||||
appResourceDir :: FilePath
|
appResourceDir :: FilePath
|
||||||
appResourceDir = resourcesPath </> "apps"
|
appResourceDir = resourcesPath </> "apps"
|
||||||
@@ -37,57 +26,65 @@ appResourceDir = resourcesPath </> "apps"
|
|||||||
sysResourceDir :: FilePath
|
sysResourceDir :: FilePath
|
||||||
sysResourceDir = resourcesPath </> "sys"
|
sysResourceDir = resourcesPath </> "sys"
|
||||||
|
|
||||||
|
iconsResourceDir :: FilePath
|
||||||
|
iconsResourceDir = resourcesPath </> "icons"
|
||||||
|
|
||||||
appManifestPath :: FilePath
|
appManifestPath :: FilePath
|
||||||
appManifestPath = appResourceDir </> appManifestFile
|
appManifestPath = appResourceDir </> appManifestFile
|
||||||
|
|
||||||
appManifestFile :: FilePath
|
appManifestFile :: FilePath
|
||||||
appManifestFile = "apps.yaml"
|
appManifestFile = "apps.yaml"
|
||||||
|
|
||||||
s9pkExt :: String -> FilePath
|
|
||||||
s9pkExt = show . S9PK
|
|
||||||
|
|
||||||
type Registry = HashMap String (HashMap AppVersion FilePath)
|
type Registry = HashMap String (HashMap AppVersion FilePath)
|
||||||
|
|
||||||
newtype RegisteredAppVersion = RegisteredAppVersion (AppVersion, FilePath)
|
newtype RegisteredAppVersion = RegisteredAppVersion (AppVersion, FilePath) deriving (Eq, Show)
|
||||||
instance HasAppVersion RegisteredAppVersion where
|
instance HasAppVersion RegisteredAppVersion where
|
||||||
version (RegisteredAppVersion (av, _)) = av
|
version (RegisteredAppVersion (av, _)) = av
|
||||||
|
|
||||||
loadAppRegistry :: MonadIO m => m Registry
|
getAvailableAppVersions :: KnownSymbol a => FilePath -> Extension a -> IO [RegisteredAppVersion]
|
||||||
loadAppRegistry = loadRegistry appResourceDir
|
getAvailableAppVersions rootDirectory ext@(Extension appId) = do
|
||||||
|
versions <- mapMaybe readMaybe <$> getSubDirectories (rootDirectory </> appId)
|
||||||
loadSysRegistry :: MonadIO m => m Registry
|
fmap catMaybes . for versions $ \v ->
|
||||||
loadSysRegistry = loadRegistry sysResourceDir
|
getVersionedFileFromDir rootDirectory ext v
|
||||||
|
>>= \case
|
||||||
loadRegistry :: MonadIO m => FilePath -> m Registry
|
Nothing -> pure Nothing
|
||||||
loadRegistry rootDirectory = liftIO $ do
|
Just appFile -> pure . Just $ RegisteredAppVersion (v, appFile)
|
||||||
appDirectories <- getSubDirectories rootDirectory
|
|
||||||
putStrLn $ "got appDirectories for " <> rootDirectory <> ": " <> show appDirectories
|
|
||||||
foldM
|
|
||||||
( \registry appId -> do
|
|
||||||
subdirs <- getSubDirectories (rootDirectory </> appId)
|
|
||||||
putStrLn $ "got appDirectories for " <> (rootDirectory </> appId) <> ": " <> show subdirs
|
|
||||||
let validVersions = mapMaybe readMaybe subdirs
|
|
||||||
versionApps <- for validVersions $ \v ->
|
|
||||||
getAppFileFromDir rootDirectory appId v
|
|
||||||
>>= \case
|
|
||||||
Nothing -> pure Nothing
|
|
||||||
Just appFile -> pure . Just $ (v, rootDirectory </> appId </> show v </> appFile)
|
|
||||||
pure $ insert appId (fromList . catMaybes $ versionApps) registry
|
|
||||||
) empty appDirectories
|
|
||||||
where
|
where
|
||||||
getSubDirectories path = listDirectory path >>= filterM (doesDirectoryExist . (path </>))
|
getSubDirectories path = (fmap (fromRight []) . try @SomeException $ listDirectory path) >>= filterM (doesDirectoryExist . (path </>))
|
||||||
|
|
||||||
|
-- /root/appId/version/appId.ext
|
||||||
|
getVersionedFileFromDir :: KnownSymbol a => FilePath -> Extension a -> AppVersion -> IO (Maybe FilePath)
|
||||||
|
getVersionedFileFromDir rootDirectory ext@(Extension appId) v = getUnversionedFileFromDir (rootDirectory </> appId </> show v) ext
|
||||||
|
|
||||||
getAppFileFromDir :: String -> String -> AppVersion -> IO (Maybe FilePath)
|
-- /root/appId.ext
|
||||||
getAppFileFromDir rootDirectory appId v = do
|
getUnversionedFileFromDir :: KnownSymbol a => FilePath -> Extension a -> IO (Maybe FilePath)
|
||||||
dirContents <- listDirectory (rootDirectory </> appId </> show v)
|
getUnversionedFileFromDir rootDirectory appExt = fmap (join . hush) . try @SomeException $ do
|
||||||
pure $ find (isPrefixOf appId) dirContents
|
dirContents <- listDirectory rootDirectory
|
||||||
|
pure . fmap (rootDirectory </>) $ find (== show appExt) dirContents
|
||||||
|
|
||||||
getAppFile :: String -> Registry -> AppVersion -> Maybe FilePath
|
newtype Extension (a :: Symbol) = Extension String deriving (Eq)
|
||||||
getAppFile appId r av = lookup av <=< lookup appId $ r
|
type S9PK = Extension "s9pk"
|
||||||
|
type PNG = Extension "png"
|
||||||
|
|
||||||
registeredAppVersions :: String -> Registry -> [RegisteredAppVersion]
|
instance IsString (Extension a) where
|
||||||
registeredAppVersions appId r = maybe [] (fmap RegisteredAppVersion . toList) (lookup appId r)
|
fromString = Extension
|
||||||
|
|
||||||
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
|
def :: Extension a
|
||||||
findM = fmap headMay .* filterM
|
def = Extension ""
|
||||||
|
|
||||||
|
extension :: KnownSymbol a => Extension a -> String
|
||||||
|
extension = symbolVal
|
||||||
|
|
||||||
|
instance KnownSymbol a => Show (Extension a) where
|
||||||
|
show e@(Extension file) = file <.> extension e
|
||||||
|
|
||||||
|
instance KnownSymbol a => Read (Extension a) where
|
||||||
|
readsPrec _ s = [(Extension . take (m - n - 1) $ s, "") | toS ext' `isSuffixOf` toS s]
|
||||||
|
where
|
||||||
|
m = length s
|
||||||
|
ext' = extension (def :: Extension a)
|
||||||
|
n = length ext'
|
||||||
|
|
||||||
|
instance KnownSymbol a => PathPiece (Extension a) where
|
||||||
|
fromPathPiece = readMaybe . toS
|
||||||
|
toPathPiece = show
|
||||||
|
|||||||
Reference in New Issue
Block a user