haskellhttp-conduithaskeline

calling network IO from within haskeline


I have an existing program which takes command line arguments (username, password, date) and then uses the Network.HTTP.Conduit library to post an xml message to a server. I then parse the results, do some work and use blaze-html to write out to a file.

It all works like a charm; however, I thought I'd use haskeline so that the password isn't visible. I'm able to create a command line program that gets the user-supplied values and prints them out, but if I call the function that uses conduit, it never returns.

Here is the offending code:

main = runInputT defaultSettings loop
where 
    loop :: InputT IO ()
    loop = do
        Just username <- getInputLine "WM username: "
        Just password <- getPassword (Just '*') "WM password: "
        Just date     <- getInputLine "Date (YYYYMMDD): "

        outputStrLn "querying WM..."
        clients <- lift $ getWMClients username password
        outputStrLn "successfully retrieved client list from WM..."

        let outHeader = renderHeader date username

        reportString <- mapM  (\x -> createString x clients)  cList

        lift $ writeFile (date ++ "_report.html") (outHeader ++ concat reportString)
        outputStrLn "Done"

The function getWMClients function is:

getWMClients :: Username -> String -> IO [Client]
getWMClients username password = do
    let f = [Size "-1", Skip "0"]
    let fs = [Select "id",
              Select "status",
              Select "last-name",
              Select "first-name",
             ]
    let query = WMQuery {transaction=SHARE,service=Query,businessObject=CONT,field=f,fields=fs}

    results <- doQuery username (Just password) Nothing (Just query)
    rows <- xmlResultsToMaps results

    let clients = map makeClient rows
    return clients

When I run the program it hangs at "querying WM..." I don't think http-conduit is ever actually running. Any hints on how to make this work?

Thanks in advance, Neil


Solution

  • You claim it worked with hard-coded username, password, date before haskeline. To help debug, perhaps you could not lift the conduit into InputT. Does the following still fail? (I did not compile this, so feel free to fix the syntax errors...)

    -- Isolate the haskeline monad to just the input part:
    main = loop
    where 
        loop :: IO ()
        loop = do
          (username,password,date) <- runInputT defaultSettings $ do
            Just username <- getInputLine "WM username: "
            Just password <- getPassword (Just '*') "WM password: "
            Just date     <- getInputLine "Date (YYYYMMDD): "
            return (username,password,date)
    
          putStrLn "querying WM..."
          clients <- getWMClients username password
          putStrLn "successfully retrieved client list from WM..."
    
          let outHeader = renderHeader date username
    
          putString <- mapM  (\x -> createString x clients)  cList
    
          writeFile (date ++ "_report.html") (outHeader ++ concat reportString)
          putStrLn "Done"