grpc-spec 1.1.0 → 1.1.1
raw patch · 4 files changed
+105/−2 lines, 4 filesdep +cborgdep +serialisedep ~QuickCheckPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: cborg, serialise
Dependency ranges changed: QuickCheck
API changes (from Hackage documentation)
+ Network.GRPC.Spec: data CborRpc (serv :: Symbol) (meth :: Symbol)
- Network.GRPC.Spec: NextElem :: !a -> NextElem a
+ Network.GRPC.Spec: NextElem :: a -> NextElem a
Files
- CHANGELOG.md +4/−0
- grpc-spec.cabal +5/−2
- src/Network/GRPC/Spec.hs +3/−0
- src/Network/GRPC/Spec/RPC/CBOR.hs +93/−0
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for grpc-spec +## 1.1.1 -- 2026-10-30++* Support for (non-standard) CBOR RPC [#383, Finley McIlwaine]+ ## 1.1.0 -- 2026-09-02 * Trivial `BuildMetadata` and `ParseMetadata` instances for `[CustomMetadata]`
grpc-spec.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: grpc-spec-version: 1.1.0+version: 1.1.1 synopsis: Implementation of the pure part of the gRPC spec description: This is an implementation of the pure part of the core gRPC spec at <https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md>.@@ -105,6 +105,7 @@ Network.GRPC.Spec.OrcaLoadReport Network.GRPC.Spec.PercentEncoding Network.GRPC.Spec.RPC+ Network.GRPC.Spec.RPC.CBOR Network.GRPC.Spec.RPC.JSON Network.GRPC.Spec.RPC.Protobuf Network.GRPC.Spec.RPC.Raw@@ -134,6 +135,7 @@ , binary >= 0.8 && < 0.9 , bytestring >= 0.10.12 && < 0.13 , case-insensitive >= 1.2 && < 1.3+ , cborg >= 0.2 && < 0.3 , containers >= 0.6 && < 0.9 , data-default >= 0.7 && < 0.9 , deepseq >= 1.4 && < 1.6@@ -147,6 +149,7 @@ , proto-lens-protobuf-types >= 0.7 && < 0.8 , proto-lens-runtime >= 0.7 && < 0.8 , record-hasfield >= 1.0 && < 1.1+ , serialise >= 0.2 && < 0.3 , text >= 1.2 && < 2.2 , utf8-string >= 1.0 && < 1.1 , vector >= 0.13 && < 0.14@@ -198,7 +201,7 @@ -- Additional dependencies , prettyprinter >= 1.7 && < 1.8 , prettyprinter-ansi-terminal >= 1.1 && < 1.2- , QuickCheck >= 2.14 && < 2.19+ , QuickCheck >= 2.14 && < 2.20 , quickcheck-instances >= 0.3 && < 0.5 , tasty >= 1.4 && < 1.6 , tasty-quickcheck >= 0.10 && < 0.12
src/Network/GRPC/Spec.hs view
@@ -27,6 +27,8 @@ , EncodeFields -- opaque -- *** Raw , RawRpc+ -- *** CBOR+ , CborRpc -- * Streaming types , StreamingType(..) , SStreamingType(..)@@ -187,6 +189,7 @@ import Network.GRPC.Spec.MessageMeta import Network.GRPC.Spec.OrcaLoadReport import Network.GRPC.Spec.RPC+import Network.GRPC.Spec.RPC.CBOR import Network.GRPC.Spec.RPC.JSON import Network.GRPC.Spec.RPC.Protobuf import Network.GRPC.Spec.RPC.Raw
+ src/Network/GRPC/Spec/RPC/CBOR.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE OverloadedStrings #-}++module Network.GRPC.Spec.RPC.CBOR (CborRpc) where++import Codec.CBOR.Read qualified as CBOR+import Codec.Serialise+import Control.DeepSeq (NFData)+import Control.Exception (displayException)+import Data.ByteString.Char8 qualified as BS.Char8+import Data.ByteString.Lazy qualified as BS.Lazy+import Data.ByteString.Lazy qualified as Lazy (ByteString)+import Data.Proxy+import GHC.TypeLits++import Network.GRPC.Spec.CustomMetadata.Typed+import Network.GRPC.Spec.RPC+import Network.GRPC.Spec.RPC.StreamType++{-------------------------------------------------------------------------------+ CBOR format+-------------------------------------------------------------------------------}++-- | gRPC using CBOR as the message encoding+--+-- You will need to manually provide 'Input' and 'Output' instances for each+-- RPC you use, along with 'Serialise' instances for those types.+data CborRpc (serv :: Symbol) (meth :: Symbol)++instance ( KnownSymbol serv+ , KnownSymbol meth++ -- Serialization+ , NFData (Input (CborRpc serv meth))+ , NFData (Output (CborRpc serv meth))++ -- Debugging constraints+ , Show (Input (CborRpc serv meth))+ , Show (Output (CborRpc serv meth))+ , Show (RequestMetadata (CborRpc serv meth))+ , Show (ResponseInitialMetadata (CborRpc serv meth))+ , Show (ResponseTrailingMetadata (CborRpc serv meth))+ ) => IsRPC (CborRpc serv meth) where+ rpcContentType _ = defaultRpcContentType "cbor"+ rpcServiceName _ = BS.Char8.pack $ symbolVal (Proxy @serv)+ rpcMethodName _ = BS.Char8.pack $ symbolVal (Proxy @meth)+ rpcMessageType _ = Nothing++instance ( IsRPC (CborRpc serv meth)++ -- Serialization constraints+ , Serialise (Input (CborRpc serv meth))+ , Serialise (Output (CborRpc serv meth))++ -- Metadata constraints+ , BuildMetadata (RequestMetadata (CborRpc serv meth))+ , ParseMetadata (ResponseInitialMetadata (CborRpc serv meth))+ , ParseMetadata (ResponseTrailingMetadata (CborRpc serv meth))+ ) => SupportsClientRpc (CborRpc serv meth) where+ rpcSerializeInput _ = serialise+ rpcDeserializeOutput _ = deserialiseExactly++instance ( IsRPC (CborRpc serv meth)++ -- Serialization constraints+ , Serialise (Input (CborRpc serv meth))+ , Serialise (Output (CborRpc serv meth))++ -- Metadata constraints+ , ParseMetadata (RequestMetadata (CborRpc serv meth))+ , BuildMetadata (ResponseInitialMetadata (CborRpc serv meth))+ , BuildMetadata (ResponseTrailingMetadata (CborRpc serv meth))+ ) => SupportsServerRpc (CborRpc serv meth) where+ rpcDeserializeInput _ = deserialiseExactly+ rpcSerializeOutput _ = serialise++-- | For CBOR protocol we do not check communication protocols+instance ValidStreamingType styp+ => SupportsStreamingType (CborRpc serv meth) styp++-- | Decode the CBOR-encoded value in the given 'Lazy.ByteString'+--+-- Fails if the decoder fails or if there are any bytes leftover after a+-- successful decode.+deserialiseExactly :: Serialise a => Lazy.ByteString -> Either String a+deserialiseExactly bs =+ case CBOR.deserialiseFromBytes decode bs of+ Left err ->+ Left $ displayException err+ Right (unconsumed, a) ->+ if BS.Lazy.null unconsumed then+ Right a+ else+ Left "Not all bytes consumed"