hoodle-core-0.15: src/Hoodle/Coroutine/Hub/Common.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
-----------------------------------------------------------------------------
-- |
-- Module : Hoodle.Coroutine.Hub.Common
-- Copyright : (c) 2015 Ian-Woo Kim
--
-- License : BSD3
-- Maintainer : Ian-Woo Kim <ianwookim@gmail.com>
-- Stability : experimental
-- Portability : GHC
--
-----------------------------------------------------------------------------
module Hoodle.Coroutine.Hub.Common where
import Control.Applicative
import Control.Monad.IO.Class
import Control.Monad.State
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Resource
import Data.Aeson as AE
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Foldable as F
import Data.IORef
import Data.Monoid ((<>))
import qualified Data.Text as T (Text,pack,unpack)
import Data.Text.Encoding (encodeUtf8)
import Database.Persist (getBy,entityVal)
import Database.Persist.Sqlite (runSqlite)
import Network
import Network.Google.OAuth2 ( formUrl, exchangeCode, refreshTokens
, OAuth2Client(..), OAuth2Tokens(..))
import Network.HTTP.Client (GivesPopper)
import Network.HTTP.Conduit ( CookieJar, Manager
, cookieJar, createCookieJar
, httpLbs, parseUrl
, requestHeaders
, responseBody, responseCookieJar, withManager)
import System.Directory
import System.Exit (ExitCode(..))
import System.Info (os)
import System.Process (rawSystem)
--
--
import Hoodle.Coroutine.Dialog
import Hoodle.Type.Coroutine
import Hoodle.Type.Hub
import Hoodle.Type.Synchronization
--
-- |
streamContent :: BL.ByteString -> GivesPopper ()
streamContent lb np = do
lbref <- newIORef lb
np (popper lbref)
where popper lbref = do
lbstr <- readIORef lbref
if (not .BL.null) lbstr
then do
let (lbstr1,lbstr2) = BL.splitAt 10240 lbstr
writeIORef lbref lbstr2
return (BL.toStrict lbstr1)
else do
return ""
-- |
prepareToken :: HubInfo -> FilePath -> MainCoroutine ()
prepareToken HubInfo {..} tokfile = do
let client = OAuth2Client { clientId = T.unpack googleClientId, clientSecret = T.unpack googleClientSecret }
permissionUrl = formUrl client ["email"]
liftIO $ putStrLn "prepareToken"
liftIO (doesFileExist tokfile) >>= \b -> unless b $ do
case os of
"linux" -> liftIO $ rawSystem "chromium" [permissionUrl]
"darwin" -> liftIO $ rawSystem "open" [permissionUrl]
_ -> return ExitSuccess
mauthcode <- textInputDialog "Please paste the verification code: "
F.forM_ mauthcode $ \authcode -> do
tokens <- liftIO $ exchangeCode client authcode
liftIO $ writeFile tokfile (show tokens)
-- |
withHub :: HubInfo -> FilePath
-> (Manager -> CookieJar -> ResourceT IO a) -> IO a
withHub HubInfo {..} tokfile action =
withSocketsDo $ withManager $ \manager -> do
let client = OAuth2Client { clientId = T.unpack googleClientId
, clientSecret = T.unpack googleClientSecret }
-- refresh token
oldtok <- liftIO $ read <$> (readFile tokfile)
newtok <- liftIO $ refreshTokens client oldtok
liftIO $ writeFile tokfile (show newtok)
--
accessTok <- fmap (accessToken . read) (liftIO (readFile tokfile))
request' <- parseUrl googleAuthURL
let request = request'
{ requestHeaders = [ ("Authorization", encodeUtf8 $ "Bearer " <> T.pack accessTok) ]
, cookieJar = Just (createCookieJar [])
}
response <- httpLbs request manager
let coojar = responseCookieJar response
action manager coojar
sessionGetJSON :: (FromJSON a) =>
String -> ReaderT (Manager,CookieJar) (ResourceT IO) (Maybe a)
sessionGetJSON url = do
(manager,coojar) <- ask
req' <- lift $ parseUrl url
let req = req'
{ requestHeaders = [ ("Accept", "application/json; charset=utf-8") ]
, cookieJar = Just coojar }
res <- lift $ httpLbs req manager
return (AE.decode (responseBody res))
-- |
getLastSyncStatus :: FilePath -> T.Text -> IO (Maybe FileSyncStatus)
getLastSyncStatus fp uuidtxt =
fmap entityVal <$> runSqlite (T.pack fp) (getBy (UniqueFileSyncStatusUUID uuidtxt))