module Ideas.Encoding.ModeJSON (processJSON) where
import Data.Char
import Ideas.Common.Library hiding (exerciseId)
import Ideas.Common.Utils (Some(..), timedSeconds)
import Ideas.Encoding.DecoderJSON
import Ideas.Encoding.Encoder (makeOptions)
import Ideas.Encoding.EncoderJSON
import Ideas.Encoding.Evaluator
import Ideas.Service.DomainReasoner
import Ideas.Service.Request
import Ideas.Text.JSON
processJSON :: Maybe Int -> Maybe String -> DomainReasoner -> String -> IO (Request, String, String)
processJSON maxTime cgiBin dr input = do
json <- either fail return (parseJSON input)
req <- jsonRequest cgiBin json
resp <- jsonRPC json $ \fun arg ->
maybe id timedSeconds maxTime (myHandler dr req fun arg)
let f = if compactOutput req then compactJSON else show
out = addVersion (version dr) (toJSON resp)
return (req, f out, "application/json")
extractExerciseId :: Monad m => JSON -> m Id
extractExerciseId json =
case json of
String s -> return (newId s)
Array [String _, String _, a@(Array _)] -> extractExerciseId a
Array [String _, String _, _, a@(Array _)] -> extractExerciseId a
Array (String s:tl) | any p s -> extractExerciseId (Array tl)
Array (hd:_) -> extractExerciseId hd
_ -> fail "no code"
where
p c = not (isAlphaNum c || isSpace c || c `elem` ".-")
addVersion :: String -> JSON -> JSON
addVersion str json =
case json of
Object xs -> Object (xs ++ [info])
_ -> json
where
info = ("version", String str)
jsonRequest :: Monad m => Maybe String -> JSON -> m Request
jsonRequest cgiBin json = do
srv <- case lookupM "method" json of
Just (String s) -> return (Just (newId s))
Nothing -> return Nothing
_ -> fail "Invalid method"
let exId = lookupM "params" json >>= extractExerciseId
enc <- case lookupM "encoding" json of
Nothing -> return []
Just (String s) -> readEncoding s
_ -> fail "Invalid encoding"
src <- case lookupM "source" json of
Nothing -> return Nothing
Just (String s) -> return (Just s)
_ -> fail "Invalid source"
let uid = case lookupM "id" json of
Just (String s) -> Just s
Just (Number (I n)) -> Just (show n)
_ -> Nothing
return emptyRequest
{ serviceId = srv
, exerciseId = exId
, user = uid
, source = src
, cgiBinary = cgiBin
, dataformat = JSON
, encoding = enc
}
myHandler :: DomainReasoner -> Request -> RPCHandler
myHandler dr request fun json = do
srv <- findService dr (newId fun)
Some options <- makeOptions dr request
evalService options jsonEvaluator srv json
jsonEvaluator :: Evaluator a JSON JSON
jsonEvaluator = Evaluator jsonDecoder jsonEncoder