{-# LANGUAGE TypeOperators, TypeFamilies #-} {-| Module : Tracker Copyright : (c) Kai Lindholm, 2014 License : MIT Maintainer : megantti@gmail.com Stability : experimental For more info on actions, see "Network.RTorrent.Action". -} module Network.RTorrent.Tracker ( TrackerId (..) , TrackerType (..) , TrackerInfo (..) , TrackerAction , getTrackerPartial , getTorrentTrackers , allTrackers -- * Functions dealing with a single variable , getTrackerUrl , getTrackerEnabled , setTrackerEnabled , getTrackerType , getTrackerOpen ) where import Control.Applicative import Control.DeepSeq import Network.RTorrent.Action.Internals import Network.RTorrent.Torrent import Network.RTorrent.Command import Network.XmlRpc.Internals import Data.List.Split (splitOn) data TrackerId = TrackerId !TorrentId !Int deriving Show instance XmlRpcType TrackerId where toValue (TrackerId (TorrentId tid) i) = ValueString $ tid ++ ":t" ++ show i fromValue v = return . uncurry TrackerId =<< parse =<< fromValue v where parse :: Monad m => String -> m (TorrentId, Int) parse str = do [hash, i] <- return $ splitOn ":t" str return (TorrentId hash, read i) getType _ = TString data TrackerType = TrackerHTTP | TrackerUDP | TrackerDHT deriving (Show, Eq) instance Enum TrackerType where toEnum 1 = TrackerHTTP toEnum 2 = TrackerUDP toEnum 3 = TrackerDHT toEnum i = error $ "toEnum :: Int -> TrackerType failed, got : " ++ show i fromEnum TrackerHTTP = 1 fromEnum TrackerUDP = 2 fromEnum TrackerDHT = 3 instance XmlRpcType TrackerType where toValue = toValue . fromEnum fromValue v = return . toEnum =<< check =<< fromValue v where check i | 1 <= i && i <= 3 = return i | otherwise = fail $ "Invalid TrackerType, got : " ++ show i getType _ = TInt instance NFData TrackerType data TrackerInfo = TrackerInfo { trackerUrl :: String , trackerType :: !TrackerType , trackerEnabled :: !Bool , trackerOpen :: !Bool , trackerId :: TrackerId } deriving Show instance NFData TrackerId where rnf (TrackerId tid i) = rnf tid `seq` rnf i instance NFData TrackerInfo where rnf (TrackerInfo a0 a1 a2 a3 a4) = rnf a0 `seq` rnf a1 `seq` rnf a2 `seq` rnf a3 `seq` rnf a4 type TrackerAction = Action TrackerId -- | Run the tracker action on all trackers that a torrent has. allTrackers :: (TrackerId -> TrackerAction a) -> TorrentId -> TorrentAction [TrackerId :*: a] allTrackers t = fmap addId . (getTorrentId <+> allToMulti (allT t)) where addId (hash :*: trackers) = zipWith (\index -> (:*:) (TrackerId hash index)) [0..] trackers allT :: (TrackerId -> TrackerAction a) -> AllAction TrackerId a allT = AllAction (TrackerId (TorrentId "") 0) "t.multicall" getTrackerUrl :: TrackerId -> TrackerAction String getTrackerUrl = simpleAction "t.get_url" [] getTrackerEnabled :: TrackerId -> TrackerAction Bool getTrackerEnabled = fmap toEnum . simpleAction "t.is_enabled" [] setTrackerEnabled :: Bool -> TrackerId -> TrackerAction Int setTrackerEnabled i = simpleAction "t.is_enabled" [PInt (fromEnum i)] getTrackerType :: TrackerId -> TrackerAction TrackerType getTrackerType = simpleAction "t.get_type" [] getTrackerOpen :: TrackerId -> TrackerAction Bool getTrackerOpen = fmap toEnum . simpleAction "t.is_open" [] -- | Get a tracker except for @TrackerId@. The @TrackerId@ can be got by running @allTrackers@. getTrackerPartial :: TrackerId -> TrackerAction (TrackerId -> TrackerInfo) getTrackerPartial = runActionB $ TrackerInfo <$> b getTrackerUrl <*> b getTrackerType <*> b getTrackerEnabled <*> b getTrackerOpen where b = ActionB getTorrentTrackers :: TorrentId -> TorrentAction [TrackerInfo] getTorrentTrackers = fmap (map contract) . allTrackers getTrackerPartial where contract (x :*: f) = f x