broken attempts to work on concurrency

This commit is contained in:
Adam C. Baker
2014-10-17 17:10:34 -07:00
parent 15d5143400
commit 49f0bf7c3f
3 changed files with 34 additions and 20 deletions
+10 -12
View File
@@ -11,29 +11,26 @@ cabal-version: >=1.10
executable dbapi executable dbapi
main-is: Main.hs main-is: Main.hs
ghc-options: -Wall -W -Werror ghc-options: -Wall -W -threaded
default-language: Haskell2010 default-language: Haskell2010
build-depends: base >=4.6 && <5 build-depends: base >=4.6 && <5
, HDBC, HDBC-postgresql , HDBC, HDBC-postgresql
, warp, wai >= 3.0.1 && < 3.0.2 , warp, wai >= 3.0.1 && < 3.0.2
, wai-extra, wai-cors , wai-extra, wai-cors
, wai-middleware-static >= 0.6.0 , wai-middleware-static >= 0.6.0
, HTTP, convertible , HTTP, convertible, http-types
, case-insensitive , case-insensitive
, http-types, scientific, time , scientific, time
, bytestring, aeson, network >= 2.6 , aeson, network >= 2.6
, text , containers , bytestring, text, split, string-conversions
, containers, unordered-containers
, optparse-applicative >= 0.9.1 && < 0.10 , optparse-applicative >= 0.9.1 && < 0.10
, unordered-containers , regex-base, regex-tdfa
, regex-base
, string-conversions
, http-media, regex-tdfa
, Ranged-sets , Ranged-sets
, transformers , transformers
, bcrypt , bcrypt, base64-string
, base64-string
, split
, network-uri >= 2.6 , network-uri >= 2.6
, resource-pool, process
Other-Modules: Dbapi Other-Modules: Dbapi
, PgStructure , PgStructure
, PgQuery , PgQuery
@@ -69,3 +66,4 @@ Test-Suite spec
, base64-string , base64-string
, split , split
, network-uri >= 2.6 , network-uri >= 2.6
, resource-pool
+12 -3
View File
@@ -3,9 +3,8 @@
module Main where module Main where
import Dbapi import Dbapi
import Middleware (inTransaction, authenticated, withSavepoint, clientErrors, import Middleware (inTransaction, authenticated, withSavepoint, clientErrors,
redirectInsecure) redirectInsecure, withDBConnection)
import Network.Wai.Handler.Warp hiding (Connection) import Network.Wai.Handler.Warp hiding (Connection)
import Database.HDBC.PostgreSQL (connectPostgreSQL')
import Data.String.Conversions (cs) import Data.String.Conversions (cs)
import Control.Monad (unless) import Control.Monad (unless)
@@ -14,6 +13,15 @@ import Options.Applicative hiding (columns)
import Network.Wai.Middleware.Gzip (gzip, def) import Network.Wai.Middleware.Gzip (gzip, def)
import Network.Wai.Middleware.Cors (cors) import Network.Wai.Middleware.Cors (cors)
import Network.Wai.Middleware.Static (staticPolicy, only) import Network.Wai.Middleware.Static (staticPolicy, only)
import Database.HDBC (disconnect)
import Database.HDBC.PostgreSQL(connectPostgreSQL')
import Data.Pool(createPool)
import System.Process
import Control.Concurrent(threadDelay)
import Network.HTTP.Types.Status
import Network.Wai
argParser :: Parser AppConfig argParser :: Parser AppConfig
argParser = AppConfig argParser = AppConfig
@@ -29,8 +37,9 @@ argParser = AppConfig
main :: IO () main :: IO ()
main = do main = do
conf <- execParser (info (helper <*> argParser) describe) conf <- execParser (info (helper <*> argParser) describe)
let port = configPort conf
let dburi = configDbUri conf let dburi = configDbUri conf
pool <- createPool (putStrLn "creating connection" >> connectPostgreSQL' (configDbUri conf)) (\c-> putStrLn "destroying connection" >> disconnect c) 1 600 10
let port = configPort conf
unless (configSecure conf) $ unless (configSecure conf) $
putStrLn "WARNING, running in insecure mode, auth will be in plaintext" putStrLn "WARNING, running in insecure mode, auth will be in plaintext"
+12 -5
View File
@@ -6,6 +6,7 @@ module Middleware where
import Data.Aeson ((.=), toJSON, ToJSON, object, encode) import Data.Aeson ((.=), toJSON, ToJSON, object, encode)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Monoid (mconcat) import Data.Monoid (mconcat)
import Data.Pool(withResource, Pool)
import Database.HDBC (runRaw) import Database.HDBC (runRaw)
import Database.HDBC.PostgreSQL (Connection) import Database.HDBC.PostgreSQL (Connection)
@@ -15,6 +16,7 @@ import Data.String.Conversions(cs)
import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Char8 as BS
import Control.Exception (finally, throw, catchJust, catch, SomeException, import Control.Exception (finally, throw, catchJust, catch, SomeException,
bracket_) bracket_)
import Control.Concurrent(threadDelay)
import Network.HTTP.Types.Header (RequestHeaders, hContentType, hAuthorization, import Network.HTTP.Types.Header (RequestHeaders, hContentType, hAuthorization,
hLocation) hLocation)
@@ -26,18 +28,23 @@ import Network.URI (URI(..), parseURI)
import PgQuery(LoginAttempt(..), signInRole, setRole, resetRole) import PgQuery(LoginAttempt(..), signInRole, setRole, resetRole)
import Codec.Binary.Base64.String (decode) import Codec.Binary.Base64.String (decode)
inTransaction :: (Connection -> Application) -> Connection -> Application
withDBConnection :: Pool Connection -> (Connection -> Application) -> Application
withDBConnection pool app req respond =
withResource pool (\c -> app c req respond)
inTransaction :: (Connection -> Application) -> (Connection -> Application)
inTransaction app conn req respond = inTransaction app conn req respond =
finally (runRaw conn "begin" >> app conn req respond) (runRaw conn "commit") finally (runRaw conn "begin" >> app conn req respond) (runRaw conn "commit")
withSavepoint :: (Connection -> Application) -> Connection -> Application withSavepoint :: (Connection -> Application) -> (Connection -> Application)
withSavepoint app conn req respond = do withSavepoint app conn req respond = do
runRaw conn "savepoint req_sp" runRaw conn "savepoint req_sp"
catch (app conn req respond) (\e -> let _ = (e::SomeException) in catch (app conn req respond) (\e -> let _ = (e::SomeException) in
runRaw conn "rollback to savepoint req_sp" >> throw e) runRaw conn "rollback to savepoint req_sp" >> throw e)
authenticated :: BS.ByteString -> (Connection -> Application) -> authenticated :: BS.ByteString -> (Connection -> Application) ->
Connection -> Application (Connection -> Application)
authenticated anon app conn req respond = do authenticated anon app conn req respond = do
attempt <- httpRequesterRole (requestHeaders req) attempt <- httpRequesterRole (requestHeaders req)
case attempt of case attempt of
@@ -46,9 +53,9 @@ authenticated anon app conn req respond = do
LoginFailed -> LoginFailed ->
respond $ responseLBS status401 [] "Invalid username or password" respond $ responseLBS status401 [] "Invalid username or password"
LoginSuccess role -> LoginSuccess role ->
bracket_ (setRole conn role) (resetRole conn) $ app conn req respond bracket_ (setRole conn role >> threadDelay 10000000) (resetRole conn) $ app conn req respond
NoCredentials -> NoCredentials ->
bracket_ (setRole conn anon) (resetRole conn) $ app conn req respond bracket_ (setRole conn anon >> threadDelay 10000000) (resetRole conn) $ app conn req respond
where where
httpRequesterRole :: RequestHeaders -> IO LoginAttempt httpRequesterRole :: RequestHeaders -> IO LoginAttempt