packages feed

network-service (empty) → 0.1.0.0

raw patch · 6 files changed

+248/−0 lines, 6 filesdep +basedep +base64-bytestringdep +bytestringsetup-changed

Dependencies added: base, base64-bytestring, bytestring, hscolour, network, network-simple

Files

+ Example/Echo.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE Rank2Types #-}+--------------------------------------------------------------------------------+-- |+-- Module      : Example.Echo+-- Copyright   : (c) Moritz Angermann 2014+-- License     : MIT+--+-- Maintainer  : moritz@lichtzwerge.de+-- Stability   : stable+-- Portability : portable+--+-- An echo service on port 2000+--+-- To start the server run+-- > $ echo server+--+-- You can then run the client+-- > $ echo client+--+-- Or connect to the server with telnet+-- > $ telnet localhost 2000+--+--------------------------------------------------------------------------------+module Main (main) where+import           Network.Simple.TCP+import           Data.ByteString.Char8   ( pack, unpack )+import           System.Environment      ( getProgName, getArgs )+import           Control.Monad           ( unless )++import Network.Service+import Network.Transport.Encoding.Base64 (mkService)++-- | Make a service server running on the executing host.+mkServiceServer :: ServiceMessage a+                   => ServiceName      -- ^ the port+                   -> ServiceHandler a -- ^ a handler to handle connections.+                   -> IO ()+mkServiceServer port shandler = serve HostAny port handler+  where handler :: (Socket, SockAddr) -> IO ()+        handler x = mkService x >>= shandler++-- | Make a service client+mkServiceClient :: ServiceMessage a+                   => HostName       -- ^ The hostname that provides a 'Service a'.+                   -> ServiceName    -- ^ The port the service runs at.+                   -> IO (Service a) -- ^ The client. (Service interface)+mkServiceClient h p = connect h p mkService++-- | We use a simple data type for communication.+--   All it holds is a simple string.+data Message = Msg String++-- | Turning a String message into a bytestring.+--   Trivially through pack and unpack.+instance ServiceMessage Message where+  toBS (Msg s) = pack s+  fromBS = Msg . unpack++main :: IO ()+main = do+  args <- getArgs+  prog <- getProgName+  +  case args of+    ["server"] -> mkServiceServer "2000" handler+    ["client"] -> do+      service <- mkServiceClient "localhost" "2000"+      let msg = "Hello World!"+      putStrLn $ "[Client] Sending: " ++ msg+      sSend service $ Msg msg+      Msg resp <- sRecv service+      putStrLn $ "[Client] Received: " ++ resp+      sTerm service+    _          -> putStrLn $ "Usage: " ++ prog ++ " (server|client)"++  where handler :: ServiceHandler Message+        handler service = sRecv service >>= sSend service >> sDone service >>= flip unless (handler service)
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2014 Moritz Angermann++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Network/Service.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE Rank2Types #-}+--------------------------------------------------------------------------------+-- |+-- Module      : Network.Service+-- Copyright   : (c) Moritz Angermann 2014+-- License     : MIT+--+-- Maintainer  : moritz@lichtzwerge.de+-- Stability   : stable+-- Portability : portable+--+-- A service is an endpoint that can receive and send messages.+--+--------------------------------------------------------------------------------+module Network.Service where++import Data.ByteString (ByteString)++-- | Services operate on Messages, the ServiceMessage class abstracts+--   the serialization.+class ServiceMessage a where+  toBS :: a -> ByteString   -- ^ serialization to ByteString representation+  fromBS :: ByteString -> a -- ^ deserialization from ByteString representation++-- | A Service of a certain Message data.+data Service a = Service+                 { sDone :: IO Bool    -- ^ tells whether the service is done or not.+                 , sRecv :: IO a       -- ^ receive a message.+                 , sSend :: a -> IO () -- ^ send a message.+                 , sTerm :: IO ()      -- ^ terminate the service.+                 }+-- | A handler takes a service and returns an IO action.+--   The idea is that a service handler will 'run' a service+--+-- a simple echo handler might look like the following:+--+-- > handler service = do { msg <- sRecv service+-- >                      ; sSend service msg+-- >                      ; isDone <- sDone service+-- >                      ; unless isDone (handler service)+-- >                      }+type ServiceHandler a = Service a -> IO ()
+ Network/Transport/Encoding/Base64.hs view
@@ -0,0 +1,46 @@+--------------------------------------------------------------------------------+-- |+-- Module      : Network.Transport.Encoding.Base64+-- Copyright   : (c) Moritz Angermann 2014+-- License     : MIT+--+-- Maintainer  : moritz@lichtzwerge.de+-- Stability   : stable+-- Portability : portable+--+-- A trivial service that uses base64 as encoding for the+-- messages and newlines for message separation.+--------------------------------------------------------------------------------+module Network.Transport.Encoding.Base64 (mkService) where+import           Network.Socket          (Socket, SockAddr, socketToHandle)+import           System.IO               (hSetBuffering, hGetContents, hPutStrLn, hClose+                                         ,IOMode( ReadWriteMode ), BufferMode( LineBuffering ))+import           Control.Concurrent      (newMVar, modifyMVar)+import           Data.ByteString.Base64  (encode, decode)+import           Data.ByteString.Char8   (pack, unpack)+import           Data.ByteString         (ByteString)++import           Network.Service++-- hack.+decode' :: ByteString -> ByteString+decode' bs = let Right res = decode bs in res++-- | Builds a simple service, that uses base64 as the base+--   encoding for the messages.  Messages are separated by+--   newlines.+mkService :: ServiceMessage a+             => (Socket, SockAddr) -- ^ The socket and socket address to the service is bound on.+             -> IO (Service a)     -- ^ The service to be used.+mkService (sock, addr) = do+  hdl <- socketToHandle sock ReadWriteMode+  hSetBuffering hdl LineBuffering+  messages <- lines `fmap` (hGetContents hdl)+  messageMVar <- newMVar messages+  return $ Service { sDone = modifyMVar messageMVar+                             (\ms -> return (ms, ms == []))+                   , sRecv = modifyMVar messageMVar+                             (\ms -> return (tail ms, fromBS . decode' . pack $ head ms))+                   , sSend = hPutStrLn hdl . unpack . encode . toBS+                   , sTerm = hClose hdl+                   }
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ network-service.cabal view
@@ -0,0 +1,61 @@+-- Initial network-service.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                network-service+version:             0.1.0.0+synopsis:            Provide a service at the data type level.+description:         Thin very layer over network-simple, that allows to write+                     a service that can be communicated with at the data level.+                     Makes it trivial to build a services upon a data type,+                     provided a ByteString serialization can be given.+homepage:            https://github.com/angerman/network-service+license:             MIT+license-file:        LICENSE+author:              Moritz Angermann+maintainer:          moritz@lichtzwerge.de+copyright:           2014 Moritz Angermann+category:            Network+build-type:          Simple+-- extra-source-files:  +cabal-version:       >=1.10++flag example+  description: Build example executables to showcase the library+  default: False++flag documentation+  default: False++source-repository head+  type:     git+  location: https://github.com/angerman/network-service.git++library+  if flag(documentation)+     build-depends:    hscolour+  exposed-modules:     Network.Service, Network.Transport.Encoding.Base64+  -- other-modules:       +  other-extensions:    Rank2Types+  build-depends:       base >=4.7 && <4.8+                     , network >=2.6 && <2.7+                     , bytestring >=0.10 && <0.11+                     , base64-bytestring >=1.0 && <1.1+  -- hs-source-dirs:      +  default-language:    Haskell2010++executable echo+  if flag(example)+     Buildable: True+  else+     Buildable: False+     +  main-is:             Example/Echo.hs+  other-modules:       Network.Service, Network.Transport.Encoding.Base64+  -- other-extensions:+  build-depends:       base >=4.7 && <4.8+                     , network >=2.6 && <2.7+                     , network-simple >= 0.4 && <0.5+                     , bytestring >=0.10 && <0.11+                     , base64-bytestring >=1.0 && <1.1+  -- hs-source-dirs:+  default-language:    Haskell2010