Inspired by Don Stewart's article on Scripting with Haskell I tried a rewrite of a shell-script I did the other day. I was really astonished how easily it worked but as a whole it is about double the size of my shell script and some things feel a bit "clumsy".
myReadTile
andgetCurlIP
haveIO
-return type, which seems a bit "unhaskellish"extractIp
andextractFromFile
seem a bit unelegant especially the maybe parts and the trivial case "" to prevent last from throwing an error.
To run my code the packages curl
network-info
had to be installed - the rest was already there (Debian haskell-platform 2012.2.0.0, ghc-7.4.1)
What my code does:
I want to log the IP-address my provider gives me - and when it changes; as I have a dynamic IP. With this information I can ssh from other devices to my home PC, and I know how long the periods are in which my IP doesn't change.
Code
import System.IO (readFile, appendFile)
import System.Exit (exitSuccess)
import System.Directory (doesFileExist, getHomeDirectory)
import Data.Maybe (listToMaybe, fromMaybe)
import Data.Time (getZonedTime)
import Network.BSD (getHostName)
import Network.Curl (curlGetString, URLString, CurlOption(CurlTimeout))
import Network.Curl.Code (CurlCode(CurlOK))
import Network.Info (getNetworkInterfaces, NetworkInterface, name, ipv4)
localFilePath :: FilePath
localFilePath = "/Dropbox/iplog.log"
dyndns :: URLString
dyndns = "http://checkip.dyndns.org"
main :: IO ()
main = do
home <- getHomeDirectory
let iplogFilePath = home ++ localFilePath
iplogS <- myReadFile iplogFilePath
curlS <- getCurlIP dyndns
let oldIP = extractFromFile iplogS
currentIP = extractIp curlS
if oldIP /= currentIP
then do
date <- fmap show getZonedTime
host <- getHostName
localIP <- fmap getLocalIP getNetworkInterfaces
let content = unwords [currentIP, date, host, localIP, "\n"]
appendFile iplogFilePath content
else
exitSuccess
extractFromFile :: String -> String
extractFromFile "" = ""
extractFromFile s = (fromMaybe [] . listToMaybe . words . last . lines) s
extractIp :: String -> String
extractIp "" = ""
extractIp s = (takeWhile (/='<') . last . words) s
myReadFile :: FilePath -> IO String
myReadFile fp = do
iplogExists <- doesFileExist fp
if iplogExists
then
readFile fp
else do
print "File does not exist - and will be created"
print ("at: ~" ++ localFilePath)
return ""
getCurlIP :: URLString -> IO String
getCurlIP url = do
(curlState, curlString) <- curlGetString url [CurlTimeout 60]
if curlState == CurlOK
then
return curlString
else do
print "No external IP found"
return "0.0.0.0"
getLocalIP :: [NetworkInterface] -> String
getLocalIP = show . ipv4 . head . filter (\x -> name x == "eth0")