{-# LANGUAGE TemplateHaskell #-}
import System.Environment (getArgs)
import System.Random (randomIO)
import Control.Monad (forM)
import Control.Monad.IO.Class (liftIO)
import Control.Distributed.Process
( Process
, NodeId
, SendPort
, newChan
, sendChan
, spawn
, receiveChan
, spawnLocal
)
import Control.Distributed.Process.Backend.Azure
import Control.Distributed.Process.Closure
( remotable
, remotableDecl
, mkClosure
)
randomElement :: [a] -> IO a
randomElement xs = do
ix <- randomIO
return (xs !! (ix `mod` length xs))
remotableDecl [
[d| dfib :: ([NodeId], SendPort Integer, Integer) -> Process () ;
dfib (_, reply, 0) = sendChan reply 0
dfib (_, reply, 1) = sendChan reply 1
dfib (nids, reply, n) = do
nid1 <- liftIO $ randomElement nids
nid2 <- liftIO $ randomElement nids
(sport, rport) <- newChan
_ <- spawn nid1 $ $(mkClosure 'dfib) (nids, sport, n - 2)
_ <- spawn nid2 $ $(mkClosure 'dfib) (nids, sport, n - 1)
n1 <- receiveChan rport
n2 <- receiveChan rport
sendChan reply $ n1 + n2
|]
]
remoteFib :: ([NodeId], Integer) -> Backend -> Process ()
remoteFib (nids, n) _backend = do
(sport, rport) <- newChan
_ <- spawnLocal $ dfib (nids, sport, n)
fib_n <- receiveChan rport
mapM_ terminateNode nids
remoteSend fib_n
remotable ['remoteFib]
printResult :: LocalProcess ()
printResult = do
result <- localExpect :: LocalProcess Integer
liftIO $ print result
main :: IO ()
main = do
args <- getArgs
case args of
"onvm":args' -> onVmMain (__remoteTable . __remoteTableDecl) args'
[sid, x509, pkey, user, cloudService, n] -> do
params <- defaultAzureParameters sid x509 pkey
let params' = params { azureSshUserName = user }
backend <- initializeBackend params' cloudService
vms <- findVMs backend
nids <- forM vms $ \vm -> spawnNodeOnVM backend vm "8080"
callOnVM backend (head vms) "8081" $
ProcessPair ($(mkClosure 'remoteFib) (nids, read n :: Integer))
printResult
_ ->
error "Invalid command line arguments"