packages feed

transient-universe-0.2: src/Transient/Move/Services.hs

-----------------------------------------------------------------------------
--
-- Module      :  Transient.Move.Services
-- Copyright   :
-- License     :  GPL-3
--
-- Maintainer  :  agocorona@gmail.com
-- Stability   :
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------

module Transient.Move.Services  where

import Transient.Base
import Transient.Move
import Transient.Logged
import Transient.EVars
import Control.Monad.IO.Class
import System.Process
import System.IO.Unsafe
import Control.Concurrent.MVar
import Control.Applicative
import Network (PortID(..))
import GHC.Conc
import System.Directory
import Control.Monad
import Data.List
import Data.TCache hiding(onNothing)

-- for the example
import System.Environment

startServices :: Cloud ()
startServices= do
  node <- getMyNode
  onAll . liftIO $ print node
  mapM_ start $ services node
  where
  start (package,program,port)= onAll . liftIO $ do
          let prog= pathExe (name package) program port
          liftIO $ print prog
          createProcess $ shell prog


pathExe package program port= package++"/dist/build/"++package++"/"++program
                                       ++ " " ++ show port

install :: String  -> String -> Int -> Cloud ()
install package program port =  do
     let packagename = name package
     exist <-  local $ liftIO $ doesDirectoryExist  packagename
     when (not exist) $ local $ liftIO $ do
         callProcess  "git" ["clone",package]
         liftIO $ print "GIT DONE"
         setCurrentDirectory packagename
         callProcess  "cabal" ["install"]
         setCurrentDirectory ".."
         return()
     let prog= pathExe packagename program port
     local $ liftIO $ do
           createProcess $ shell program
           return ()

     let service= (package, program,  port)

     Connection{myNode= rnode} <- onAll getSData <|> error "Mynode not set: use setMyNode"
     local $ liftIO $ do
       atomically $ do
        MyNode( Node h p c servs) <- readTVar rnode

        writeTVar rnode $ MyNode $ Node h p c $ service:servs
       liftIO syncCache
     node <-  getMyNode
     notifyService node service
     return()

name url= do
     let git= "http://github.com/"
     if not $ isPrefixOf git url
       then error "install: only github repos are admitted, sorry"
       else
        let segments = split '/' $ drop (length git) url
            segs'= reverse segments
        in  head  segs'


     where
     split c []= []
     split c xs=
        let (h,t)= span  (/= c) xs
        in  if null t then [h] else h : split c  (tail t)

rfreePort :: MVar Int
rfreePort = unsafePerformIO $ newMVar  3000

freePort :: MonadIO m => m Int
freePort= liftIO $ modifyMVar rfreePort $ \ n -> return (n+1,n)

initService node package program= loggedc $
    case   find  (\(package', program',_) -> package==package' && program== program') $ services node of
       Just (_,_,port) -> return port
       Nothing -> do
            beamTo node
            port <- onAll freePort
            install package program  port
            empty
          <|> do
            Connection{comEvent=ev} <- onAll getSData
            (node', (package', program',port)) <- local waitNodeEvents
            if node'== node && package' == package && program'== program
                 then return port
                 else empty

notifyService :: Node -> Service -> Cloud ()
notifyService node service=  clustered $ do
     onAll . liftIO $ atomically $ do
        nodes <- readTVar nodeList
        let ([nod], nodes')= span (== node) nodes
        let nod' = nod{services=service:services nod}
        writeTVar nodeList $ nod' : nodes'
        return ()

     local $ sendNodeEvent (node,service)
     return ()

{-
main= do
--      keep $ install "http://github.com/agocorona/transient" "MainStreamFiles"  3000
    let node1= createNode "localhost" 2000
    let node2= createNode "localhost" 2001
    args <-getArgs
    let [localNode,remoteNode]= if null args then [node1,node2] else [node2,node1]


    runCloudIO $ do
      onAll $ addNodes [localNode, remoteNode]
      onAll $ setMyNode localNode
      listen localNode <|> return ()
      local $ option "start" "start"

      startServices
      port <-initService remoteNode "http://github.com/agocorona/transient" "MainStreamFiles"
      onAll . liftIO $ putStrLn $ "installed at" ++ show port
-}