irc-dcc 1.1.0 → 1.2.0
raw patch · 5 files changed
+43/−34 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Network.IRC.DCC.FileTransfer: acceptFile :: Integral a => OfferFile -> (PortNumber -> ExceptT String IO ()) -> (a -> IO ()) -> ExceptT String IO ()
+ Network.IRC.DCC.FileTransfer: acceptFile :: Integral a => OfferFile -> (PortNumber -> ExceptT String IO ()) -> (a -> IO ()) -> ReaderT (Maybe PortNumber) (ExceptT String IO) ()
- Network.IRC.DCC.FileTransfer: resumeFile :: Integral a => AcceptResumeFile -> (PortNumber -> ExceptT String IO ()) -> (a -> IO ()) -> ExceptT String IO ()
+ Network.IRC.DCC.FileTransfer: resumeFile :: Integral a => AcceptResumeFile -> (PortNumber -> ExceptT String IO ()) -> (a -> IO ()) -> ReaderT (Maybe PortNumber) (ExceptT String IO) ()
Files
- irc-dcc.cabal +1/−1
- src/Network/IRC/DCC/FileTransfer.hs +15/−9
- src/Network/Socket/ByteString/Extended.hs +18/−9
- tests/Main.hs +2/−5
- tests/Network/IRC/DCCTest.hs +7/−10
irc-dcc.cabal view
@@ -1,5 +1,5 @@ name: irc-dcc-version: 1.1.0+version: 1.2.0 synopsis: A DCC message parsing and helper library for IRC clients description: DCC (Direct Client-to-Client) is an IRC sub-protocol for establishing and maintaining direct connections to
src/Network/IRC/DCC/FileTransfer.hs view
@@ -13,6 +13,8 @@ import Control.Error import Control.Monad (unless)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Reader (ReaderT, ask) import Data.ByteString.Char8 (ByteString, length, null) import Network.Socket.ByteString.Extended import Path (File, Path, Rel,@@ -29,7 +31,7 @@ -- ^ Callback when socket is ready -> (a -> IO ()) -- ^ Callback when a chunk of data was transfered- -> ExceptT String IO ()+ -> ReaderT (Maybe PortNumber) (ExceptT String IO) () acceptFile (OfferFile tt f) = download (fileName f) WriteMode 0 tt @@ -40,7 +42,7 @@ -- ^ Callback when socket is ready -> (a -> IO ()) -- ^ Callback when a chunk of data was transfered- -> ExceptT String IO ()+ -> ReaderT (Maybe PortNumber) (ExceptT String IO) () resumeFile (AcceptResumeFile tt f pos) = download (fileName f) AppendMode (fromIntegral pos) tt @@ -50,14 +52,18 @@ -> a -> TransferType -> (PortNumber -> ExceptT String IO ())+ -- ^ Callback when socket is ready -> (a -> IO ())- -> ExceptT String IO ()-download fn mode pos tt onListen onChunk =- withSocket tt onListen $- toFile (fromRelFile fn) . stream pos onChunk- where withSocket (Active i p) = withActiveSocket i p- withSocket (Passive i _) = withPassiveSocket i- toFile f = withFileAsOutputExt f mode NoBuffering+ -- ^ Callback when a chunk of data was transfered+ -> ReaderT (Maybe PortNumber) (ExceptT String IO) ()+download fn mode pos tt onListen onChunk = do+ localPort <- ask+ lift $+ withSocket tt localPort onListen $+ withFileAsOutputExt (fromRelFile fn) mode NoBuffering .+ stream pos onChunk+ where withSocket (Active i p) _ = withActiveSocket (Sink i p)+ withSocket (Passive i _) p = withPassiveSocket (Source i p) stream :: Integral a => a
src/Network/Socket/ByteString/Extended.hs view
@@ -2,6 +2,8 @@ module Network.Socket.ByteString.Extended ( module Network.Socket , module Network.Socket.ByteString+ , Sink(..)+ , Source(..) , withActiveSocket , withPassiveSocket , toNetworkByteOrder@@ -19,15 +21,18 @@ import Network.Socket.ByteString import System.Timeout +data Sink = Sink IPv4 PortNumber++data Source = Source IPv4 (Maybe PortNumber)+ -- | Run functions on socket when connected and close socket afterwards-withActiveSocket :: IPv4- -> PortNumber+withActiveSocket :: Sink -> (PortNumber -> ExceptT String IO ()) -- ^ Callback when socket is ready -> (Socket -> IO ()) -- ^ Callback when socket is connected to server -> ExceptT String IO ()-withActiveSocket i p onListen onConnected = do+withActiveSocket (Sink i p) onListen onConnected = do liftIO $ return withSocketsDo sock <- liftIO $ socket AF_INET Stream defaultProtocol onListen p@@ -38,17 +43,15 @@ {- | Run functions on passive socket when listening and when connected and close socket afterwards. -}-withPassiveSocket :: IPv4+withPassiveSocket :: Source -> (PortNumber -> ExceptT String IO ()) -- ^ Callback when socket is open and listening -> (Socket -> IO ()) -- ^ Callback when client connected to socket -> ExceptT String IO ()-withPassiveSocket i onListen onConnected = do+withPassiveSocket (Source i maybeP) onListen onConnected = do liftIO $ return withSocketsDo- sock <- liftIO $ socket AF_INET Stream defaultProtocol- liftIO $ bind sock (SockAddrInet aNY_PORT iNADDR_ANY)- liftIO $ listen sock 1+ sock <- liftIO $ openListenSocket (fromMaybe aNY_PORT maybeP) p <- liftIO $ socketPort sock onListen p accepted <- liftIO $ timeout 10000000 $ accept sock@@ -60,10 +63,16 @@ throwE ( "Expected connection from host " ++ show (fromHostAddress client) ++ ", not from " ++ show i ++". Aborting…\n" )- _ -> throwE ( "Timeout when waiting for other party to connect on port " ++ show p ++ "…\n") liftIO $ sClose sock++openListenSocket :: PortNumber -> IO Socket+openListenSocket p = do+ sock <- socket AF_INET Stream defaultProtocol+ bind sock (SockAddrInet p iNADDR_ANY)+ listen sock 1+ return sock -- | Converts numbers to a '32bit unsigned int' in network byte order. toNetworkByteOrder :: Integral a => a -> ByteString
tests/Main.hs view
@@ -2,9 +2,6 @@ import qualified Network.IRC.DCCTest as DCC import Test.Tasty-import Test.Tasty.Hspec -main = tests--tests :: IO ()-tests = DCC.spec >>= defaultMain+main :: IO ()+main = DCC.spec >>= defaultMain
tests/Network/IRC/DCCTest.hs view
@@ -4,18 +4,15 @@ import Network.IRC.DCC.Internal -import Data.Attoparsec.ByteString.Char8 (IResult (Done, Fail), Parser,- endOfInput, maybeResult,- parse)-import Data.ByteString.Char8 (pack)-import qualified Data.ByteString.UTF8 as UTF8 (fromString)-import Data.IP (IPv4, toIPv4)-import Path (mkRelFile)+import Data.ByteString.Char8 (pack)+import qualified Data.ByteString.UTF8 as UTF8 (fromString)+import Data.IP (toIPv4)+import Path (mkRelFile) import Test.Hspec.Attoparsec-import Test.Tasty (testGroup)-import Test.Tasty.Hspec (SpecWith, describe, it,- testSpec)+import Test.Tasty (TestTree)+import Test.Tasty.Hspec (describe, it, testSpec) +spec :: IO TestTree spec = testSpec "DCC message serialization" $ describe "Parsing single elements" $ do