3
\$\begingroup\$

I wrote a test program (and first "real" Haskell program!) that receives a zmq request on 1 socket, and forwards part of that message to another socket.

There are a 2 things I specifically don't like:

  • I couldn't figure out a way to build a protobuf message without specifying every field. This is especially annoying for fields like failure_message, which I had to set to Nothing
  • I'm not a fan of the lazyToStrictBS conversion

Is there any way to avoid these? Also, any other things I should fix? I would be shocked if there were no other issues.

The code:

module Main where

import System.ZMQ4.Monadic  
import Control.Monad (forever)  
import Data.ByteString.Char8 (pack, unpack)  
import qualified Data.ByteString as ByteString (ByteString, concat)
import Data.ByteString.Lazy as LBS (ByteString, toChunks)
import Control.Concurrent (threadDelay)

import Text.ProtocolBuffers.WireMessage (messageGet)
import Text.ProtocolBuffers.WireMessage (messagePut)

import ProtoMsg.ForwardRequest (ForwardRequest)
import ProtoMsg.ForwardResponse
import ProtoMsg.ReqResponse (ReqResponse)
import ProtoMsg.Status
import ProtoMsg.Retort


lazyToStrictBS :: LBS.ByteString -> ByteString.ByteString
lazyToStrictBS x = ByteString.concat $ LBS.toChunks x

main :: IO ()  
main =  
    runZMQ $ do
        repSocket <- socket Rep
        bind repSocket "tcp://*:9000"

        pubSocket <- socket Pub
        bind pubSocket "tcp://*:9001"

        liftIO $ putStrLn "Ready"
        forever $ do
            msg <- receive repSocket
            (liftIO.putStrLn.unwords) ["Received request:", unpack msg]

            let repMsg = ProtoMsg.ForwardResponse.ForwardResponse {
                header = ProtoMsg.ReqResponse.ReqResponse {
                    message_id = Nothing,
                    user_id = Nothing,
                    request_id = Nothing,
                    ProtoMsg.ReqResponse.status = Just ProtoMsg.Status.OK,
                    failure_message = Nothing
                }
            }
            let respMsg = ProtoMsg.Retort.Retort {
                status = Just ProtoMsg.Status.OK,
                failure_message = Nothing
            }
            send repSocket [] (lazyToStrictBS (messagePut respMsg))
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

1) If you have used hprotoc to generate Haskell modules then you should be able to use defaultValue and optional fields will be assigned to Nothing by default i.e.

header = ProtoMsg.ReqResponse.ReqResponse {
    message_id = Nothing,
    user_id = Nothing,
    request_id = Nothing,
    ProtoMsg.ReqResponse.status = Just ProtoMsg.Status.OK,
    failure_message = Nothing
}

could be replaced with

header = defaultValue {
    ProtoMsg.ReqResponse.status = Just ProtoMsg.Status.OK
}

2) Instead of your lazyToStrictBS you could use the standard function toStrict in the bytestring package

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.