cachix-api 0.6.0 → 0.7.0
raw patch · 13 files changed
+286/−132 lines, 13 filesdep +asyncdep +unordered-containersdep +uuidPVP ok
version bump matches the API change (PVP)
Dependencies added: async, unordered-containers, uuid, websockets
API changes (from Hackage documentation)
- Cachix.Types.NarInfo: instance Control.DeepSeq.NFData (Nix.NarInfo.Types.NarInfo Data.Text.Internal.Text Data.Text.Internal.Text Data.Text.Internal.Text)
- Cachix.Types.NarInfo: instance Data.Aeson.Types.FromJSON.FromJSON (Nix.NarInfo.Types.NarInfo Data.Text.Internal.Text Data.Text.Internal.Text Data.Text.Internal.Text)
- Cachix.Types.NarInfo: instance Data.Aeson.Types.ToJSON.ToJSON (Nix.NarInfo.Types.NarInfo Data.Text.Internal.Text Data.Text.Internal.Text Data.Text.Internal.Text)
- Cachix.Types.NarInfo: instance Data.Swagger.Internal.Schema.ToSchema (Nix.NarInfo.Types.NarInfo Data.Text.Internal.Text Data.Text.Internal.Text Data.Text.Internal.Text)
+ Cachix.API.Deploy: DeployAPI :: (route :- (CachixAuth :> ("deploy" :> ("activate" :> (ReqBody '[JSON] Deploy :> Post '[JSON] DeployResponse))))) -> DeployAPI route
+ Cachix.API.Deploy: [activate] :: DeployAPI route -> route :- (CachixAuth :> ("deploy" :> ("activate" :> (ReqBody '[JSON] Deploy :> Post '[JSON] DeployResponse))))
+ Cachix.API.Deploy: api :: Proxy API
+ Cachix.API.Deploy: data DeployAPI route
+ Cachix.API.Deploy: instance GHC.Generics.Generic (Cachix.API.Deploy.DeployAPI route)
+ Cachix.API.Deploy: type API = "api" :> "v1" :> ToServantApi DeployAPI
+ Cachix.API.WebSocketSubprotocol: AgentInformation :: Maybe Cache -> UUID -> AgentInformation
+ Cachix.API.WebSocketSubprotocol: AgentRegistered :: AgentInformation -> BackendCommand
+ Cachix.API.WebSocketSubprotocol: Cache :: Text -> Text -> Bool -> Cache
+ Cachix.API.WebSocketSubprotocol: Deployment :: DeploymentDetails -> BackendCommand
+ Cachix.API.WebSocketSubprotocol: DeploymentDetails :: Text -> UUID -> Int64 -> DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: DeploymentFinished :: UUID -> UTCTime -> Bool -> AgentCommand
+ Cachix.API.WebSocketSubprotocol: DeploymentStarted :: UUID -> UTCTime -> AgentCommand
+ Cachix.API.WebSocketSubprotocol: Log :: Text -> UTCTime -> Log
+ Cachix.API.WebSocketSubprotocol: Message :: Text -> cmd -> Maybe UUID -> UUID -> Message cmd
+ Cachix.API.WebSocketSubprotocol: [$sel:agent:Message] :: Message cmd -> Maybe UUID
+ Cachix.API.WebSocketSubprotocol: [$sel:cache:AgentInformation] :: AgentInformation -> Maybe Cache
+ Cachix.API.WebSocketSubprotocol: [$sel:cacheName:Cache] :: Cache -> Text
+ Cachix.API.WebSocketSubprotocol: [$sel:command:Message] :: Message cmd -> cmd
+ Cachix.API.WebSocketSubprotocol: [$sel:hasSucceeded:DeploymentStarted] :: AgentCommand -> Bool
+ Cachix.API.WebSocketSubprotocol: [$sel:id:AgentInformation] :: AgentInformation -> UUID
+ Cachix.API.WebSocketSubprotocol: [$sel:id:DeploymentDetails] :: DeploymentDetails -> UUID
+ Cachix.API.WebSocketSubprotocol: [$sel:id:DeploymentStarted] :: AgentCommand -> UUID
+ Cachix.API.WebSocketSubprotocol: [$sel:id:Message] :: Message cmd -> UUID
+ Cachix.API.WebSocketSubprotocol: [$sel:index:DeploymentDetails] :: DeploymentDetails -> Int64
+ Cachix.API.WebSocketSubprotocol: [$sel:isPublic:Cache] :: Cache -> Bool
+ Cachix.API.WebSocketSubprotocol: [$sel:line:Log] :: Log -> Text
+ Cachix.API.WebSocketSubprotocol: [$sel:method:Message] :: Message cmd -> Text
+ Cachix.API.WebSocketSubprotocol: [$sel:publicKey:Cache] :: Cache -> Text
+ Cachix.API.WebSocketSubprotocol: [$sel:storePath:DeploymentDetails] :: DeploymentDetails -> Text
+ Cachix.API.WebSocketSubprotocol: [$sel:time:DeploymentStarted] :: AgentCommand -> UTCTime
+ Cachix.API.WebSocketSubprotocol: [$sel:time:Log] :: Log -> UTCTime
+ Cachix.API.WebSocketSubprotocol: data AgentCommand
+ Cachix.API.WebSocketSubprotocol: data AgentInformation
+ Cachix.API.WebSocketSubprotocol: data BackendCommand
+ Cachix.API.WebSocketSubprotocol: data Cache
+ Cachix.API.WebSocketSubprotocol: data DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: data Log
+ Cachix.API.WebSocketSubprotocol: data Message cmd
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.API.WebSocketSubprotocol.AgentCommand
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.API.WebSocketSubprotocol.AgentInformation
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.API.WebSocketSubprotocol.BackendCommand
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.API.WebSocketSubprotocol.Cache
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.API.WebSocketSubprotocol.DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.API.WebSocketSubprotocol.Log
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.FromJSON.FromJSON cmd => Data.Aeson.Types.FromJSON.FromJSON (Cachix.API.WebSocketSubprotocol.Message cmd)
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.API.WebSocketSubprotocol.AgentCommand
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.API.WebSocketSubprotocol.AgentInformation
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.API.WebSocketSubprotocol.BackendCommand
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.API.WebSocketSubprotocol.Cache
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.API.WebSocketSubprotocol.DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.API.WebSocketSubprotocol.Log
+ Cachix.API.WebSocketSubprotocol: instance Data.Aeson.Types.ToJSON.ToJSON cmd => Data.Aeson.Types.ToJSON.ToJSON (Cachix.API.WebSocketSubprotocol.Message cmd)
+ Cachix.API.WebSocketSubprotocol: instance GHC.Classes.Eq Cachix.API.WebSocketSubprotocol.AgentCommand
+ Cachix.API.WebSocketSubprotocol: instance GHC.Classes.Eq Cachix.API.WebSocketSubprotocol.AgentInformation
+ Cachix.API.WebSocketSubprotocol: instance GHC.Classes.Eq Cachix.API.WebSocketSubprotocol.BackendCommand
+ Cachix.API.WebSocketSubprotocol: instance GHC.Classes.Eq Cachix.API.WebSocketSubprotocol.Cache
+ Cachix.API.WebSocketSubprotocol: instance GHC.Classes.Eq Cachix.API.WebSocketSubprotocol.DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: instance GHC.Classes.Eq cmd => GHC.Classes.Eq (Cachix.API.WebSocketSubprotocol.Message cmd)
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic (Cachix.API.WebSocketSubprotocol.Message cmd)
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic Cachix.API.WebSocketSubprotocol.AgentCommand
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic Cachix.API.WebSocketSubprotocol.AgentInformation
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic Cachix.API.WebSocketSubprotocol.BackendCommand
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic Cachix.API.WebSocketSubprotocol.Cache
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic Cachix.API.WebSocketSubprotocol.DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: instance GHC.Generics.Generic Cachix.API.WebSocketSubprotocol.Log
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show Cachix.API.WebSocketSubprotocol.AgentCommand
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show Cachix.API.WebSocketSubprotocol.AgentInformation
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show Cachix.API.WebSocketSubprotocol.BackendCommand
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show Cachix.API.WebSocketSubprotocol.Cache
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show Cachix.API.WebSocketSubprotocol.DeploymentDetails
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show Cachix.API.WebSocketSubprotocol.Log
+ Cachix.API.WebSocketSubprotocol: instance GHC.Show.Show cmd => GHC.Show.Show (Cachix.API.WebSocketSubprotocol.Message cmd)
+ Cachix.API.WebSocketSubprotocol: parseMessage :: FromJSON cmd => ByteString -> Either Text (Message cmd)
+ Cachix.API.WebSocketSubprotocol: recieveDataConcurrently :: Connection -> (ByteString -> IO ()) -> IO ()
+ Cachix.API.WebSocketSubprotocol: sendMessage :: ToJSON cmd => Connection -> Message cmd -> IO ()
+ Cachix.Types.ContentTypes: instance Servant.API.ContentTypes.MimeRender Servant.API.ContentTypes.PlainText Cachix.Types.ByteStringStreaming.ByteStringStreaming
+ Cachix.Types.ContentTypes: instance Servant.API.ContentTypes.MimeUnrender Servant.API.ContentTypes.PlainText Cachix.Types.ByteStringStreaming.ByteStringStreaming
+ Cachix.Types.Deploy: Deploy :: HashMap Text Text -> Deploy
+ Cachix.Types.Deploy: [agents] :: Deploy -> HashMap Text Text
+ Cachix.Types.Deploy: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.Types.Deploy.Deploy
+ Cachix.Types.Deploy: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.Types.Deploy.Deploy
+ Cachix.Types.Deploy: instance Data.Swagger.Internal.Schema.ToSchema Cachix.Types.Deploy.Deploy
+ Cachix.Types.Deploy: instance GHC.Generics.Generic Cachix.Types.Deploy.Deploy
+ Cachix.Types.Deploy: instance GHC.Show.Show Cachix.Types.Deploy.Deploy
+ Cachix.Types.Deploy: newtype Deploy
+ Cachix.Types.DeployResponse: DeployResponse :: HashMap Text Text -> DeployResponse
+ Cachix.Types.DeployResponse: [agents] :: DeployResponse -> HashMap Text Text
+ Cachix.Types.DeployResponse: instance Control.DeepSeq.NFData Cachix.Types.DeployResponse.DeployResponse
+ Cachix.Types.DeployResponse: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.Types.DeployResponse.DeployResponse
+ Cachix.Types.DeployResponse: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.Types.DeployResponse.DeployResponse
+ Cachix.Types.DeployResponse: instance Data.Swagger.Internal.Schema.ToSchema Cachix.Types.DeployResponse.DeployResponse
+ Cachix.Types.DeployResponse: instance GHC.Generics.Generic Cachix.Types.DeployResponse.DeployResponse
+ Cachix.Types.DeployResponse: instance GHC.Show.Show Cachix.Types.DeployResponse.DeployResponse
+ Cachix.Types.DeployResponse: newtype DeployResponse
+ Cachix.Types.NarInfo: instance Control.DeepSeq.NFData Cachix.Types.NarInfo.CachixNarInfo
+ Cachix.Types.NarInfo: instance Data.Aeson.Types.FromJSON.FromJSON Cachix.Types.NarInfo.CachixNarInfo
+ Cachix.Types.NarInfo: instance Data.Aeson.Types.ToJSON.ToJSON Cachix.Types.NarInfo.CachixNarInfo
+ Cachix.Types.NarInfo: instance Data.Swagger.Internal.Schema.ToSchema Cachix.Types.NarInfo.CachixNarInfo
- Cachix.API: BinaryCacheAPI :: (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("nix-cache-info" :> Get '[XNixCacheInfo, JSON] NixCacheInfo))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> Get '[XNixNarInfo, JSON] CachixNarInfo))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> Head))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("nar" :> (Capture "nar" NarFileName :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming (ResourceT IO) ()))))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> Get '[JSON] BinaryCache)))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("narinfo" :> (Summary "Given a list of store hashes, return a list of those that are missing" :> (ReqBody '[JSON] [Text] :> Post '[JSON] [Text]))))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("narurl" :> (Capture "nar" NarFileName :> Get '[JSON] Text)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> (ReqBody '[JSON] NarInfoCreate :> Post '[JSON] NoContent)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("nar" :> (StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming (ResourceT IO) ()) :> Post '[JSON] NoContent)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("serve" :> (Capture "storehash" Text :> (CaptureAll "filepath" Text :> (Summary "Serve a file from a given store path" :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text] LazyByteStringStreaming))))))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("key" :> (ReqBody '[JSON] SigningKeyCreate :> Post '[JSON] NoContent)))))) -> BinaryCacheAPI route
+ Cachix.API: BinaryCacheAPI :: (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("nix-cache-info" :> Get '[XNixCacheInfo, JSON] NixCacheInfo))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> Get '[XNixNarInfo, JSON] (Headers '[Header "Cache-Control" Text] CachixNarInfo)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> Head))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("nar" :> (Capture "nar" NarFileName :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming (ResourceT IO) ()))))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> Get '[JSON] BinaryCache)))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("narinfo" :> (Summary "Given a list of store hashes, return a list of those that are missing" :> (ReqBody '[JSON] [Text] :> Post '[JSON] [Text]))))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("narurl" :> (Capture "nar" NarFileName :> Get '[JSON] Text)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> (ReqBody '[JSON] NarInfoCreate :> Post '[JSON] NoContent)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("nar" :> (StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming (ResourceT IO) ()) :> Post '[JSON] NoContent)))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("serve" :> (Capture "storehash" Text :> (CaptureAll "filepath" Text :> (Summary "Serve a file from a given store path" :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text, Header "Cache-Control" Text] LazyByteStringStreaming))))))))) -> (route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("key" :> (ReqBody '[JSON] SigningKeyCreate :> Post '[JSON] NoContent)))))) -> BinaryCacheAPI route
- Cachix.API: [narinfo] :: BinaryCacheAPI route -> route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> Get '[XNixNarInfo, JSON] CachixNarInfo))))
+ Cachix.API: [narinfo] :: BinaryCacheAPI route -> route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> (Capture "narinfohash" NarInfoHash :> Get '[XNixNarInfo, JSON] (Headers '[Header "Cache-Control" Text] CachixNarInfo)))))
- Cachix.API: [serveNarContent] :: BinaryCacheAPI route -> route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("serve" :> (Capture "storehash" Text :> (CaptureAll "filepath" Text :> (Summary "Serve a file from a given store path" :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text] LazyByteStringStreaming))))))))
+ Cachix.API: [serveNarContent] :: BinaryCacheAPI route -> route :- (CachixAuth :> ("cache" :> (Capture "name" Text :> ("serve" :> (Capture "storehash" Text :> (CaptureAll "filepath" Text :> (Summary "Serve a file from a given store path" :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text, Header "Cache-Control" Text] LazyByteStringStreaming))))))))
Files
- CHANGELOG.md +4/−0
- cachix-api.cabal +9/−1
- src/Cachix/API.hs +92/−93
- src/Cachix/API/Deploy.hs +31/−0
- src/Cachix/API/WebSocketSubprotocol.hs +79/−0
- src/Cachix/Types/BinaryCache.hs +8/−9
- src/Cachix/Types/ContentTypes.hs +6/−0
- src/Cachix/Types/Deploy.hs +16/−0
- src/Cachix/Types/DeployResponse.hs +16/−0
- src/Cachix/Types/NarFileName.hs +4/−5
- src/Cachix/Types/NarInfoCreate.hs +13/−14
- src/Cachix/Types/NixCacheInfo.hs +5/−6
- src/Cachix/Types/SigningKeyCreate.hs +3/−4
CHANGELOG.md view
@@ -7,6 +7,10 @@ ## [Unreleased] +## [0.7.0] - 2022-01-12++- Support Cachix Deploy+ ## [0.6.0] - 2021-01-08 - Support latest stackage nightly
cachix-api.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: cachix-api-version: 0.6.0+version: 0.7.0 synopsis: Servant HTTP API specification for https://cachix.org homepage: https://github.com/cachix/cachix#readme bug-reports: https://github.com/cachix/cachix/issues@@ -38,11 +38,15 @@ import: defaults exposed-modules: Cachix.API+ Cachix.API.Deploy Cachix.API.Error Cachix.API.Signing+ Cachix.API.WebSocketSubprotocol Cachix.Types.BinaryCache Cachix.Types.ByteStringStreaming Cachix.Types.ContentTypes+ Cachix.Types.Deploy+ Cachix.Types.DeployResponse Cachix.Types.NarFileName Cachix.Types.NarInfo Cachix.Types.NarInfoCreate@@ -56,6 +60,7 @@ hs-source-dirs: src build-depends: , aeson+ , async , base >=4.7 && <5 , base16-bytestring , bytestring@@ -81,6 +86,9 @@ , text , time , transformers+ , unordered-containers+ , uuid+ , websockets test-suite cachix-api-test import: defaults
src/Cachix/API.hs view
@@ -31,99 +31,98 @@ type CachixAuth = Auth '[Cookie, JWT, BasicAuth] Session -- Nix CLI + Cachix CLI-data BinaryCacheAPI route- = BinaryCacheAPI- { -- https://cache.nixos.org/nix-cache-info- nixCacheInfo ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "nix-cache-info"- :> Get '[XNixCacheInfo, JSON] NixCacheInfo.NixCacheInfo,- -- Hydra: src/lib/Hydra/View/NARInfo.pm- narinfo ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> Capture "narinfohash" NarInfoHash.NarInfoHash- :> Get '[XNixNarInfo, JSON] NarInfo.CachixNarInfo,- narinfoHead ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> Capture "narinfohash" NarInfoHash.NarInfoHash- :> Head,- -- Hydra: src/lib/Hydra/View/NixNAR.pm- nar ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "nar"- :> Capture "nar" NarFileName- :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ()),- -- cachix specific- getCache ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> Get '[JSON] BinaryCache.BinaryCache,- narinfoBulk ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "narinfo"- :> Summary "Given a list of store hashes, return a list of those that are missing"- :> ReqBody '[JSON] [Text]- :> Post '[JSON] [Text],- narURL ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "narurl"- :> Capture "nar" NarFileName- :> Get '[JSON] Text,- createNarinfo ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> Capture "narinfohash" NarInfoHash.NarInfoHash- :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate- :> Post '[JSON] NoContent,- createNar ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "nar"- :> StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ())- :> Post '[JSON] NoContent,- serveNarContent ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "serve"- :> Capture "storehash" Text- :> CaptureAll "filepath" Text- :> Summary "Serve a file from a given store path"- :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text] ByteStringStreaming.LazyByteStringStreaming),- createKey ::- route- :- CachixAuth- :> "cache"- :> Capture "name" Text- :> "key"- :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate- :> Post '[JSON] NoContent- }+data BinaryCacheAPI route = BinaryCacheAPI+ { -- https://cache.nixos.org/nix-cache-info+ nixCacheInfo ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "nix-cache-info"+ :> Get '[XNixCacheInfo, JSON] NixCacheInfo.NixCacheInfo,+ -- Hydra: src/lib/Hydra/View/NARInfo.pm+ narinfo ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Capture "narinfohash" NarInfoHash.NarInfoHash+ :> Get '[XNixNarInfo, JSON] (Headers '[Header "Cache-Control" Text] NarInfo.CachixNarInfo),+ narinfoHead ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Capture "narinfohash" NarInfoHash.NarInfoHash+ :> Head,+ -- Hydra: src/lib/Hydra/View/NixNAR.pm+ nar ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "nar"+ :> Capture "nar" NarFileName+ :> StreamGet NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ()),+ -- cachix specific+ getCache ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Get '[JSON] BinaryCache.BinaryCache,+ narinfoBulk ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "narinfo"+ :> Summary "Given a list of store hashes, return a list of those that are missing"+ :> ReqBody '[JSON] [Text]+ :> Post '[JSON] [Text],+ narURL ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "narurl"+ :> Capture "nar" NarFileName+ :> Get '[JSON] Text,+ createNarinfo ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> Capture "narinfohash" NarInfoHash.NarInfoHash+ :> ReqBody '[JSON] NarInfoCreate.NarInfoCreate+ :> Post '[JSON] NoContent,+ createNar ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "nar"+ :> StreamBody NoFraming XNixNar (ConduitT () ByteStringStreaming.ByteStringStreaming (ResourceT IO) ())+ :> Post '[JSON] NoContent,+ serveNarContent ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "serve"+ :> Capture "storehash" Text+ :> CaptureAll "filepath" Text+ :> Summary "Serve a file from a given store path"+ :> Get '[XNixNar] (Headers '[Header "X-Content-Type-Options" Text, Header "Cache-Control" Text] ByteStringStreaming.LazyByteStringStreaming),+ createKey ::+ route+ :- CachixAuth+ :> "cache"+ :> Capture "name" Text+ :> "key"+ :> ReqBody '[JSON] SigningKeyCreate.SigningKeyCreate+ :> Post '[JSON] NoContent+ } deriving (Generic) type API = "api" :> "v1" :> ToServantApi BinaryCacheAPI
+ src/Cachix/API/Deploy.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeOperators #-}++module Cachix.API.Deploy where++import Cachix.API (CachixAuth)+import qualified Cachix.Types.ByteStringStreaming as ByteStringStreaming+import qualified Cachix.Types.Deploy as Deploy+import qualified Cachix.Types.DeployResponse as DeployResponse+import Conduit (ConduitT, ResourceT)+import qualified Data.UUID as UUID+import Protolude+import Servant.API+import Servant.API.Generic++data DeployAPI route = DeployAPI+ { activate ::+ route+ :- CachixAuth+ :> "deploy"+ :> "activate"+ :> ReqBody '[JSON] Deploy.Deploy+ :> Post '[JSON] DeployResponse.DeployResponse+ }+ deriving (Generic)++type API = "api" :> "v1" :> ToServantApi DeployAPI++api :: Proxy API+api = Proxy
+ src/Cachix/API/WebSocketSubprotocol.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DuplicateRecordFields #-}++module Cachix.API.WebSocketSubprotocol where++import qualified Control.Concurrent.Async as Async+import qualified Control.Concurrent.Chan as Chan+import qualified Data.Aeson as Aeson+import Data.Time (UTCTime)+import Data.UUID (UUID)+import qualified Network.WebSockets as WS+import Protolude++data Message cmd = Message+ { method :: Text,+ command :: cmd,+ agent :: Maybe UUID,+ id :: UUID+ }+ deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)++data Cache = Cache+ { cacheName :: Text,+ publicKey :: Text,+ isPublic :: Bool+ }+ deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)++data AgentInformation = AgentInformation+ { cache :: Maybe Cache,+ id :: UUID+ }+ deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)++data DeploymentDetails = DeploymentDetails+ { storePath :: Text,+ id :: UUID,+ index :: Int64+ }+ deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)++data BackendCommand+ = Deployment DeploymentDetails+ | AgentRegistered AgentInformation+ deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)++data AgentCommand+ = DeploymentStarted {id :: UUID, time :: UTCTime}+ | DeploymentFinished {id :: UUID, time :: UTCTime, hasSucceeded :: Bool}+ deriving (Show, Eq, Generic, Aeson.FromJSON, Aeson.ToJSON)++parseMessage :: Aeson.FromJSON cmd => ByteString -> Either Text (Message cmd)+parseMessage body =+ case Aeson.eitherDecodeStrict' body of+ Left err -> Left $ toS err+ Right message -> Right message++sendMessage :: Aeson.ToJSON cmd => WS.Connection -> Message cmd -> IO ()+sendMessage connection cmd =+ WS.sendTextData connection $ Aeson.encode cmd++-- TODO: use Async.replicateConcurrently+recieveDataConcurrently :: WS.Connection -> (ByteString -> IO ()) -> IO ()+recieveDataConcurrently connection m = do+ channel <- Chan.newChan+ Async.race_ (producer channel) (consumer channel)+ where+ producer channel = forever $ do+ payload <- WS.receiveData connection+ Chan.writeChan channel payload+ consumer channel = forever $ do+ payload <- Chan.readChan channel+ m payload++data Log = Log+ { line :: Text,+ time :: UTCTime+ }+ deriving (Generic, Show, Aeson.ToJSON, Aeson.FromJSON)
src/Cachix/Types/BinaryCache.hs view
@@ -5,13 +5,12 @@ import Data.Swagger (ToSchema) import Protolude -data BinaryCache- = BinaryCache- { name :: Text,- uri :: Text,- isPublic :: Bool,- publicSigningKeys :: [Text],- githubUsername :: Text,- permission :: Permission- }+data BinaryCache = BinaryCache+ { name :: Text,+ uri :: Text,+ isPublic :: Bool,+ publicSigningKeys :: [Text],+ githubUsername :: Text,+ permission :: Permission+ } deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)
src/Cachix/Types/ContentTypes.hs view
@@ -49,3 +49,9 @@ instance MimeRender XNixNar ByteStringStreaming.LazyByteStringStreaming where mimeRender _ = coerce++instance MimeRender PlainText ByteStringStreaming.ByteStringStreaming where+ mimeRender _ = BSL.fromStrict . coerce++instance MimeUnrender PlainText ByteStringStreaming.ByteStringStreaming where+ mimeUnrender _ = Right . coerce . BSL.toStrict
+ src/Cachix/Types/Deploy.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE DeriveAnyClass #-}++module Cachix.Types.Deploy where++import Data.Aeson+ ( FromJSON,+ ToJSON,+ )+import Data.HashMap.Strict+import Data.Swagger (ToSchema)+import Protolude++newtype Deploy = Deploy+ { agents :: HashMap Text Text+ }+ deriving (Show, Generic, FromJSON, ToJSON, ToSchema)
+ src/Cachix/Types/DeployResponse.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE DeriveAnyClass #-}++module Cachix.Types.DeployResponse where++import Data.Aeson+ ( FromJSON,+ ToJSON,+ )+import Data.HashMap.Strict+import Data.Swagger (ToSchema)+import Protolude++newtype DeployResponse = DeployResponse+ { agents :: HashMap Text Text+ }+ deriving (Show, Generic, FromJSON, ToJSON, ToSchema, NFData)
src/Cachix/Types/NarFileName.hs view
@@ -9,11 +9,10 @@ import Servant.API -- | <hash>.nar.<extension> file-data NarFileName- = NarFileName- { contentHash :: Text,- extension :: Text- }+data NarFileName = NarFileName+ { contentHash :: Text,+ extension :: Text+ } deriving (Generic) instance FromHttpApiData NarFileName where
src/Cachix/Types/NarInfoCreate.hs view
@@ -15,20 +15,19 @@ -- TODO: get rid of c prefix -- | Client create type-data NarInfoCreate- = NarInfoCreate- { -- | \$storePrefix / $storeHash - $storeSuffix- cStoreHash :: Text,- -- | \$storePrefix / $storeHash - $storeSuffix- cStoreSuffix :: Text,- cNarHash :: Text,- cNarSize :: Integer,- cFileHash :: Text,- cFileSize :: Integer,- cReferences :: [Text],- cDeriver :: Text,- cSig :: Maybe Text- }+data NarInfoCreate = NarInfoCreate+ { -- | \$storePrefix / $storeHash - $storeSuffix+ cStoreHash :: Text,+ -- | \$storePrefix / $storeHash - $storeSuffix+ cStoreSuffix :: Text,+ cNarHash :: Text,+ cNarSize :: Integer,+ cFileHash :: Text,+ cFileSize :: Integer,+ cReferences :: [Text],+ cDeriver :: Text,+ cSig :: Maybe Text+ } deriving (Generic, Show, FromJSON, ToJSON, ToSchema) data NarInfoInvalid
src/Cachix/Types/NixCacheInfo.hs view
@@ -4,10 +4,9 @@ import Data.Swagger (ToSchema) import Protolude -data NixCacheInfo- = NixCacheInfo- { storeDir :: Text,- wantMassQuery :: Integer,- priority :: Integer- }+data NixCacheInfo = NixCacheInfo+ { storeDir :: Text,+ wantMassQuery :: Integer,+ priority :: Integer+ } deriving (Generic, Show, FromJSON, ToJSON, ToSchema, NFData)
src/Cachix/Types/SigningKeyCreate.hs view
@@ -11,8 +11,7 @@ import Protolude -- | Conveys that a signing secret key was created, by sharing the public key.-newtype SigningKeyCreate- = SigningKeyCreate- { publicKey :: Text- }+newtype SigningKeyCreate = SigningKeyCreate+ { publicKey :: Text+ } deriving (Show, Generic, FromJSON, ToJSON, ToSchema)