{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
module Capabilities(processCaps) where
import Data.Aeson
import Data.Text (Text, pack)
import qualified Data.HashMap.Strict as M
import qualified Data.Vector as V
import Data.Maybe (isJust, mapMaybe, fromMaybe)
import Internal (Timeouts(..))
processCaps :: Maybe Value -> Maybe Object
processCaps caps
| Just (required, fallbacks) <- decodeCaps caps, isJust $ validateCap required =
foldl mergeCaps (Just required) $ mapMaybe validateCap fallbacks
processCaps _ = Nothing
-- Manual decode, to ensure WebDriver specs are followed.
decodeCaps :: Maybe Value -> Maybe (Object, [Object])
decodeCaps (Just (Object obj))
| Just (Object caps) <- "capabilities" `M.lookup` obj,
required <- "alwaysMatch" `M.lookup` caps, fallbacks <- "firstMatch" `M.lookup` caps,
fromMaybe True (isObj <$> required) =
let required' = case required of {
Just (Object o) -> o;
_ -> nilCap
} in case fallbacks of
Just (Array fallbacks') | all isObj fallbacks' ->
Just (required', [f | Object f <- V.toList fallbacks'])
Nothing -> Just (required', [nilCap])
_ -> Nothing
where
isObj (Object _) = True
isObj _ = False
nilCap = M.empty
decodeCaps _ = Nothing
validateCap :: Object -> Maybe Object
validateCap cap
| and [isJust $ inner k v | (k, v) <- M.toList cap, v /= Null] = Just $ M.mapMaybeWithKey inner cap
| otherwise = Nothing
where
inner _ Null = Nothing
inner "acceptInsecureCertificates" v@(Bool _) = Just v -- What's the behavior here?
inner "browserName" v@(String "rhapsode") = Just v
inner "browserVersion" v@(String "5") = Just v
inner "browserVersion" v@(String "4") = Just v
inner "browserVersion" v@(String "3") = Just v
inner "platformName" v@(String _) = Just v -- Rhapsode's very cross-platform.
inner "pageLoadStrategy" v@(String v') | v' `elem` ["none", "eager", "normal"] = Just v -- Noop
-- I don't support "proxy" yet.
inner "timeouts" v | Success Timeouts {} <- fromJSON v = Just v
inner "unhandledPromptBehavior" v@(String v')
| v' `elem` ["dissmiss", "accept", "dismiss and accept", "accept and notify", "ignore"] = Just v -- Noop
inner _ _ = Nothing
mergeCaps :: Maybe Object -> Object -> Maybe Object
mergeCaps (Just primary) secondary | M.null $ M.intersection primary secondary =
Just $ M.union primary secondary