transient-universe-0.6.0.0: src/Transient/Move/PubSub.hs
{-# LANGUAGE CPP, TypeSynonymInstances,FlexibleInstances #-}
module Transient.Move.PubSub where
import Transient.Base
import Transient.Internals ((!>))
import Transient.Move
import Transient.Move.Utils
import qualified Data.Map as M
import Control.Applicative
import Control.Monad
import Data.List
import Data.Maybe
import Data.IORef
import System.IO.Unsafe
import Control.Monad.IO.Class (liftIO)
import Data.ByteString.Lazy.Char8 (pack, unpack)
import Data.Typeable
#ifndef ghcjs_HOST_OS
import Data.TCache
import Data.TCache.DefaultPersistence
#endif
type Suscribed = M.Map String [Node]
#ifndef ghcjs_HOST_OS
instance Indexable Suscribed where
key _= "#suscribed"
instance Serializable Suscribed where
serialize= pack . show
deserialize= read . unpack
suscribed= getDBRef "#suscribed" :: DBRef Suscribed
atomicModifyDBRef :: DBRef Suscribed -> (Suscribed -> (Suscribed,a)) -> IO a
atomicModifyDBRef ref proc= atomically $ do
x <- readDBRef ref `onNothing` return M.empty
let (r,y) = proc x
writeDBRef ref r
return y
#else
suscribed= undefined
atomicModifyDBRef a b= return ()
#endif
suscribe :: (Typeable a,Loggable a) => String -> Cloud a
suscribe key= do
node <- local getMyNode
local (getMailbox' key) <|> notifySuscribe key node
notifySuscribe key node = atServer (do
localIO $ atomicModifyDBRef suscribed $ \ss -> (insert key [ node] ss,())
susc node)
where
susc node=do
exploreNet $ localIO $ liftIO $ atomicModifyDBRef suscribed $ \ss -> (insert key [node] ss,())
empty
insert h node susc=
let ns = fromMaybe [] $ M.lookup h susc
in M.insert h (union node ns) susc
unsuscribe key withness= do
node <- local getMyNode
local $ deleteMailbox' key withness
atServer $ exploreNet $ localIO $ atomicModifyDBRef suscribed $ \ss -> (delete key [node] ss,())
where
delete h nodes susc=
let ns = fromMaybe [] $ M.lookup h susc
in M.insert h (ns \\ nodes) susc
publish :: (Typeable a, Loggable a) => String -> a -> Cloud ()
publish key dat= do
n <- local getMyNode
publishExclude [n] key dat
where
-- publishExclude :: Loggable a => [Node] -> String -> a -> Cloud ()
publishExclude excnodes key dat= foldPublish (<|>) empty excnodes key $ local $ do
putMailbox' key dat
return () !> "PUTMAILBOX"
empty
return()
-- | executes `proc` in all the nodes suscribed to `key`
foldPublish op init excnodes key proc= atServer $ do
#ifndef ghcjs_HOST_OS
nodes <- localIO $ atomically ((readDBRef suscribed) `onNothing` return M.empty)
>>= return . fromMaybe [] . M.lookup key
#else
nodes <- localIO empty
#endif
let unodes= union nodes excnodes
return() !> ("NODES PUB",nodes \\ excnodes)
foldr op init $ map pub (nodes \\ excnodes)
empty
where
pub node= runAt node $ proc
{-
examples
main = keep $ initNode $ inputNodes <|> (onBrowser $ do
--addWebNode
--local $ optionn ("f" :: String) "fire"
-- crawl the cloud to list all the nodes connected
--r <- exploreNet $ local $ return <$> getMyNode :: Cloud [Node]
--localIO $ print r
--empty
wnode <- local getMyNode
atRemote $ local $ updateConnectionInfo wnode "" >> return ()
r <- suscribe "hello" <|> do
local $ optionn ("f" :: String) "fire"
publish ("hello" ::String) ("world" :: String)
empty
local $ render $ rawHtml $ p (r :: String) )
-}