mirror of
https://github.com/Start9Labs/registry.git
synced 2026-03-26 02:11:53 +00:00
scaffolding ready for s9pks
This commit is contained in:
9
apps.yaml
Normal file
9
apps.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
bitcoind:
|
||||||
|
title: "Bitcoin Core"
|
||||||
|
description:
|
||||||
|
short: "A Bitcoin Full Node"
|
||||||
|
long: "The bitcoin full node implementation by Bitcoin Core."
|
||||||
|
version-info:
|
||||||
|
- version: 0.18.1
|
||||||
|
release-notes: "Some stuff"
|
||||||
|
icon-type: png
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
--authed
|
--authed
|
||||||
/version VersionR GET
|
/version/#AppVersion VersionR GET
|
||||||
|
-- /apps AppsManifestR GET --get current apps listing
|
||||||
|
-- /apps/#Text/#AppVersion AppR GET --install new app
|
||||||
|
-- /sys/agent/#AppVersion AgentR GET --install new agent version
|
||||||
|
-- /sys/appmgr/#AppVersion AppMgrR GET --install new appmgr version
|
||||||
|
|
||||||
-- /v0/authorizedKeys AuthorizeKeyR POST
|
-- /v0/authorizedKeys AuthorizeKeyR POST
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ import Data.Aeson
|
|||||||
import Data.Aeson.Types
|
import Data.Aeson.Types
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Version (showVersion)
|
import Data.Version (showVersion)
|
||||||
import Lib.Types.ServerApp
|
import Lib.Types.Semver
|
||||||
import Paths_start9_registry (version)
|
import Paths_start9_registry (version)
|
||||||
import Startlude
|
import Startlude
|
||||||
|
|
||||||
configBasePath :: FilePath
|
configPath :: FilePath
|
||||||
configBasePath = "./config"
|
configPath = "./config"
|
||||||
|
|
||||||
|
resourcesPath :: FilePath
|
||||||
|
resourcesPath = "./resources"
|
||||||
|
|
||||||
registryVersion :: AppVersion
|
registryVersion :: AppVersion
|
||||||
registryVersion = fromJust . parseMaybe parseJSON . String . toS . showVersion $ version
|
registryVersion = fromJust . parseMaybe parseJSON . String . toS . showVersion $ version
|
||||||
|
|
||||||
getRegistryHostname :: IsString a => a
|
getRegistryHostname :: IsString a => a
|
||||||
getRegistryHostname = "registry"
|
getRegistryHostname = "registry.start9labs.com"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import Startlude
|
|||||||
import Control.Monad.Logger (LogSource)
|
import Control.Monad.Logger (LogSource)
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import Database.Persist.Sql
|
import Database.Persist.Sql
|
||||||
|
import Lib.Types.Semver
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.Core.Types (Logger)
|
import Yesod.Core.Types (Logger)
|
||||||
import qualified Yesod.Core.Unsafe as Unsafe
|
import qualified Yesod.Core.Unsafe as Unsafe
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Startlude
|
|||||||
import Constants
|
import Constants
|
||||||
import Foundation
|
import Foundation
|
||||||
import Handler.Types.Status
|
import Handler.Types.Status
|
||||||
|
import Lib.Types.Semver
|
||||||
|
|
||||||
getVersionR :: Handler AppVersionRes
|
getVersionR :: AppVersion -> Handler AppVersionRes
|
||||||
getVersionR = pure . AppVersionRes $ registryVersion
|
getVersionR = pure . AppVersionRes -- $ registryVersion
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Data.Aeson
|
|||||||
import Data.Time.ISO8601
|
import Data.Time.ISO8601
|
||||||
import Yesod.Core.Content
|
import Yesod.Core.Content
|
||||||
|
|
||||||
|
import Lib.Types.Semver
|
||||||
import Lib.Types.ServerApp
|
import Lib.Types.ServerApp
|
||||||
|
|
||||||
newtype AvailableAppsRes = AvailableAppsRes
|
newtype AvailableAppsRes = AvailableAppsRes
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import Data.Text
|
|||||||
import Yesod.Core.Content
|
import Yesod.Core.Content
|
||||||
|
|
||||||
import Lib.Types.ServerApp
|
import Lib.Types.ServerApp
|
||||||
|
import Lib.Types.Semver
|
||||||
|
|
||||||
data ServerRes = ServerRes
|
data ServerRes = ServerRes
|
||||||
{ serverStatus :: AppStatus
|
{ serverStatus :: AppStatus
|
||||||
|
|||||||
45
src/Lib/Semver.hs
Normal file
45
src/Lib/Semver.hs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
module Lib.Semver where
|
||||||
|
|
||||||
|
import Startlude
|
||||||
|
|
||||||
|
import Lib.Types.Semver
|
||||||
|
|
||||||
|
(<||) :: HasAppVersion a => a -> AppVersionSpecification -> Bool
|
||||||
|
(<||) a (AppVersionSpecification SVEquals av1) = version a == av1
|
||||||
|
(<||) a (AppVersionSpecification SVLessThan av1) = version a < av1
|
||||||
|
(<||) a (AppVersionSpecification SVGreaterThan av1) = version a > av1
|
||||||
|
(<||) a (AppVersionSpecification SVLessThanEq av1) = version a <= av1
|
||||||
|
(<||) a (AppVersionSpecification SVGreaterThanEq av1) = version a >= av1
|
||||||
|
(<||) a (AppVersionSpecification SVGreatestWithMajor av1)
|
||||||
|
= major av == major av1 && av >= av1
|
||||||
|
where
|
||||||
|
av = version a
|
||||||
|
(<||) a (AppVersionSpecification SVGreatestWithMajorMinor av1)
|
||||||
|
= major av == major av1 && minor av == minor av1 && av >= av1
|
||||||
|
where
|
||||||
|
av = version a
|
||||||
|
|
||||||
|
major :: AppVersion -> Word16
|
||||||
|
major (AppVersion (a, _, _)) = a
|
||||||
|
minor :: AppVersion -> Word16
|
||||||
|
minor (AppVersion (_, a, _)) = a
|
||||||
|
patch :: AppVersion -> Word16
|
||||||
|
patch (AppVersion (_, _, a)) = a
|
||||||
|
|
||||||
|
hasGiven :: (AppVersion -> Word16) -> AppVersion -> AppVersion -> Bool
|
||||||
|
hasGiven projection av = (== projection av) . projection
|
||||||
|
|
||||||
|
getSpecifiedAppVersion :: HasAppVersion a => AppVersionSpecification -> [a] -> Maybe a
|
||||||
|
getSpecifiedAppVersion avSpec = appVersionMax . filter (<|| avSpec) -- get the largest thing satisfying the spec.
|
||||||
|
|
||||||
|
class HasAppVersion a where
|
||||||
|
version :: a -> AppVersion
|
||||||
|
|
||||||
|
instance HasAppVersion AppVersion where
|
||||||
|
version = id
|
||||||
|
|
||||||
|
appVersionMax :: HasAppVersion a => [a] -> Maybe a
|
||||||
|
appVersionMax [] = Nothing
|
||||||
|
appVersionMax as = Just $ maximumBy (\a1 a2 -> version a1 `compare` version a2) as
|
||||||
|
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ import Constants
|
|||||||
-- openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem
|
-- openssl x509 -req -in certificate.csr -signkey key.pem -out certificate.pem
|
||||||
|
|
||||||
sslBaseLocation :: FilePath
|
sslBaseLocation :: FilePath
|
||||||
sslBaseLocation = configBasePath </> "ssl"
|
sslBaseLocation = configPath </> "ssl"
|
||||||
|
|
||||||
sslKeyLocation :: FilePath
|
sslKeyLocation :: FilePath
|
||||||
sslKeyLocation = sslBaseLocation </> "key.pem"
|
sslKeyLocation = sslBaseLocation </> "key.pem"
|
||||||
|
|||||||
90
src/Lib/Types/Semver.hs
Normal file
90
src/Lib/Types/Semver.hs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
module Lib.Types.Semver where
|
||||||
|
|
||||||
|
import Startlude hiding (break)
|
||||||
|
|
||||||
|
import qualified GHC.Read (Read (..))
|
||||||
|
import qualified GHC.Show (Show (..))
|
||||||
|
|
||||||
|
import Control.Monad.Fail
|
||||||
|
import Data.Aeson
|
||||||
|
import Data.Char (isDigit)
|
||||||
|
import Data.String.Interpolate
|
||||||
|
import Data.Text
|
||||||
|
import Yesod.Core
|
||||||
|
|
||||||
|
newtype AppVersion = AppVersion
|
||||||
|
{ unAppVersion :: (Word16, Word16, Word16) } deriving (Eq, Ord)
|
||||||
|
|
||||||
|
instance Read AppVersion where
|
||||||
|
readsPrec _ s = case traverse (readMaybe . toS) $ split (=='.') (toS s) of
|
||||||
|
Just [major, minor, patch] -> [(AppVersion (major, minor, patch), "")]
|
||||||
|
_ -> []
|
||||||
|
instance PathPiece AppVersion where
|
||||||
|
fromPathPiece = readMaybe . toS
|
||||||
|
toPathPiece = show
|
||||||
|
|
||||||
|
instance Show AppVersion where
|
||||||
|
show (AppVersion (a, b, c)) = [i|#{a}.#{b}.#{c}|]
|
||||||
|
instance IsString AppVersion where
|
||||||
|
fromString s = case traverse (readMaybe . toS) $ split (=='.') (toS s) of
|
||||||
|
Just [major, minor, patch] -> AppVersion (major, minor, patch)
|
||||||
|
_ -> panic . toS $ "Invalid App Version: " <> s
|
||||||
|
instance ToJSON AppVersion where
|
||||||
|
toJSON av = String . toS $ let (a,b,c) = unAppVersion av in [i|#{a}.#{b}.#{c}|]
|
||||||
|
instance FromJSON AppVersion where
|
||||||
|
parseJSON = withText "app version" $ \t ->
|
||||||
|
case splitOn "." t of
|
||||||
|
[a, b, c] ->
|
||||||
|
case traverse (decode . toS) [a, b, c] of
|
||||||
|
Just [a', b', c'] -> pure $ AppVersion (a', b', c')
|
||||||
|
_ -> fail "non word16 versioning"
|
||||||
|
_ -> fail "unknown versioning"
|
||||||
|
instance ToTypedContent AppVersion where
|
||||||
|
toTypedContent = toTypedContent . toJSON
|
||||||
|
instance ToContent AppVersion where
|
||||||
|
toContent = toContent . toJSON
|
||||||
|
|
||||||
|
(\\) :: AppVersion -> AppVersion -> (Word16, Word16, Word16)
|
||||||
|
(\\) (AppVersion (a, b, c)) (AppVersion (a1, b1, c1)) = (a `diffy` a1, b `diffy` b1, c `diffy` c1)
|
||||||
|
where
|
||||||
|
d `diffy` d1 = fromIntegral . abs $ (fromIntegral d :: Integer) - (fromIntegral d1 :: Integer)
|
||||||
|
|
||||||
|
data AppVersionSpecification = AppVersionSpecification
|
||||||
|
{ requestModifier :: SemverRequestModifier
|
||||||
|
, baseVersion :: AppVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Show AppVersionSpecification where
|
||||||
|
show (AppVersionSpecification r b) = show r <> show b
|
||||||
|
instance ToJSON AppVersionSpecification where
|
||||||
|
toJSON = String . show
|
||||||
|
instance FromJSON AppVersionSpecification where
|
||||||
|
parseJSON = withText "app version spec" $ \t -> do
|
||||||
|
let (svMod, version) = break isDigit t
|
||||||
|
baseVersion <- parseJSON . String $ version
|
||||||
|
requestModifier <- parseJSON . String $ svMod
|
||||||
|
pure $ AppVersionSpecification {..}
|
||||||
|
|
||||||
|
data SemverRequestModifier = SVEquals | SVLessThan | SVGreaterThan | SVGreatestWithMajor | SVGreatestWithMajorMinor | SVLessThanEq | SVGreaterThanEq deriving (Eq, Bounded, Enum)
|
||||||
|
instance Show SemverRequestModifier where
|
||||||
|
show SVEquals = "="
|
||||||
|
show SVLessThan = "<"
|
||||||
|
show SVGreaterThan = ">"
|
||||||
|
show SVGreatestWithMajor = "~"
|
||||||
|
show SVGreatestWithMajorMinor = "^"
|
||||||
|
show SVLessThanEq = "<="
|
||||||
|
show SVGreaterThanEq = ">="
|
||||||
|
|
||||||
|
instance FromJSON SemverRequestModifier where
|
||||||
|
parseJSON = withText "semver request modifier" $ \case
|
||||||
|
"" -> pure SVGreatestWithMajorMinor
|
||||||
|
"=" -> pure SVEquals
|
||||||
|
"<" -> pure SVLessThan
|
||||||
|
">" -> pure SVGreaterThan
|
||||||
|
"~" -> pure SVGreatestWithMajor
|
||||||
|
"^" -> pure SVGreatestWithMajorMinor
|
||||||
|
"<=" -> pure SVLessThanEq
|
||||||
|
">=" -> pure SVGreaterThanEq
|
||||||
|
_ -> fail "invalid semver request modifier"
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
module Lib.Types.ServerApp where
|
module Lib.Types.ServerApp where
|
||||||
|
|
||||||
import Startlude hiding (break)
|
import Startlude
|
||||||
|
|
||||||
import qualified GHC.Show (Show (..))
|
|
||||||
|
|
||||||
import Control.Monad.Fail
|
import Control.Monad.Fail
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Char (isDigit)
|
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Text
|
import Data.Text
|
||||||
import Yesod.Core
|
|
||||||
|
import Lib.Types.Semver
|
||||||
|
|
||||||
data StoreApp = StoreApp
|
data StoreApp = StoreApp
|
||||||
{ storeAppId :: Text
|
{ storeAppId :: Text
|
||||||
@@ -44,83 +41,6 @@ data ServerApp = ServerApp
|
|||||||
, serverAppIsConfigured :: Bool
|
, serverAppIsConfigured :: Bool
|
||||||
} deriving (Eq, Show)
|
} deriving (Eq, Show)
|
||||||
|
|
||||||
data SemverRequestModifier = SVEquals | SVLessThan | SVGreaterThan | SVMinMinor | SVMinPatch | SVLessThanEq | SVGreaterThanEq deriving (Eq, Bounded, Enum)
|
|
||||||
instance Show SemverRequestModifier where
|
|
||||||
show SVEquals = "="
|
|
||||||
show SVLessThan = "<"
|
|
||||||
show SVGreaterThan = ">"
|
|
||||||
show SVMinMinor = "~"
|
|
||||||
show SVMinPatch = "^"
|
|
||||||
show SVLessThanEq = "<="
|
|
||||||
show SVGreaterThanEq = ">="
|
|
||||||
|
|
||||||
instance FromJSON SemverRequestModifier where
|
|
||||||
parseJSON = withText "semver request modifier" $ \case
|
|
||||||
"" -> pure SVMinPatch
|
|
||||||
"=" -> pure SVEquals
|
|
||||||
"<" -> pure SVLessThan
|
|
||||||
">" -> pure SVGreaterThan
|
|
||||||
"~" -> pure SVMinMinor
|
|
||||||
"^" -> pure SVMinPatch
|
|
||||||
"<=" -> pure SVLessThanEq
|
|
||||||
">=" -> pure SVGreaterThanEq
|
|
||||||
_ -> fail "invalid semver request modifier"
|
|
||||||
|
|
||||||
data AppVersionSpecification = AppVersionSpecification
|
|
||||||
{ requestModifier :: SemverRequestModifier
|
|
||||||
, baseVersion :: AppVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
instance Show AppVersionSpecification where
|
|
||||||
show (AppVersionSpecification r b) = show r <> show b
|
|
||||||
instance ToJSON AppVersionSpecification where
|
|
||||||
toJSON = String . show
|
|
||||||
instance FromJSON AppVersionSpecification where
|
|
||||||
parseJSON = withText "app version spec" $ \t -> do
|
|
||||||
let (svMod, version) = break isDigit t
|
|
||||||
baseVersion <- parseJSON . String $ version
|
|
||||||
requestModifier <- parseJSON . String $ svMod
|
|
||||||
pure $ AppVersionSpecification {..}
|
|
||||||
|
|
||||||
(<||) :: AppVersion -> AppVersionSpecification -> Bool
|
|
||||||
(<||) av (AppVersionSpecification SVEquals av1) = av == av1
|
|
||||||
(<||) av (AppVersionSpecification SVLessThan av1) = av < av1
|
|
||||||
(<||) av (AppVersionSpecification SVGreaterThan av1) = av > av1
|
|
||||||
(<||) av (AppVersionSpecification SVLessThanEq av1) = av <= av1
|
|
||||||
(<||) av (AppVersionSpecification SVGreaterThanEq av1) = av >= av1
|
|
||||||
(<||) (AppVersion (a,b,_)) (AppVersionSpecification SVMinMinor (AppVersion (a1, b1, _)))
|
|
||||||
= a == a1 && b >= b1
|
|
||||||
(<||) (AppVersion (a,b,c)) (AppVersionSpecification SVMinPatch (AppVersion (a1, b1, c1)))
|
|
||||||
= a == a1 && b == b1 && c >= c1
|
|
||||||
|
|
||||||
|
|
||||||
newtype AppVersion = AppVersion
|
|
||||||
{ unAppVersion :: (Word16, Word16, Word16) } deriving (Eq, Ord)
|
|
||||||
instance Show AppVersion where
|
|
||||||
show (AppVersion (a, b, c)) = [i|#{a}.#{b}.#{c}|]
|
|
||||||
instance IsString AppVersion where
|
|
||||||
fromString s = case traverse (readMaybe . toS) $ split (=='.') (toS s) of
|
|
||||||
Just [major, minor, patch] -> AppVersion (major, minor, patch)
|
|
||||||
_ -> panic . toS $ "Invalid App Version: " <> s
|
|
||||||
instance ToJSON AppVersion where
|
|
||||||
toJSON av = String . toS $ let (a,b,c) = unAppVersion av in [i|#{a}.#{b}.#{c}|]
|
|
||||||
instance FromJSON AppVersion where
|
|
||||||
parseJSON = withText "app version" $ \t ->
|
|
||||||
case splitOn "." t of
|
|
||||||
[a, b, c] ->
|
|
||||||
case traverse (decode . toS) [a, b, c] of
|
|
||||||
Just [a', b', c'] -> pure $ AppVersion (a', b', c')
|
|
||||||
_ -> fail "non word16 versioning"
|
|
||||||
_ -> fail "unknown versioning"
|
|
||||||
instance ToTypedContent AppVersion where
|
|
||||||
toTypedContent = toTypedContent . toJSON
|
|
||||||
instance ToContent AppVersion where
|
|
||||||
toContent = toContent . toJSON
|
|
||||||
|
|
||||||
(\\) :: AppVersion -> AppVersion -> (Word16, Word16, Word16)
|
|
||||||
(\\) (AppVersion (a, b, c)) (AppVersion (a1, b1, c1)) = (a `diffy` a1, b `diffy` b1, c `diffy` c1)
|
|
||||||
where
|
|
||||||
d `diffy` d1 = fromIntegral . abs $ (fromIntegral d :: Integer) - (fromIntegral d1 :: Integer)
|
|
||||||
|
|
||||||
data AppStatus = Running | Stopped | Restarting | Removing | Dead deriving (Eq, Show)
|
data AppStatus = Running | Stopped | Restarting | Removing | Dead deriving (Eq, Show)
|
||||||
instance ToJSON AppStatus where
|
instance ToJSON AppStatus where
|
||||||
|
|||||||
@@ -6,4 +6,18 @@ import Startlude
|
|||||||
(.*) = (.) . (.)
|
(.*) = (.) . (.)
|
||||||
|
|
||||||
(.**) :: (b -> c) -> (a0 -> a1 -> a2 -> b) -> a0 -> a1 -> a2 -> c
|
(.**) :: (b -> c) -> (a0 -> a1 -> a2 -> b) -> a0 -> a1 -> a2 -> c
|
||||||
(.**) = (.) . (.*)
|
(.**) = (.) . (.*)
|
||||||
|
|
||||||
|
preimage :: Eq b => (a -> b) -> b -> [a] -> [a]
|
||||||
|
preimage f target = filter ((== target) . f)
|
||||||
|
|
||||||
|
mapFind :: ([a] -> Maybe a) -> (b -> a) -> [b] -> Maybe b
|
||||||
|
mapFind _ _ [] = Nothing
|
||||||
|
mapFind finder mapping (b:bs) = let
|
||||||
|
mB = mapFind finder mapping bs
|
||||||
|
mA = finder [mapping b]
|
||||||
|
in case (mB, mA) of
|
||||||
|
(Just b',_) -> Just b'
|
||||||
|
(Nothing, Just _) -> Just b
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user