HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Haskell zmq & protobuf message forwarding

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
protobufmessagezmqforwardinghaskell

Problem

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
}

Solution

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

Code Snippets

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

Context

StackExchange Code Review Q#118180, answer score: 2

Revisions (0)

No revisions yet.