om-socket: Socket utilities.

[ library, mit, network ] [ Propose Tags ]

Binary ingress server, egress client, and bidirectional binarry client/server


[Skip to Readme]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.11.0.3, 0.11.0.4, 0.11.0.5, 1.0.0.0, 1.0.0.1
Dependencies aeson (>=2.0.3.0 && <2.3), base (>=4.15.1.0 && <4.20), binary (>=0.8.8.0 && <0.9), binary-conduit (>=1.3.1 && <1.4), bytestring (>=0.10.12.1 && <0.13), conduit (>=1.3.4.3 && <1.4), conduit-extra (>=1.3.6 && <1.4), containers (>=0.6.4.1 && <0.7), exceptions (>=0.10.4 && <0.11), megaparsec (>=9.2.2 && <9.7), monad-logger (>=0.3.37 && <0.4), network (>=3.1.2.7 && <3.2), om-show (>=0.1.2.6 && <0.2), stm (>=2.5.0.0 && <2.6), text (>=1.2.5.0 && <2.2), time (>=1.9.3 && <1.10), tls (>=1.5.8 && <1.10) [details]
License MIT
Copyright 2022 Rick Owens
Author Rick Owens
Maintainer rick@owensmurray.com
Category Network
Home page https://github.com/owensmurray/om-socket
Uploaded by rickowens at 2024-01-13T01:06:06Z
Distributions
Reverse Dependencies 1 direct, 0 indirect [details]
Downloads 146 total (14 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for om-socket-0.11.0.4

[back to package description]

om-socket

Overview

This package provides some utilities for Haskell programs to communicate raw binary messages over the network. It includes:

  • Opening an "Ingress" service. It provides a way for a program to open a socket and accept a stream of messages without responding to any of them.

  • Open an "Egress" socket. It provides a way to connect to an "Ingress" service and dump a stream of messages to it.

  • Open a bidirectional "server". It provides a way to open a "server", which provides your program with a stream of requests paired with a way to respond to each request. Responses are allowed to be supplied in an order different than that from which the corresponding requests were received.

  • Open a client to a bidirectional "server". It provides a way to connect to an open server and provides a convenient (request -> IO response) interface to talk to the server.

Examples

Open an Ingress service

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import Conduit ((.|), awaitForever, runConduit)
import Control.Monad.IO.Class (MonadIO(liftIO))
import Data.Binary (Binary)
import GHC.Generics (Generic)
import OM.Socket (openIngress)

{- | The messages that arrive on the socket. -}
data Msg
  = A
  | B
  deriving stock (Generic)
  deriving anyclass (Binary)

main :: IO ()
main =
  runConduit $
    openIngress "localhost:9000"
    .| awaitForever (\msg ->
         case msg of
           A -> liftIO $ putStrLn "Got A"
           B -> liftIO $ putStrLn "Got B"
       )

Open an Egress connection

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import Conduit ((.|), runConduit, yield)
import Data.Binary (Binary)
import GHC.Generics (Generic)
import OM.Socket (openEgress)

{- | The messages that arrive on the socket. -}
data Msg
  = A
  | B
  deriving stock (Generic)
  deriving anyclass (Binary)

main :: IO ()
main =
  runConduit $
    mapM_ yield [A, B, B, A, A, A, B]
    .| openEgress "localhost:9000"

Start a server process

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import Conduit ((.|), awaitForever, runConduit)
import Control.Monad.Logger (runStdoutLoggingT)
import Control.Monad.Trans.Class (MonadTrans(lift))
import Data.Binary (Binary)
import OM.Socket (openServer)

{- | The requests accepted by the server. -}
newtype Request = EchoRequest String
  deriving newtype (Binary, Show)


{- | The response sent back to the client. -}
newtype Responsee = EchoResponse String
  deriving newtype (Binary, Show)


{- | Simple echo resposne server. -}
main :: IO ()
main =
  runStdoutLoggingT . runConduit $
    pure ()
    .| openServer "localhost:9000" Nothing
    .| awaitForever (\(EchoRequest str, respond) ->
        {-
          You don't necessarily have to respond right away if you don't
          want to. You can cache the responder away in some state and
          get back to it at some later time if you like.
        -}
        lift $ respond (EchoResponse str)
    )

Connect a client to a server

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import Control.Monad.Logger (runStdoutLoggingT)
import Data.Binary (Binary)
import OM.Socket (connectServer)

{- | The requests accepted by the server. -}
newtype Request = EchoRequest String
  deriving newtype (Binary, Show)


{- | The response sent back to the client. -}
newtype Responsee = EchoResponse String
  deriving newtype (Binary, Show)


{- | Simple echo resposne client. -}
main :: IO ()
main = do
  client <-
    runStdoutLoggingT $
      connectServer "localhost:9000" Nothing
  putStrLn =<< client (EchoRequest "hello")
  putStrLn =<< client (EchoRequest "world")