module Webrexp.JsonNode( JsonNode ) where
import Control.Arrow
import Control.Applicative
import Control.Monad.IO.Class
import Data.Maybe( catMaybes )
import qualified Data.Map as Map
import Network.HTTP
import System.Directory
import Text.JSON.AttoJSON
import qualified Webrexp.ProjectByteString as B
import Webrexp.GraphWalker
import Webrexp.ResourcePath
import Webrexp.UnionNode
import Webrexp.Remote.MimeTypes
type JsonNode = (Maybe String, JSValue)
instance PartialGraph JsonNode ResourcePath where
dummyElem = undefined
isResourceParseable _ _ ParseableJson = True
isResourceParseable _ _ _ = False
parseResource _ ParseableJson binData = (,) Nothing <$> readJSON binData
parseResource _ _ _ = error "Wrong kind of parser used"
instance GraphWalker JsonNode ResourcePath where
accessGraph = loadJson
attribOf attrName (_, JSObject obj) =
valueOf . none <$> Map.lookup (B.pack attrName) obj
where none a = (Nothing :: Maybe String, a)
attribOf _ _ = Nothing
childrenOf (_, JSArray children) =
return $ (,) Nothing <$> children
childrenOf (_, JSObject obj) =
return $ first (Just . B.unpack) <$> Map.assocs obj
childrenOf _ = return []
nameOf (Just s, _) = Just s
nameOf _ = Nothing
indirectLinks n =
catMaybes [ attribOf "href" n >>= importPath
, attribOf "src" n >>= importPath ]
isHistoryMutable _ = False
valueOf (_, JSString s) = B.unpack s
valueOf (_, JSNumber i) = show i
valueOf (_, JSBool b) = show b
valueOf (_, JSArray _) = ""
valueOf (_, JSObject _) = ""
valueOf (_, JSNull) = ""
parseJson :: (MonadIO m)
=> Loggers -> ResourcePath -> B.ByteString
-> m (AccessResult JsonNode ResourcePath)
parseJson (_, errLog, _) datapath file =
case parseJSON file of
Left err -> do liftIO . errLog $ "> JSON Parsing error " ++ err
return AccessError
Right valid -> return $ Result datapath (Nothing, valid)
loadJson :: (MonadIO m)
=> Loggers -> ResourcePath
-> m (AccessResult JsonNode ResourcePath)
loadJson loggers@(logger, _errLog, _verbose) datapath@(Local s) = do
liftIO . logger $ "Opening file : '" ++ s ++ "'"
realFile <- liftIO $ doesFileExist s
if not realFile
then return AccessError
else do file <- liftIO $ B.readFile s
parseJson loggers datapath file
loadJson loggers@(logger, _, verbose) datapath@(Remote uri) = do
liftIO . logger $ "Downloading URL : '" ++ show uri ++ "'"
(u, rsp) <- downloadBinary loggers uri
let contentType = retrieveHeaders HdrContentType rsp
case contentType of
[] -> return AccessError
(hdr:_) ->
do liftIO . verbose $ "Downloaded (" ++ show u ++ ") ["
++ hdrValue hdr ++ "] "
parseJson loggers datapath $ rspBody rsp