packages feed

transient-universe-0.3: 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(Loggable(..))
--import Transient.Internals((!>))
import Transient.Move.Utils
import Transient.Internals(Log(..))
import Transient.EVars
import Transient.Indeterminism
import Control.Monad.IO.Class
import System.Process
import System.IO.Unsafe
import Control.Concurrent.MVar
import Control.Applicative

import System.Directory
import Control.Monad
import Data.List
import Data.Maybe
--import Data.TCache hiding(onNothing)

-- for the example
import System.Environment

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


pathExe package program port= package++"/dist/build/"++package++"/"++program
                                       ++ " -p start/" ++ show port

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

     return()

name url=  slash . slash . slash $ slash url
  where
  slash= tail1 . dropWhile (/='/')
  tail1 []=[]
  tail1 x= tail x

rfreePort :: MVar Int
rfreePort = unsafePerformIO $ newMVar  3000

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

initService ident service@(package, program)= loggedc $ do
    nodes <- local getNodes
    case find (\node  -> service `elem` nodeServices node) nodes  of
       Just node -> return node
       Nothing -> do

          nodes <- callOne $ do
                    yn<- requestService ident service
                    if yn then do
                        port <- onAll freePort
                        install package program  port
                        nodeService port
                      else empty
          local $ addNodes nodes
          return $ head nodes
    where
    nodeService port= local $ do
       Node h _ _ _ <- getMyNode
       return $ Node h port (unsafePerformIO $ newMVar []) [service] :: TransIO Node



callOne mx= local . collect 1 . runCloud $ clustered mx

rfriends        =   unsafePerformIO $ newMVar []
rservices       =   unsafePerformIO $ newMVar []
ridentsBanned    =   unsafePerformIO $ newMVar []
rServicesBanned =   unsafePerformIO $ newMVar []

requestService ident service= local $  do

     friends            <- liftIO $ readMVar rfriends
     services           <- liftIO $ readMVar rservices
     identsBanned       <- liftIO $ readMVar ridentsBanned
     servicesBanned     <- liftIO $ readMVar rServicesBanned

     return $ if (null friends || ident `elem` friends)
        && (null services || service `elem` services)
        && (null identsBanned || ident `notElem` identsBanned)
        && (null servicesBanned || service `notElem` servicesBanned)
      then True else False
  where
  notElem a b= not $ elem a b


callService
    :: (Loggable a, Loggable b)
    => String -> Service -> a  -> Cloud b
callService ident service params = do
    node <-  initService ident service
    log <- onAll $ do
           log  <- getSData <|> return emptyLog
           setData emptyLog
           return log

    r <- wormhole node $ loggedc $ do
             local $ return params

             teleport
             local empty
--    return () !> ("r=",r)
    restoreLog log
--    local $ do
--       Log _ _ log <- getSData <|> return emptyLog
--       return() !> ("log after",log)
    return  r -- (r `asTypeOf` witness)
    where
    restoreLog (Log _ _ logw)= onAll $ do
       Log _ _ logw' <- getSData <|> return emptyLog

       let newlog= reverse logw' ++ logw
--       return ()                 !> ("newlog", logw,logw')
       setData $ Log False newlog newlog

    emptyLog= Log False [] []



{-
servicios
      autoinstall service
      servicio de instalaci¢n de servicios
  procedurers call services, services install themselves in nodes.
     clustered oriented call invoke the nodes that shares the same service.
        if the service variable state is set. if not, invoke all the nodes.

  some service accessing data may move to the machine where the data is if support the service.

  servicio en browser necesita algo que en el server no existe y no pude dar:
     forward the request to other nodes
     return the result to the browser.
  forward service requests:
     cuando un nodo no puede servir un servicio, puede hacer forward.
        otros nodos puede instalarlo o hacer forward a su vez

  clusterizaci¢n de servicios
   nodo con database saturado puede hacer automatic sharding
     siquientes requests retornan los nuevos nodos
  la resupuesta de un servicio puede incluir una nueva direcci¢n, del nodo donde se ha movido o donde ha delegado.

  servicio wrarpper que ejecuta una libreria no transient

  cat logo de servicios
  ghcjsi service for notebooks

  web site de compilaci¢n que compile en su propio ordenador
     opcion descargar el programa de instalacion y hace stack build
     ventaja: conectar todos los nodos que ejecutan un servicio determinado
       necesario un deposito de nombres de servicios:: github

  friend ident.... request you to install... in your computer. Do you agree?
   if ident is the same, this is automatic.
-}