module Web.Tweet
( tweet
, signRequest
, urlString
) where
import Data.Aeson
import GHC.Generics
import Network.HTTP.Client
import Network.HTTP.Client.TLS
import Network.HTTP.Types.Status (statusCode)
import Web.Authenticate.OAuth
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as BSL
import Data.Char (toLower)
data Tweet = Tweet
{ status :: String
, trim_user :: Bool
} deriving Generic
instance ToJSON Tweet where
tweet :: FilePath -> BS.ByteString -> IO ()
tweet filepath content = do
requestString <- urlString content
manager <- newManager tlsManagerSettings
initialRequest <- parseRequest ("https://api.twitter.com/1.1/statuses/update.json" ++ requestString)
request <- signRequest filepath $ initialRequest { method = "POST" }
response request manager
response :: Request -> Manager -> IO ()
response request manager = do
response <- httpLbs request manager
putStrLn $ "The status code was: " ++ show (statusCode $ responseStatus response)
BSL.putStrLn $ responseBody response
signRequest :: FilePath -> Request -> IO Request
signRequest filepath req = do
o <- oAuth filepath
c <- credential filepath
signOAuth o c req
oAuth :: FilePath -> IO OAuth
oAuth filepath = do
secret <- (lineByKey "api-sec") <$> getConfigData filepath
key <- (lineByKey "api-key") <$> getConfigData filepath
let url = "api.twitter.com"
return newOAuth { oauthConsumerKey = key , oauthConsumerSecret = secret , oauthServerName = url }
credential :: FilePath -> IO Credential
credential filepath = newCredential <$> token <*> secretToken
where token = (lineByKey "tok") <$> getConfigData filepath
secretToken = (lineByKey "tok-sec") <$> getConfigData filepath
lineByKey :: BS.ByteString -> [(BS.ByteString, BS.ByteString)] -> BS.ByteString
lineByKey key = snd . head . (filter (\i -> fst i == key))
getConfigData :: FilePath -> IO [(BS.ByteString, BS.ByteString)]
getConfigData filepath = zip <$> keys <*> content
where content = (map (BS.pack . filterLine)) . lines <$> file
keys = (map (BS.pack . keyLine)) . lines <$> file
file = readFile filepath
keyLine :: String -> String
keyLine = takeWhile (/=':')
filterLine :: String -> String
filterLine = reverse . (takeWhile (not . (`elem` (" :" :: String)))) . reverse
urlString :: BS.ByteString -> IO String
urlString content = do
return $ "?status=" ++ ((BS.unpack . paramEncode) content) ++ "&trim_user" ++ (map toLower $ show True)