packages feed

transient-universe 0.3.2.1 → 0.3.2.2

raw patch · 4 files changed

+109/−121 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Transient.Move: callNodes :: (Typeable * a1, Typeable * a, Show a1, Show a, Read a1, Read a) => (Cloud a1 -> Cloud a -> Cloud a) -> Cloud a -> Cloud a1 -> Cloud a
+ Transient.Move.Services: after :: (Typeable * a, Show a, Read a) => Cloud a -> Cloud a -> Cloud a
- Transient.Move: createNode :: HostName -> Integer -> Node
+ Transient.Move: createNode :: HostName -> Integer -> IO Node
- Transient.Move: createNodeServ :: HostName -> Integer -> [Service] -> Node
+ Transient.Move: createNodeServ :: HostName -> Integer -> [Service] -> IO Node
- Transient.Move: createWebNode :: Node
+ Transient.Move: createWebNode :: IO Node
- Transient.Move: defConnection :: Int -> Connection
+ Transient.Move: defConnection :: MonadIO m => m Connection
- Transient.Move.Services: callOne :: (Node -> Cloud [Node]) -> Cloud [Node]
+ Transient.Move.Services: callOne :: Loggable a => Cloud a -> Cloud a

Files

src/Transient/Move.hs view
@@ -18,18 +18,23 @@ Cloud(..),runCloudIO, runCloudIO',local,onAll,lazy, loggedc, lliftIO,localIO,
 listen, Transient.Move.connect, connect', fullStop,
 
+-- * primitives for communication
 wormhole, teleport, copyData,
 
+-- * single node invocation
 beamTo, forkTo, streamFrom, callTo, runAt, atRemote,
 
-clustered, mclustered,
+-- * invocation of many nodes
+clustered, mclustered, callNodes,
 
+-- * messaging
 newMailbox, putMailbox,getMailbox,cleanMailbox,
 
 #ifndef ghcjs_HOST_OS
 setBuffSize, getBuffSize,
 #endif
 
+-- * node management
 createNode, createWebNode, createNodeServ, getMyNode, getNodes,
 addNodes, shuffleNodes,
 
@@ -444,7 +449,7 @@    if not rec                                    --  !> ("wormhole recovery", rec)
             then runTrans $ (do
 
-                    conn <-  mconnect node       --  !> (mynode,"connecting node ",  node)
+                    conn <-  mconnect node         -- !> (mynode,"connecting node ",  node)
                     setData  conn{calling= True}
 #ifdef ghcjs_HOST_OS
                     addPrefix    -- for the DOM identifiers
@@ -571,7 +576,7 @@ 
 mconnect :: Node -> TransIO  Connection
 mconnect  node@(Node _ _ _ _ )=  do
-  nodes <- getNodes
+  nodes <- getNodes                                 --  !> ("connecting node", node)
 
   let fnode =  filter (==node) nodes
   case fnode of
@@ -583,7 +588,7 @@     case plist  of
       handle:_ -> do
                   delData $ Closure undefined
-                  return  handle                        -- !>   "REUSED!"
+                  return  handle                       --  !>   ("REUSED!", node)
 
       _ -> do
 --        liftIO $ putStr "*****CONNECTING NODE: " >> print node
@@ -594,9 +599,10 @@ 
         conn <- liftIO $ do
           let size=8192
-          sock <-  connectTo' size  host $ PortNumber $ fromIntegral port  --   !> ("CONNECTING ",node)
+          sock <-  connectTo' size  host $ PortNumber $ fromIntegral port
+                      -- !> ("CONNECTING ",port)
 
-          let conn= (defConnection 8100){myNode=my,comEvent= ev,connData= Just $ Node2Node u  sock (error $ "addr: outgoing connection")}
+          conn <- defConnection >>= \c -> return c{myNode=my,comEvent= ev,connData= Just $ Node2Node u  sock (error $ "addr: outgoing connection")}
 
           SBS.send sock "CLOS a b\n\n"   -- !> "sending CLOS"
 
@@ -607,7 +613,7 @@         conn <- do
 
           ws <- connectToWS host $ PortNumber $ fromIntegral port
-          let conn= (defConnection 8100){comEvent= ev,connData= Just $ Web2Node ws}
+          conn <- defConnection >>= \c -> return c{comEvent= ev,connData= Just $ Web2Node ws}
 
           return conn    -- !>  ("websocker CONNECION")
 #endif
@@ -693,18 +699,6 @@ newMailbox name= do
 --   return ()  -- !> "newMailBox"
    Connection{comEvent= mv} <- getData `onNothing` errorMailBox
---   onFinish . const $ liftIO $ do
-----         return ()                        --  !> "NEWMAILBOX finish"
---         mailboxes <- readIORef mv
---         let me = M.lookup name  mailboxes
---         case me of
---             Nothing -> empty             -- !> "EMPTY"
---             Just (EVar id rn ref1) -> do
---                 n <- atomically $ do
---                      (n,n') <- readTVar rn
---                      writeTVar rn (n-1,n'-1)        -- !> ("decreased rn",n-1)
---                      return $ n-1
---                 when (n==0) $ atomicModifyIORef mv $ \mboxes -> (M.delete name mboxes,())
    ev <- newEVar
    liftIO $ atomicModifyIORef mv $ \mailboxes ->   (M.insert name ev mailboxes,())
 
@@ -738,45 +732,6 @@              Nothing -> empty
              Just x -> return x
 
---getMailBox :: Typeable a => String -> TransIO a
---getMailBox name= Transient $ do
---     return () !> "getMailBox"
---     Connection{comEvent=(EVar id rn ref1)} <- getData `onNothing` error "getMailBox: accessing network events out of listen"
---     runTrans  $ do
---         liftIO $ atomically $ readTVar rn >>= \(n,n') -> writeTVar rn (n +1,n'+1)
---         r <- parallel $  do
---                  n' <- atomically $ do
---                              (n,n') <- readTVar rn
---                              writeTVar rn $ if n' > 1 then   (n,n'-1) else (n, n)
---                              return n'
---                  return () !> ("rear rn",name,n')
---                  atomically $ do
---                    d <- if n'> 1 then  peekTChan ref1 else readTChan ref1
---
---
---                    return () !> ("readmailbox",name,n')
---                    case d of
---                        SDone -> return SDone
---                        SMore x ->  case fromDynamic x of
---                              Nothing -> return $ SMore Nothing
---                              Just (nam, Nothing) -> do
---                                readTVar rn >>= \(n,n') -> writeTVar rn $ (n,n' -1)
---                                return SDone
---                              Just (nam,Just dat) ->
---                                return $ SMore $  if nam /= name then  Nothing else Just dat
-----                        SLast x -> case fromDynamic x of
-----                              Nothing -> retry
-----                              Just (nam, Nothing) -> return SDone
-----                              Just (nam,Just dat) ->
-----                                if nam /= name !>(nam,name) then retry else return $ SLast dat
---                        SError e -> return $ SError e
---
---         case r of
---            SDone -> empty
---            SMore Nothing -> empty
---            SMore (Just x) -> return x
---            SLast (Just x) -> return x
---            SError e -> error $ show e
 
 -- | delete all subscriptions for that mailbox expecting this kind of data.
 cleanMailbox :: Typeable a =>  T.Text ->  a -> TransIO ()
@@ -793,21 +748,22 @@ 
 
 
-defConnection :: Int -> Connection
+defConnection :: MonadIO m => m Connection
 
 -- #ifndef ghcjs_HOST_OS
-defConnection size=
-  Connection (createNode "program" 0) Nothing  size
+defConnection = liftIO $ do
+  x <- newMVar ()
+  y <- newMVar M.empty
+  return $ Connection (error "node in default connection") Nothing  8192
                  (error "defConnection: accessing network events out of listen")
-                 (unsafePerformIO $ newMVar ())
-                 False (unsafePerformIO $ newMVar M.empty)
+                 x  False (y)
 
 
 
 #ifndef ghcjs_HOST_OS
 setBuffSize :: Int -> TransIO ()
 setBuffSize size= Transient $ do
-   conn<- getData `onNothing` return (defConnection 8192)
+   conn<- getData `onNothing`  defConnection
    setData $ conn{bufferSize= size}
    return $ Just ()
 
@@ -823,7 +779,7 @@ 
    setData $ Log False [] []
 
-   conn' <- getSData <|> return (defConnection 8192)
+   conn' <- getSData <|> defConnection
    ev <- liftIO $ newIORef M.empty
    let conn= conn'{myNode=node, comEvent=ev}
 
@@ -836,7 +792,7 @@ 
 
 
-listenNew port conn= do --  node bufSize events blocked port= do
+listenNew port conn= do
 
 
    sock <- liftIO . listenOn  $ PortNumber port
@@ -856,7 +812,7 @@ 
    initFinish
    onFinish $ const $ do
-             return()                                 -- !> "onFinish closures receivedd with LISTEN"
+--             return()                   !> "onFinish closures receivedd with LISTEN"
              let Connection{closures=closures}= conn  -- !> "listenNew closures empty"
              liftIO $ modifyMVar_ closures $ const $ return M.empty
 
@@ -990,18 +946,21 @@ emptyPool= liftIO $ newMVar  []
 
 
-createNodeServ :: HostName -> Integer -> [Service] -> Node
-createNodeServ h p svs= Node h ( fromInteger p) (unsafePerformIO emptyPool) svs
+createNodeServ ::  HostName -> Integer -> [Service] -> IO Node
+createNodeServ h p svs= do
+    pool <- emptyPool
+    return $ Node h ( fromInteger p) pool svs
 
 
 
 
-createNode :: HostName -> Integer -> Node
+createNode :: HostName -> Integer -> IO Node
 createNode h p= createNodeServ h p []
 
-createWebNode :: Node
-createWebNode= Node "webnode" ( fromInteger 0) (unsafePerformIO emptyPool)
-                      [("webnode","")]
+createWebNode :: IO Node
+createWebNode= do
+  pool <- emptyPool
+  return $ Node "webnode" ( fromInteger 0) pool  [("webnode","")]
 
 
 instance Eq Node where
@@ -1153,10 +1112,10 @@ -- | synchronize the list of nodes with a remote node and all the nodes connected to it
 -- the final effect is that all the nodes reachable share the same list of nodes
 connect'  remotenode= do
-    nodes <- local $ getNodes
+    nodes <- local getNodes
     local $ liftIO $ putStrLn $ "connecting to: "++ show remotenode
 
-    newNodes <- runAt remotenode $  do
+    newNodes <- runAt remotenode $ do
            local $ do
               conn@(Connection _(Just (Node2Node _ _ _)) _ _ _ _ _) <- getSData <|>
                error ("connect': need to be connected to a node: use wormhole/connect/listen")
src/Transient/Move/Services.hs view
@@ -56,10 +56,11 @@ 
 install :: String  -> String -> Int -> Cloud ()
 install package program port =  do
+     exist <- localIO $ findExecutable program -- liftIO $ doesDirectoryExist  packagename
      let packagename = name package
-     when (null packagename) $ error $ "source for \""++package ++ "\" not found"
-     exist <- local $ liftIO $ doesDirectoryExist  packagename
-     when (not exist) $ local $ liftIO $ do
+     when (isNothing exist) $ local $ liftIO $ do
+
+         when (null packagename) $ error $ "source for \""++package ++ "\" not found"
          callProcess  "git" ["clone",package]
          liftIO $ putStr package >> putStrLn " cloned"
          setCurrentDirectory packagename
@@ -68,7 +69,7 @@          return()
      let prog = pathExe packagename program port
      lliftIO $ print $ "executing "++ prog
-     local  $ (async $ do createProcess $ shell prog ; return ()) <|> return ()
+     localIO $ do createProcess $ shell prog ; return ()  -- ) <|> return ()
 
 
      return() -- !> "INSTALLED"
@@ -88,35 +89,44 @@ initService ident service@(package, program)= loggedc $ do
     nodes <- local getNodes
     case find (\node  -> service `elem` nodeServices node) nodes  of
-       Just node -> return node
+       Just node -> return node                 -- !> "found"
        Nothing -> do
 
-          nodes <- callOne $ \thisNode -> do
+          node <- runAt (head nodes)  $ do
+                    thisNode <- local getMyNode
                     yn<- requestService ident service
-                    if yn then do
+                    if yn   then do
                         port <- onAll freePort
+                        localIO $ putStr "installing " >> putStrLn package
                         install package program  port
                         nodeService thisNode port
                       else empty
-          local $ addNodes nodes
-          return $ head nodes   -- !> ("GENERATED NODE", nodes)
+          local $ addNodes [node]
+          return node
     where
-    nodeService (Node h _ _ _) port= local $
-       return [Node h port (unsafePerformIO $ newMVar []) [service] ]  -- !> (thisNode,port)
-
+    nodeService (Node h _ _ _) port= localIO $ do
+       pool <- newMVar []
+       return $ Node h port pool [service]
 
+callOne :: Loggable a =>  Cloud a ->  Cloud a
+callOne = callNodes after empty
 
-callOne mx= callNodes' (<>) empty mx
- where
+after mx my= waitone mx <|> my
+  where
+  waitone mx = local $ do
+       rs <- collect' 1 1 0 $ runCloud mx
+       return $ head rs
 
- callNodes' op init proc= loggedc $ do
-    nodes <-  local getNodes
-    let nodes' = filter (not . isWebNode) nodes
-    foldr op init $ map (\node -> runAt node $ proc node) nodes'  :: Cloud [Node]
-    where
-    isWebNode Node {nodeServices=srvs}
-         | ("webnode","") `elem` srvs = True
-         | otherwise = False
+-- where
+--
+-- callNodes' op init proc= loggedc $ do
+--    nodes <-  local getNodes
+--    let nodes' = filter (not . isWebNode) nodes
+--    foldr op init $ map (\node -> runAt node $ proc node) nodes'  :: Cloud [Node]
+--    where
+--    isWebNode Node {nodeServices=srvs}
+--         | ("webnode","") `elem` srvs = True
+--         | otherwise = False
 
 
 rfriends        =   unsafePerformIO $ newMVar []
@@ -143,8 +153,10 @@     :: (Loggable a, Loggable b)
     => String -> Service -> a  -> Cloud b
 callService ident service params = do
+
     node <-  initService ident service
-    localIO $ print node
+
+
     log <- onAll $ do
            log  <- getSData <|> return emptyLog
            setData emptyLog
@@ -155,12 +167,10 @@ 
              teleport
              local empty
---    return () !> ("r=",r)
+
     restoreLog log
---    local $ do
---       Log _ _ log <- getSData <|> return emptyLog
---       return() !> ("log after",log)
-    return  r -- (r `asTypeOf` witness)
+
+    return  r
     where
     restoreLog (Log _ _ logw)= onAll $ do
        Log _ _ logw' <- getSData <|> return emptyLog
@@ -175,8 +185,10 @@ 
 runEmbeddedService :: (Loggable a, Loggable b) =>  Service -> (a -> Cloud b) -> Cloud b
 runEmbeddedService servname serv =  do
-   port <- lliftIO $ freePort
-   listen $ createNodeServ "localhost" (fromIntegral port) [servname]
+   node <- localIO $ do
+          port <- freePort
+          createNodeServ "localhost" (fromIntegral port) [servname]
+   listen node
    wormhole notused $ loggedc $ do
       x <- local $ return notused
       r <- onAll $ runCloud (serv x) <** setData WasRemote
@@ -202,7 +214,7 @@    initNodeServ servs=do
       mynode <- local $ do
         port <-  getPort
-        return $ createNodeServ "localhost" port servs
+        liftIO $ createNodeServ "localhost" port servs
 
       listen mynode -- <|> return()
       where
@@ -210,6 +222,21 @@       getPort =  if isBrowserInstance then return 0 else do
           oneThread $ option "start" "re/start node"
           input (const True) "port to listen? "
+
+{- |
+a service called monitor:
+  runService
+  receive request for a service.
+  check service in list
+  if executing return node
+  when not installed install
+  execute
+  return node
+-}
+--localServiceMonitor ident service = keep $ runCloud  $
+--    runService ("https://github.com/agocorona/transient-universe","monitor") $ do
+--       initService ident service
+
 
 
 
src/Transient/Move/Utils.hs view
@@ -48,20 +48,20 @@ --
 -- To translate the code from the browser to the server node, use `teleport`.
 --
-
+initNode :: Cloud () -> TransIO ()
 initNode app= do
-   node <- getPort
+   node <- getNodeParams
    initWebApp node  app
 
 
   where
-  getPort :: TransIO Node
-  getPort =
-      if isBrowserInstance then return createWebNode else do
+  getNodeParams  :: TransIO Node
+  getNodeParams  =
+      if isBrowserInstance then  liftIO createWebNode else do
           oneThread $ option "start" "re/start node"
           host <- input (const True) "hostname of this node (must be reachable): "
           port <- input (const True) "port to listen? "
-          return $ createNode host port
+          liftIO $ createNode host port
 
 -- | ask for nodes to be added to the list of known nodes. it also ask to connect to the node to get
 -- his list of known nodes
@@ -76,7 +76,7 @@           port <-  local $ input (const True) "port?"
 
           connectit <- local $ input (\x -> x=="y" || x== "n") "connect to get his list of nodes?"
-          let nnode= createNode host port
+          nnode <- localIO $ createNode host port
           if connectit== "y" then connect'  nnode
                              else local $ addNodes [nnode]
    empty
@@ -100,19 +100,21 @@ --
 --
 simpleWebApp :: Integer -> Cloud () -> IO ()
-simpleWebApp port app =  keep $ initWebApp (createNode "localhost" port) app
+simpleWebApp port app = do
+   node <- createNode "localhost" port
+   keep $ initWebApp node app
 
 -- | use this instead of smpleWebApp when you have to do some initializations in the server prior to the
 -- initialization of the web server
 initWebApp :: Node -> Cloud () -> TransIO ()
 initWebApp node app=  do
-    let conn= defConnection 8192
+    conn <- defConnection
     setData  conn{myNode = node}
-    serverNode  <-  getWebServerNode  :: TransIO Node
+    serverNode  <-   getWebServerNode  :: TransIO Node
 
-    let mynode = if isBrowserInstance
-                    then createWebNode
-                    else serverNode
+    mynode <- if isBrowserInstance
+                    then liftIO $ createWebNode
+                    else return serverNode
 
     runCloud $ do
         listen mynode <|> return()
@@ -135,6 +137,6 @@ -- | run N nodes (N ports to listen) in the same program. For testing purposes.
 -- It add them to the list of known nodes, so it is possible to perform `clustered` operations with them.
 runTestNodes ports= do
-    let nodes=  map (\p -> createNode "localhost" p) ports
+    nodes <- onAll $  mapM (\p -> liftIO $ createNode "localhost" p) ports
     foldl (<|>) empty (map listen nodes) <|> return()
 
transient-universe.cabal view
@@ -1,5 +1,5 @@ name: transient-universe
-version: 0.3.2.1
+version: 0.3.2.2
 cabal-version: >=1.10
 build-type: Simple
 license: MIT