I'd tried to use
hGetContents
and just read off one message at a time. This is doomed to failure because laziness and hanging around on a network socket that's in a semi-closed state just isn't going to work.In this version of the code we enter a loop which terminates once the client sends the "quit" message (rather than an infinite loop).
(Update: Thanks to helpful comments edited the code to use
Control.Monad.when
)
listenLoop :: Handle -> IO ()
listenLoop h = do
sendFrame h "hi, remember you can stop this at anytime by pressing quit!"
msg <- readFrame h
putStrLn msg
when (msg /= "quit") (listenLoop h)
readFrame :: Handle -> IO String
readFrame h = readUntil h ""
where
readUntil h str = do
new <- hGetChar h
if (new == chr 0)
then readUntil h ""
else if new == chr 255
then return str
else readUntil h (str ++ [new])
On a side note - the indentation for the if/then/else is a little strange, but "if within do" at least explains why.
All that remains is a quick bit of HTML to allow you to have a conversation. Replace the body in the previous example with something like this (and also make sure that the
ws
object has the appropriate scope!
<body>
<h1>I'm doing something</h1>
<div id="output">
</div>
<div id="connectionStatus">
</div>
<textarea rows="2" cols="80" id="message">
Type whatever you want here, but type quit to close the connection
</textarea>
<br />
<button id="clickMe" onClick="ws.send($('#message').val());">
Click me!
</button>
</body>
You should get something where you can have a rather boring conversation with Haskell. It repeats the same text over and over again until you press quit.