From 64be4aa68a3ec03f318ff93af3ce9566795a993a Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 23 Nov 2013 17:29:16 -0500 Subject: [PATCH] Use the round-robin approach to choosing a hostname. Time out the login after 5s if it has not completed. Add some comments. --- src/CommandLine.hs | 2 ++ src/Main.hs | 49 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/CommandLine.hs b/src/CommandLine.hs index 40a1ac8..d710b18 100644 --- a/src/CommandLine.hs +++ b/src/CommandLine.hs @@ -46,6 +46,8 @@ arg_spec = password = def &= typ "PASSWORD" &= help password_help, output_directory = def &= typDir &= help output_directory_help, username = def &= typ "USERNAME" &= help username_help, + -- Using "def" below for the FeedHosts causes the list to show up in + -- reverse. Don't ask me why. feed_hosts = def &= typ "HOSTNAMES" } &= program program_name &= summary my_summary diff --git a/src/Main.hs b/src/Main.hs index 34d775b..415517f 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -6,7 +6,7 @@ where import Control.Concurrent (threadDelay) import Control.Exception.Base (bracket) -import Control.Monad (forever, when) +import Control.Monad (when) import Data.List (isPrefixOf) import Data.Maybe (isNothing) import Data.Monoid ((<>)) @@ -28,6 +28,7 @@ import System.IO ( stderr, stdout ) import System.IO.Error (catchIOError) +import System.Timeout (timeout) import CommandLine (get_args) import Configuration (Configuration(..), merge_optional) @@ -123,19 +124,34 @@ log_in cfg h = do recv_prompt :: Handle -> IO String recv_prompt = recv_chars 10 -connect_and_loop :: Configuration -> IO () -connect_and_loop cfg = +connect_and_loop :: Configuration -> String -> IO () +connect_and_loop cfg host = do + putStrLn $ "Connecting to " ++ host ++ "..." bracket acquire_handle release_handle action + return () where - --acquire_handle = connectTo "feed1.sportsnetwork.com" (PortNumber 4500) - acquire_handle = connectTo "feed2.sportsnetwork.com" (PortNumber 4500) - --acquire_handle = connectTo "127.0.0.1" (PortNumber 13337) + five_seconds :: Int + five_seconds = 5000000 + + acquire_handle = connectTo host (PortNumber 4500) release_handle = hClose action h = do -- No buffering anywhere. hSetBuffering h NoBuffering - log_in cfg h - loop cfg h [] + + -- The feed is often unresponsive after we send out username. It + -- happens in a telnet session, too (albeit less frequently?), + -- so there might be a bug on their end. + -- + -- If we dump the packets with tcpdump, it looks like their + -- software is getting confused: they send us some XML in + -- the middle of the log-in procedure. In any case, the easiest + -- fix is to disconnect and try again. + -- + login_worked <- timeout five_seconds $ log_in cfg h + case login_worked of + Nothing -> putStrLn "Login timed out (5s)." + Just _ -> loop cfg h [] -- | A wrapper around threadDelay which takes seconds instead of @@ -155,6 +171,10 @@ main = do -- prefering the command-line ones. let opt_config = rc_cfg <> cmd_cfg + -- This is necessary because if the user specifies an empty list of + -- hostnames in e.g. the config file, we want to bail rather than + -- fall back on the default list (which gets merged from a + -- Configuration below). when (null $ get_feed_hosts (OC.feed_hosts opt_config)) $ do report_error "ERROR: no feed hosts supplied." exitWith (ExitFailure exit_no_feed_hosts) @@ -174,6 +194,13 @@ main = do hSetBuffering stderr NoBuffering hSetBuffering stdout NoBuffering - forever $ do - catchIOError (connect_and_loop cfg) (report_error . show) - thread_sleep 10 -- Wait 10s before attempting to reconnect. + round_robin cfg 0 + + where + round_robin :: Configuration -> Int -> IO () + round_robin cfg feed_host_idx = do + let hosts = get_feed_hosts $ feed_hosts cfg + let host = hosts !! feed_host_idx + catchIOError (connect_and_loop cfg host) (report_error . show) + thread_sleep 10 -- Wait 10s before attempting to reconnect. + round_robin cfg $ (feed_host_idx + 1) `mod` (length hosts) -- 2.43.2