IHaskell/Main.hs

105 lines
3.2 KiB
Haskell
Raw Normal View History

import BasicPrelude
import Control.Concurrent
import Data.Aeson
import qualified Data.Map as Map
2013-08-26 14:47:27 -07:00
import qualified Data.UUID.V4 as UUID (nextRandom)
import qualified Data.ByteString.Lazy as ByteString
import IHaskell.Types
2013-08-26 14:47:27 -07:00
import IHaskell.ZeroMQ
2013-09-28 21:29:54 -07:00
data KernelState = KernelState
{ getExecutionCounter :: Int
}
main :: IO ()
main = do
2013-08-26 14:47:27 -07:00
-- Read the profile JSON file from the argument list.
[profileSrc] <- getArgs
2013-08-26 14:47:27 -07:00
-- Parse the profile file.
Just profile <- liftM decode $ ByteString.readFile (textToString profileSrc)
2013-08-26 14:47:27 -07:00
-- Serve on all sockets and ports defined in the profile.
interface <- serveProfile profile
2013-08-26 14:47:27 -07:00
state <- initialKernelState
2013-08-26 14:47:27 -07:00
-- Receive and reply to all messages on the shell socket.
forever $ do
-- Read the request from the request channel.
request <- readChan $ shellRequestChannel interface
2013-08-26 14:47:27 -07:00
-- Create a header for the reply.
replyHeader <- createReplyHeader (header request)
2013-08-26 14:47:27 -07:00
-- Create the reply, possibly modifying kernel state.
reply <- modifyMVar state $ replyTo interface request replyHeader
2013-08-26 14:47:27 -07:00
-- Write the reply to the reply channel.
writeChan (shellReplyChannel interface) reply
2013-08-26 14:47:27 -07:00
-- Initial kernel state.
initialKernelState :: IO (MVar KernelState)
2013-09-28 21:29:54 -07:00
initialKernelState = newMVar KernelState {
getExecutionCounter = 1
}
2013-08-26 14:47:27 -07:00
-- | Create a new message header, given a parent message header.
createReplyHeader :: MessageHeader -> IO MessageHeader
createReplyHeader parent = do
-- Generate a new message UUID.
newMessageId <- UUID.nextRandom
2013-08-26 14:47:27 -07:00
return MessageHeader {
identifiers = identifiers parent,
parentHeader = Just parent,
metadata = Map.fromList [],
messageId = newMessageId,
sessionId = sessionId parent,
username = username parent,
msgType = replyType $ msgType parent
}
2013-08-26 14:47:27 -07:00
replyTo :: ZeroMQInterface -> Message -> MessageHeader -> KernelState -> IO (KernelState, Message)
replyTo _ KernelInfoRequest{} replyHeader state = return (state, KernelInfoReply { header = replyHeader })
2013-08-26 16:14:48 -07:00
2013-08-27 09:46:31 -07:00
replyTo interface ExecuteRequest{} replyHeader state = do
-- Queue up a response on the iopub socket
newMessageId <- UUID.nextRandom
newMessageId2 <- UUID.nextRandom
2013-08-27 09:46:31 -07:00
let header = MessageHeader {
identifiers = identifiers replyHeader,
parentHeader = Nothing,
metadata = Map.fromList [],
messageId = newMessageId,
sessionId = sessionId replyHeader,
username = username replyHeader,
msgType = "status"
}
let statusMsg = IopubStatus {
header = header,
executionState = Idle
}
let streamHeader = MessageHeader {
identifiers = identifiers replyHeader,
parentHeader = Nothing,
metadata = Map.fromList [],
messageId = newMessageId2,
sessionId = sessionId replyHeader,
username = username replyHeader,
msgType = "stream"
}
let streamMsg = IopubStream streamHeader Stdout $ textToString $ "Hello! " ++ show (getExecutionCounter state)
writeChan (iopubChannel interface) streamMsg
2013-08-27 09:46:31 -07:00
writeChan (iopubChannel interface) statusMsg
2013-09-28 21:29:54 -07:00
let counter = getExecutionCounter state
newState = state { getExecutionCounter = getExecutionCounter state + 1 }
return (newState, ExecuteReply {
2013-08-27 09:46:31 -07:00
header = replyHeader,
2013-09-28 21:29:54 -07:00
executionCounter = counter,
2013-08-27 09:46:31 -07:00
status = "ok"
})