module Twitter.Http where import Network.Curl import System.IO (hPutStrLn, stderr) -- |The API URL of username's timeline. -- -- See, -- -- -- user_timeline_url :: String -> String user_timeline_url username = concat [ "http://api.twitter.com/1/statuses/user_timeline.xml", "?screen_name=" ++ username, "&include_rts=true", "&count=10" ] status_url :: Integer -> String status_url status_id = concat [ "http://api.twitter.com/1/statuses/show/", (show status_id), ".xml" ] -- |Given username's last status id, constructs the API URL for -- username's new statuses. Essentially, 'user_timeline_url' with a -- "since_id" parameter tacked on. user_new_statuses_url :: String -> Integer -> String user_new_statuses_url username last_status_id = concat [ user_timeline_url username, "&since_id=" ++ (show last_status_id) ] get_status :: Integer -> IO (Maybe String) get_status status_id = do let uri = (status_url status_id) status <- (http_get uri) return status -- |Return's username's timeline, or 'Nothing' if there was an error. get_user_timeline :: String -> IO (Maybe String) get_user_timeline username = do let uri = (user_timeline_url username) timeline <- (http_get uri) return timeline -- | Returns the XML representing all of username's statuses that are -- newer than last_status_id. get_user_new_statuses :: String -> Integer -> IO (Maybe String) get_user_new_statuses username last_status_id = do let uri = (user_new_statuses_url username last_status_id) new_statuses <- (http_get uri) return new_statuses -- | Options that will be passed to every curl request. curl_options :: [CurlOption] curl_options = [ CurlTimeout 45, -- The Global cache is not thread-friendly. CurlDNSUseGlobalCache False, -- And we don't want to use a DNS cache anyway. CurlDNSCacheTimeout 0 ] -- | Uses the CURL API to retrieve uri. Returns 'Nothing' if there was -- an error. http_get :: String -> IO (Maybe String) http_get uri = withCurlDo $ do -- Create a Curl instance. curl <- initialize -- Perform the request, and get back a CurlResponse object. -- The cast is needed to specify how we would like our headers -- and body returned (Strings). resp <- do_curl_ curl uri curl_options :: IO CurlResponse -- Pull out the response code as a CurlCode. let code = respCurlCode resp case code of CurlOK -> return $ Just (respBody resp) error_code -> do hPutStrLn stderr ("HTTP Error: " ++ (show error_code)) -- If an error occurred, we want to dump as much information as -- possible. If this becomes a problem, we can use respGetInfo to -- query the response object for more information return Nothing