module Web.Groonga.Server where import Web.Scotty import Network.HTTP.Types import Data.Monoid (mconcat) import Bindings.Groonga.Raw (C'_grn_ctx) import qualified Bindings.Groonga.CommandAPI as Groonga import qualified Data.Text.Lazy as L import Control.Monad.IO.Class (liftIO) import Foreign.Ptr (Ptr) import Network.Wai.Middleware.RequestLogger (logStdoutDev) import System.Directory #if !MIN_VERSION_time(1,5,0) import Data.Time import System.Locale #else import Data.Time hiding (TimeLocale) import System.Locale hiding (defaultTimeLocale) #endif import Control.Applicative ((<$>)) type GrnCtx = Ptr C'_grn_ctx db :: String -> IO () db dbpath = do ctx <- Groonga.grn_ctx_init create_db_if_needed ctx dbpath create_db_if_needed :: GrnCtx -> String -> IO () create_db_if_needed ctx dbpath = do result <- doesFileExist dbpath if result then putStrLn $ "Skip create database. Already exists " ++ dbpath ++ "." else do _ <- Groonga.grn_database_create ctx dbpath return () _ <- Groonga.grn_ctx_fin ctx return () app :: String -> ScottyM () app dbpath = do middleware logStdoutDev get "/version" $ do start_at <- liftIO $ get_current_time_as_double ver <- get_groonga_version done_at <- liftIO $ get_current_time_as_double let buf = concat ["{\"Groonga Version\": \"", (L.unpack ver), "\"}"] let response = format_response 0 start_at done_at buf text $ L.pack response set_json_header get "/d/" $ do start_at <- liftIO $ get_current_time_as_double done_at <- liftIO $ get_current_time_as_double let errbuf = "empty param." let response = format_err_response (-1) start_at done_at errbuf text $ L.pack response status internalServerError500 set_json_header get (regex "^/d/(.*)$") $ do command <- param "1" response <- send_groonga_command $ L.unpack command case response of Left res -> do text $ L.pack res status internalServerError500 set_json_header Right res -> do text $ L.pack res set_json_header notFound $ do status notFound404 set_json_header where get_groonga_version :: ActionM L.Text get_groonga_version = liftIO $ do version <- Groonga.grn_get_version return (L.pack version) send_groonga_command :: String -> ActionM (Either String String) send_groonga_command command = liftIO $ do ctx <- Groonga.grn_ctx_init _ <- Groonga.grn_database_open ctx dbpath start_at <- get_current_time_as_double response <- Groonga.grn_execute_command ctx command done_at <- get_current_time_as_double errbuf <- Groonga.grn_get_errbuf ctx _ <- Groonga.grn_ctx_fin ctx if length errbuf > 0 then return $ Left $ format_err_response (-1) start_at done_at errbuf else return $ Right $ format_response 0 start_at done_at response set_json_header :: ActionM () set_json_header = setHeader "Content-Type" "application/json; charset=utf-8" treat_as_string :: String -> String treat_as_string str = concat ["\"", str, "\""] get_current_time_as_double :: IO Double get_current_time_as_double = do epoch_double <- (read <$> formatTime defaultTimeLocale "%s.%q" <$> getCurrentTime) :: IO Double return epoch_double format_response :: (Show a, Num a) => Int -> a -> a -> String -> String format_response status start_at done_at response = concat ["[", "[", (show status), ",", (show start_at), ",", (show $ (done_at - start_at)), "],", response, "]"] format_err_response :: (Show a, Num a) => Int -> a -> a -> String -> String format_err_response status start_at done_at errbuf = concat ["[", "[", (show status), ",", (show start_at), ",", (show $ (done_at - start_at)), ",", (treat_as_string errbuf), ",[]", "]]"]