summaryrefslogtreecommitdiff
path: root/src/Network
diff options
context:
space:
mode:
authorSam Truzjan <pxqr.sta@gmail.com>2014-02-21 02:22:29 +0400
committerSam Truzjan <pxqr.sta@gmail.com>2014-02-21 02:22:29 +0400
commit8c790322bbb09364b38b8667f63511eeb943796b (patch)
tree5411581eae31555d093daf11c140bcc2d0d28057 /src/Network
parentbf3dc8b3b21d267758e429d01c73048dc8be99b5 (diff)
Safely interruptable client initialization
Diffstat (limited to 'src/Network')
-rw-r--r--src/Network/BitTorrent/Client.hs50
-rw-r--r--src/Network/BitTorrent/Client/Types.hs16
2 files changed, 44 insertions, 22 deletions
diff --git a/src/Network/BitTorrent/Client.hs b/src/Network/BitTorrent/Client.hs
index 349283c3..905d3384 100644
--- a/src/Network/BitTorrent/Client.hs
+++ b/src/Network/BitTorrent/Client.hs
@@ -39,10 +39,10 @@ import Control.Exception
39import Control.Concurrent 39import Control.Concurrent
40import Control.Monad.Logger 40import Control.Monad.Logger
41import Control.Monad.Trans 41import Control.Monad.Trans
42import Control.Monad.Trans.Resource
42 43
43import Data.Default 44import Data.Default
44import Data.HashMap.Strict as HM 45import Data.HashMap.Strict as HM
45import Data.Maybe
46import Data.Text 46import Data.Text
47import Network 47import Network
48 48
@@ -86,38 +86,52 @@ exchangeOptions pid Options {..} = Exchange.Options
86connHandler :: MVar (HashMap InfoHash Handle) -> Exchange.Handler 86connHandler :: MVar (HashMap InfoHash Handle) -> Exchange.Handler
87connHandler _tmap = undefined 87connHandler _tmap = undefined
88 88
89newClient :: Options -> LogFun -> IO Client 89initClient :: Options -> LogFun -> ResIO Client
90newClient opts @ Options {..} logger = do 90initClient opts @ Options {..} logFun = do
91 pid <- genPeerId 91 pid <- liftIO genPeerId
92 tmap <- newMVar HM.empty 92 tmap <- liftIO $ newMVar HM.empty
93 tmgr <- Tracker.newManager def (PeerInfo pid Nothing optPort) 93
94 emgr <- Exchange.newManager (exchangeOptions pid opts) (connHandler tmap) 94 let peerInfo = PeerInfo pid Nothing optPort
95 node <- do 95 let mkTracker = Tracker.newManager def peerInfo
96 node <- startNode defaultHandlers def optNodeAddr logger 96 (_, tmgr) <- allocate mkTracker Tracker.closeManager
97 runDHT node $ bootstrap (maybeToList optBootNode) 97
98 return node 98 let mkEx = Exchange.newManager (exchangeOptions pid opts) (connHandler tmap)
99 (_, emgr) <- allocate mkEx Exchange.closeManager
100
101 let mkNode = startNode defaultHandlers def optNodeAddr logFun
102 (_, node) <- allocate mkNode stopNode
103
104 resourceMap <- getInternalState
99 return Client 105 return Client
100 { clientPeerId = pid 106 { clientPeerId = pid
101 , clientListenerPort = optPort 107 , clientListenerPort = optPort
102 , allowedExtensions = toCaps optExtensions 108 , allowedExtensions = toCaps optExtensions
109 , clientResources = resourceMap
103 , trackerManager = tmgr 110 , trackerManager = tmgr
104 , exchangeManager = emgr 111 , exchangeManager = emgr
105 , clientNode = node 112 , clientNode = node
106 , clientTorrents = tmap 113 , clientTorrents = tmap
107 , clientLogger = logger 114 , clientLogger = logFun
108 } 115 }
109 116
117newClient :: Options -> LogFun -> IO Client
118newClient opts logFun = do
119 s <- createInternalState
120 runInternalState (initClient opts logFun) s
121 `onException` closeInternalState s
122
110closeClient :: Client -> IO () 123closeClient :: Client -> IO ()
111closeClient Client {..} = do 124closeClient Client {..} = closeInternalState clientResources
112 Exchange.closeManager exchangeManager
113 Tracker.closeManager trackerManager
114 DHT.stopNode clientNode
115 return ()
116-- closeNode clientNode
117 125
118withClient :: Options -> LogFun -> (Client -> IO a) -> IO a 126withClient :: Options -> LogFun -> (Client -> IO a) -> IO a
119withClient opts lf action = bracket (newClient opts lf) closeClient action 127withClient opts lf action = bracket (newClient opts lf) closeClient action
120 128
129-- do not perform IO in 'initClient', do it in the 'boot'
130--boot :: BitTorrent ()
131--boot = do
132-- Options {..} <- asks options
133-- liftDHT $ bootstrap (maybeToList optBootNode)
134
121-- | Run bittorrent client with default options and log to @stderr@. 135-- | Run bittorrent client with default options and log to @stderr@.
122-- 136--
123-- For testing purposes only. 137-- For testing purposes only.
diff --git a/src/Network/BitTorrent/Client/Types.hs b/src/Network/BitTorrent/Client/Types.hs
index 63971518..c2f79460 100644
--- a/src/Network/BitTorrent/Client/Types.hs
+++ b/src/Network/BitTorrent/Client/Types.hs
@@ -13,6 +13,7 @@ module Network.BitTorrent.Client.Types
13 , MonadBitTorrent (..) 13 , MonadBitTorrent (..)
14 ) where 14 ) where
15 15
16import Control.Applicative
16import Control.Concurrent 17import Control.Concurrent
17import Control.Monad.Logger 18import Control.Monad.Logger
18import Control.Monad.Reader 19import Control.Monad.Reader
@@ -40,6 +41,7 @@ data Client = Client
40 { clientPeerId :: !PeerId 41 { clientPeerId :: !PeerId
41 , clientListenerPort :: !PortNumber 42 , clientListenerPort :: !PortNumber
42 , allowedExtensions :: !Caps 43 , allowedExtensions :: !Caps
44 , clientResources :: !InternalState
43 , trackerManager :: !Tracker.Manager 45 , trackerManager :: !Tracker.Manager
44 , exchangeManager :: !Exchange.Manager 46 , exchangeManager :: !Exchange.Manager
45 , clientNode :: !(Node IPv4) 47 , clientNode :: !(Node IPv4)
@@ -68,8 +70,10 @@ externalAddr Client {..} = PeerAddr
68-----------------------------------------------------------------------} 70-----------------------------------------------------------------------}
69 71
70newtype BitTorrent a = BitTorrent 72newtype BitTorrent a = BitTorrent
71 { unBitTorrent :: ReaderT Client (ResourceT IO) a 73 { unBitTorrent :: ReaderT Client IO a
72 } deriving (Functor, Monad, MonadIO) 74 } deriving ( Functor, Applicative, Monad
75 , MonadIO, MonadThrow, MonadUnsafeIO
76 )
73 77
74class MonadBitTorrent m where 78class MonadBitTorrent m where
75 liftBT :: BitTorrent a -> m a 79 liftBT :: BitTorrent a -> m a
@@ -77,6 +81,11 @@ class MonadBitTorrent m where
77instance MonadBitTorrent BitTorrent where 81instance MonadBitTorrent BitTorrent where
78 liftBT = id 82 liftBT = id
79 83
84instance MonadResource BitTorrent where
85 liftResourceT m = BitTorrent $ do
86 s <- asks clientResources
87 liftIO $ runInternalState m s
88
80instance MonadDHT BitTorrent where 89instance MonadDHT BitTorrent where
81 liftDHT action = BitTorrent $ do 90 liftDHT action = BitTorrent $ do
82 node <- asks clientNode 91 node <- asks clientNode
@@ -88,8 +97,7 @@ instance MonadLogger BitTorrent where
88 liftIO $ logger loc src lvl (toLogStr msg) 97 liftIO $ logger loc src lvl (toLogStr msg)
89 98
90runBitTorrent :: Client -> BitTorrent a -> IO a 99runBitTorrent :: Client -> BitTorrent a -> IO a
91runBitTorrent client action = runResourceT $ 100runBitTorrent client action = runReaderT (unBitTorrent action) client
92 runReaderT (unBitTorrent action) client
93{-# INLINE runBitTorrent #-} 101{-# INLINE runBitTorrent #-}
94 102
95getClient :: BitTorrent Client 103getClient :: BitTorrent Client