bert 1.2.1.1 → 1.2.1.2
raw patch · 7 files changed
+138/−23 lines, 7 files
Files
- CHANGELOG.md +26/−0
- README.md +78/−0
- bert.cabal +8/−3
- src/Data/BERT.hs +1/−1
- src/Data/BERT/Packet.hs +4/−4
- src/Data/BERT/Parser.hs +4/−4
- src/Network/BERT/Server.hs +17/−11
+ CHANGELOG.md view
@@ -0,0 +1,26 @@+Version 1.2.1.2+---------------++* Fix Windows compatibility++Version 1.2.1.1+---------------++* Fix integer (de)serialization on 64-bit platforms++Version 1.2.1+-------------++* Fix the docs+* Export the `Error` data type++Version 1.2+-----------++* Drop the `bert` command-line tool+* Remove support for the (non-standard) bert:// URI+* Change the way transports are represented+* Instead of `fromURI` or `fromHostPort`, you should now use `tcpClient` and+ `tcpServer`+* Both the client and the server now support persistent connections+* The default TCP backlog is increased for the server
+ README.md view
@@ -0,0 +1,78 @@+BERT[-RPC] for Haskell+======================++Originally written by marius a. eriksen (marius@monkey.org)++This is a [BERT](http://bert-rpc.org/) serializer/deserializer and+[BERT-RPC](http://bert-rpc.org) client and server for+[Haskell](http://www.haskell.org/). BERT-RPC currently supports+synchronous (`call`) requests.++The primitives provided are fairly elementary: for the client, `call`+provides the capability to perform the RPC call, while the server's+`serve` is provided with a dispatch function providing the dispatching+logic for the server. Thus, one can imagine building higher level+abstractions on top of these primitives.++Installation+------------++It's a cabal package, so++ $ cabal install bert++should do the trick.++BERT+----++ import qualified Data.ByteString.Lazy.Char8 as C+ import Data.BERT++Creating BERT terms is simple.++ TupleTerm [BytelistTerm (C.pack "hello"), IntTerm 123]++Or by using the `BERT` typeclass.++ showBERT $ ("hello", 123)++The `BERT` class can also read terms back.++ Right ("hello", 123) = readBERT . showBERT $ ("hello", 123)++BERT-RPC client+---------------++ import Data.BERT+ import Network.BERT.Client++Create a transport to the server endpoint, and issue a (synchronous)+call with it.++ t <- tcpClient "localhost" 8080+ r <- call t "calc" "add" ([123, 3000]::[Int])+ case r of+ Right res -> print (res :: Int)+ Left _ -> putStrLn "error"+ +BERT-RPC server+---------------++ import Data.BERT+ import Network.BERT.Server++Create a transport from which to accept connections, and provide a+dispatch function for incoming RPCs. The dispatch function is issued+in a new thread for each incoming request.++ main = do+ s <- tcpServer 8080+ serve t dispatch++ dispatch "calc" "add" [IntTerm a, IntTerm b] = + return $ Success $ IntTerm (a + b)+ dispatch "calc" _ _ =+ return NoSuchFunction+ dispatch _ _ _ = + return NoSuchModule
bert.cabal view
@@ -1,6 +1,6 @@ cabal-version: >= 1.16 name: bert-version: 1.2.1.1+version: 1.2.1.2 build-type: Simple license: BSD3 license-file: LICENSE@@ -13,6 +13,9 @@ copyright: (c) 2009-2011 marius a. eriksen; (c) 2013 Roman Cheplyaka homepage: https://github.com/feuerbach/bert bug-reports: https://github.com/feuerbach/bert/issues+extra-source-files:+ README.md+ CHANGELOG.md source-repository head type: git@@ -20,14 +23,16 @@ library hs-source-dirs: src- build-depends: base == 4.*, containers >= 0.2, + build-depends: base == 4.*, containers >= 0.2, bytestring >= 0.9, binary >= 0.5, mtl >= 1.1,- network >= 2.2, unix >= 2.0, time >= 1.1, + network >= 2.2, time >= 1.1, parsec >= 2.0, conduit >= 1.0, network-conduit >= 1.0, binary-conduit >= 1.2, void+ if !os(windows)+ build-depends: unix >= 2.0 exposed-modules: Data.BERT
src/Data/BERT.hs view
@@ -1,7 +1,7 @@ -- | BERT (Erlang terms) implementation. See <http://bert-rpc.org/> and -- <http://erlang.org/doc/apps/erts/erl_ext_dist.html> for more -- details.-module Data.BERT +module Data.BERT ( module Data.BERT.Types , module Data.BERT.Term , module Data.BERT.Packet
src/Data/BERT/Packet.hs view
@@ -1,5 +1,5 @@ -- | BERP (BERT packets) support.-module Data.BERT.Packet +module Data.BERT.Packet ( Packet(..) , fromPacket ) where@@ -21,7 +21,7 @@ fromPacket (Packet t) = t instance Binary Packet where- put (Packet term) = + put (Packet term) = putWord32be (fromIntegral len) >> putLazyByteString encoded where encoded = encode term len = L.length encoded@@ -29,6 +29,6 @@ get = getPacket getPacket =- liftM fromIntegral getWord32be >>= - getLazyByteString >>= + liftM fromIntegral getWord32be >>=+ getLazyByteString >>= return . Packet . decode
src/Data/BERT/Parser.hs view
@@ -22,11 +22,11 @@ -- | Parse a simple BERT (erlang) term from a string in the erlang -- grammar. Does not attempt to decompose complex terms. parseTerm :: String -> Either ParseError Term-parseTerm = parse p_term "term" +parseTerm = parse p_term "term" p_term :: Parser Term-p_term = t <* spaces - where +p_term = t <* spaces+ where t = IntTerm <$> p_num (readSigned readDec) <|> FloatTerm <$> p_num (readSigned readFloat) <|> AtomTerm <$> p_atom@@ -47,7 +47,7 @@ quoted = quote >> many1 letter <* quote quote = char '\'' -p_seq open close elem = +p_seq open close elem = between (open >> spaces) (spaces >> close) $ elem `sepBy` (spaces >> char ',' >> spaces)
src/Network/BERT/Server.hs view
@@ -2,7 +2,9 @@ -- client RPC call/reply logic. Only synchronous requests are -- supported at this time. -module Network.BERT.Server +{-# LANGUAGE CPP #-}++module Network.BERT.Server ( -- * Example -- $example@@ -20,7 +22,9 @@ import Data.ByteString.Lazy.Char8 as C import Data.BERT import Text.Printf+#if !mingw32_HOST_OS import qualified System.Posix.Signals as Sig+#endif data DispatchResult = Success Term@@ -39,9 +43,11 @@ -> (String -> String -> [Term] -> IO DispatchResult) -> IO () serve server dispatch = do+#if !mingw32_HOST_OS -- Ignore sigPIPE, which can be delivered upon writing to a closed -- socket. Sig.installHandler Sig.sigPIPE Sig.Ignore Nothing+#endif (runServer server $ \t -> (forkIO $ runSession t $ handleCall dispatch) >> return ())@@ -55,38 +61,38 @@ handle (TupleTerm [AtomTerm "info", AtomTerm "cache", _]) = return () -- Ignore caching requests. handle (TupleTerm [- AtomTerm "call", AtomTerm mod, + AtomTerm "call", AtomTerm mod, AtomTerm fun, ListTerm args]) = do res <- liftIO $ dispatch mod fun args case res of- Success term -> + Success term -> sendt $ TupleTerm [AtomTerm "reply", term] NoSuchModule ->- sendErr "server" 1 "BERTError" + sendErr "server" 1 "BERTError" (printf "no such module \"%s\"" mod :: String) [] NoSuchFunction ->- sendErr "server" 2 "BERTError" + sendErr "server" 2 "BERTError" (printf "no such function \"%s\"" fun :: String) [] Undesignated detail -> sendErr "server" 0 "HandlerError" detail [] - sendErr etype ecode eclass detail backtrace = + sendErr etype ecode eclass detail backtrace = sendt $ TupleTerm [- AtomTerm "error", + AtomTerm "error", TupleTerm [- AtomTerm etype, IntTerm ecode, BinaryTerm . C.pack $ eclass, + AtomTerm etype, IntTerm ecode, BinaryTerm . C.pack $ eclass, ListTerm $ Prelude.map (BinaryTerm . C.pack) backtrace]] -- $example--- +-- -- To serve requests, create a server and call 'serve' with a -- dispatch function.--- +-- -- > main = do -- > s <- tcpServer 8080 -- > serve s dispatch -- >--- > dispatch "calc" "add" [IntTerm a, IntTerm b] = +-- > dispatch "calc" "add" [IntTerm a, IntTerm b] = -- > return $ Success $ IntTerm (a + b) -- > dispatch "calc" _ _ = -- > return NoSuchFunction