
Hi! I would like to make an one-directional inter-process communication in a way that one process is printing out read-compatible Haskell data types and Haskell program is reading them from a pipe. I would like to make a function which would return Nothing if there is no data type in a pipe or Just last data type there was in a pipe (discarding all before). So it should behave in a non-blocking way. In an attempt I made this: getLastMyData :: MyState (Maybe MyData) getLastMyData = do p <- gets process case p of Nothing -> fail "No process" Just (MyProcess processOut processPid processBuffer) -> do processRunning <- io $ getProcessExitCode processPid case processRunning of Just _ -> processExited _ -> do ret <- io $ tryJust (guard . isEOFError) $ slurpInput processOut processBuffer case ret of Left _ -> processExited -- EOF Right currentBuffer -> do let (datalist, currentBuffer') = readData currentBuffer modify (\s -> s { process = Just (MyProcess processOut processPid currentBuffer') }) if null datalist then return Nothing else return $ Just $ head datalist -- MyData is stored in the reverse order so head is the last MyData from the process slurpInput :: Handle -> String -> IO String slurpInput h buffer = do ready <- hReady h if not ready then return buffer else do char <- hGetChar h slurpInput h (buffer ++ [char]) readData :: String -> ([MyData], String) readData buffer = readData' [] buffer where readData' datalist [] = (datalist, []) readData' datalist buf = case reads buf of [(x, rest)] -> readData' ((head x):datalist) rest -- x is a list and currently it has only one element [] -> if length buf > 5 * maxMyDataDescLength then error "Invalid data from process" else (datalist, buf) -- we probably do not have enough data to read MyData properly _ -> error "Ambiguous parse from process" (I have cleaned a code somewhat, I hope I have not introduced any errors. MyData is encapsulated in a list when printed from a process, this is why is there "head".) The problem is that I do not like this approach. And it does not look nice. For example I am reading byte per byte and appending it to the end. Then the problem is that if process is sending garbage faster then Haskell can consume it Haskell stays in slurpInput function and never gets to readData where it would found out that there is garbage coming in. I could use hGetBufNonBlocking? But it would still not solve garbage problem. So is there some better way to do it? Mitar

2009/12/16 Mitar
The problem is that I do not like this approach. And it does not look nice. For example I am reading byte per byte and appending it to the end. Then the problem is that if process is sending garbage faster then Haskell can consume it Haskell stays in slurpInput function and never gets to readData where it would found out that there is garbage coming in. I could use hGetBufNonBlocking? But it would still not solve garbage problem.
The what is a solid, terminating criterion for garbage? How do you know this stream of bytes is no good or has gone as far as you can allow it to go? Use that criterion in `slurpInput`.
So is there some better way to do it?
I urge you to reconsider your approach for message delimiting. Why use the `hReady` signal as the clue? Seems like a race condition waiting to happen. Maybe terminate them with a Haskell comment, like `-- EOT`. Since your message always comes wrapped in a list, you could just use the square brackets to tell you when you're done. -- Jason Dusek

Hi!
On Wed, Dec 16, 2009 at 11:25 PM, Jason Dusek
The what is a solid, terminating criterion for garbage? How do you know this stream of bytes is no good or has gone as far as you can allow it to go? Use that criterion in `slurpInput`.
Criterion for garbage is that it is not readable with "read" and that not because there would be not enough data available. It seems that I will need to do buffer filling and reading at the same time. I was hoping I could split this in two functions.
I urge you to reconsider your approach for message delimiting. Why use the `hReady` signal as the clue? Seems like a race condition waiting to happen. Maybe terminate them with a Haskell comment, like `-- EOT`. Since your message always comes wrapped in a list, you could just use the square brackets to tell you when you're done.
I am not using hReady signal as delimiter. This is just to have some robustness for example if processes will communicate over network and there will be delays. So I am just trying to pick enough bytes together for "read" to succeed. And I do have upper limit on the message defined. Mitar

2009/12/16 Mitar
On Wed, Dec 16, 2009 at 11:25 PM, Jason Dusek
wrote: Criterion for garbage is that it is not readable with "read" and that not because there would be not enough data available. It seems that I will need to do buffer filling and reading at the same time. I was hoping I could split this in two functions.
I don't see where you express in the code the notion of enough data, though. Maybe I missed it.
I am not using hReady signal as delimiter.
It seems like the message delimiter to me because you keep buffering till you receive it. -- Jason Dusek
participants (2)
-
Jason Dusek
-
Mitar