1 {-# LANGUAGE OverloadedStrings #-}
4 import Prelude hiding (log, length, readFile, getContents)
6 import Control.Concurrent (forkIO)
7 import Data.ByteString.Char8 (ByteString, getContents, readFile, unpack)
8 import Network (PortID (PortNumber))
9 import System.Environment (getArgs)
10 import System.Exit (exitSuccess)
11 import System.Directory (doesFileExist)
12 import System.Random (getStdGen, randomRs)
14 import FuncTorrent.Logger (initLogger, logMessage, logStop)
15 import FuncTorrent.Metainfo (Info(..), Metainfo(..), torrentToMetainfo)
16 import FuncTorrent.Peer (handlePeerMsgs)
17 import qualified FuncTorrent.Server as Server
18 import FuncTorrent.Tracker (peers, getTrackerResponse)
20 logError :: String -> (String -> IO ()) -> IO ()
21 logError e logMsg = logMsg $ "parse error: \n" ++ e
27 usage = putStrLn "usage: functorrent torrent-file"
29 parse :: [String] -> IO ByteString
30 parse [] = getContents
32 fileExist <- doesFileExist a
35 else error "file does not exist"
38 -- peer id is exactly 20 bytes long.
39 -- peer id starts with '-', followed by 2 char client id'
40 -- followed by 4 ascii digits for version number, followed by
41 -- a '-'. Rest are random digits to fill the 20 bytes.
45 let digits = randomRs (0, 9) stdgen :: [Integer]
46 return $ "-HS9001-" ++ (concatMap show $ take (20 - 8) digits)
53 let log = logMessage logR
54 log "Starting up functorrent"
55 log $ "Parsing arguments " ++ concat args
56 torrentStr <- parse args
57 case torrentToMetainfo torrentStr of
58 Left e -> logError e log
61 log $ "Downloading file : " ++ p
62 -- if we had downloaded the file before (partly or completely)
63 -- then we should check the current directory for the existence
64 -- of the file and then update the map of each piece' availability.
65 -- This can be donw by reading each piece and verifying the checksum.
66 -- If the checksum does not match, we don't have that piece.
67 log $ "starting server"
68 (serverSock, (PortNumber portnum)) <- Server.start
69 log $ "server started on " ++ show portnum
70 log "Trying to fetch peers"
71 forkIO $ Server.run serverSock peerId m
72 log $ "Trackers: " ++ head (announceList m)
73 trackerResp <- getTrackerResponse portnum peerId m
75 Left e -> log $ "Error" ++ unpack e
77 log $ "Peers List : " ++ (show . peers $ peerList)
78 let p1 = head (peers peerList)
79 handlePeerMsgs p1 peerId m