summaryrefslogtreecommitdiff
path: root/DWProxy.hs
diff options
context:
space:
mode:
Diffstat (limited to 'DWProxy.hs')
-rw-r--r--DWProxy.hs88
1 files changed, 60 insertions, 28 deletions
diff --git a/DWProxy.hs b/DWProxy.hs
index 10776c9..ec03a1a 100644
--- a/DWProxy.hs
+++ b/DWProxy.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
@@ -7,12 +9,12 @@ import Data.Graph.Inductive.Graph (mkGraph)
import Data.Graph.Inductive.PatriciaTree (Gr)
import Data.Graph.Inductive.Query.SP (sp)
import qualified Data.HashMap.Strict as HM
-import qualified Database.SQLite.Simple as SQLite
-import Data.Maybe (mapMaybe)
+import Database.HDBC
+import Database.HDBC.Sqlite3 as Sqlite3
+import Data.Convertible
import System.Environment (getArgs)
-import System.FilePath ((</>))
import Network.Socket.ByteString (sendAll, recv)
-import Network.Socket hiding (send, recv)
+import Network.Socket
import Control.Concurrent.Async (async, waitAnyCatchCancel)
import Control.Exception as E
import Control.Monad (when, forM_, forever)
@@ -24,7 +26,6 @@ import Data.Either (rights)
import Control.Applicative
import Data.Aeson (FromJSON, decodeStrict)
import GHC.Generics (Generic)
-import Data.Monoid
import Data.List
import Data.Maybe
@@ -47,6 +48,13 @@ data Exit = Exit { exitFrom :: RoomID
, exitName :: T.Text }
deriving (Show, Eq)
+data ShopItem = ShopItem { siRoomID :: RoomID
+ , siMapID :: Int
+ , siRoomShort :: T.Text
+ , siItemName :: T.Text
+ , siSalePrice :: T.Text }
+ deriving (Show, Eq)
+
mapNames :: [T.Text]
mapNames =
[ "Ankh-Morpork", "AM Assassins", "AM Buildings", "AM Cruets", "AM Docks"
@@ -73,14 +81,38 @@ elemAtIndex n (_:xs) = elemAtIndex (n - 1) xs
mapNameByID :: Int -> T.Text
mapNameByID n = fromMaybe "unknown" $ elemAtIndex (n - 1) mapNames
-
-instance SQLite.FromRow Room where
- fromRow = Room <$> SQLite.field <*> SQLite.field <*> SQLite.field
- <*> SQLite.field <*> SQLite.field <*> SQLite.field
-instance SQLite.FromRow Exit where
- fromRow = Exit <$> SQLite.field <*> SQLite.field <*> SQLite.field
+instance Convertible [SqlValue] Room where
+ safeConvert [rid, rmid, rx, ry, rs, rt] = do
+ rid' <- safeFromSql rid
+ rmid' <- safeFromSql rmid
+ rx' <- safeFromSql rx
+ ry' <- safeFromSql ry
+ rs' <- safeFromSql rs
+ rt' <- safeFromSql rt
+ pure $ Room rid' rmid' rx' ry' rs' rt'
+ safeConvert other = Left $ ConvertError (show other) "[SqlValue]" "Room" "Unexpected list length"
+
+instance Convertible [SqlValue] Exit where
+ safeConvert [ef, et, en] = do
+ ef' <- safeFromSql ef
+ et' <- safeFromSql et
+ en' <- safeFromSql en
+ pure $ Exit ef' et' en'
+ safeConvert other = Left $ ConvertError (show other) "[SqlValue]" "Exit" "Unexpected list length"
+
+
+instance Convertible [SqlValue] ShopItem where
+ safeConvert [rid, mid, rs, iname, sprice] = do
+ rid' <- safeFromSql rid
+ mid' <- safeFromSql mid
+ rs' <- safeFromSql rs
+ iname' <- safeFromSql iname
+ sprice' <- safeFromSql sprice
+ pure $ ShopItem rid' mid' rs' iname' sprice'
+ safeConvert other = Left $ ConvertError (show other) "[SqlValue]" "ShopItem" "Unexpected list length"
+
data PathFinder = PF { pfGraph :: Gr RoomID Int
, pfRoomToNode :: HM.HashMap RoomID Int
@@ -173,14 +205,14 @@ c2s c leftover = do
Telnet other -> sendAll (cServer c) $ BS.cons '\255' other
ShopSearch query -> do
curRoom <- currentRoom <$> readMVar (connState c)
- shops <- SQLite.query (dbConn c)
- ("select room_id, map_id, room_short, item_name, sale_price from shop_items"
- <> " natural inner join rooms where item_name like ?")
- (SQLite.Only (concat ["%", query, "%"]))
- :: IO [(RoomID, Int, T.Text, T.Text, T.Text)]
+ shops <- map convert
+ <$> quickQuery' (dbConn c)
+ ("select room_id, map_id, room_short, item_name, sale_price from shop_items"
+ <> " natural inner join rooms where item_name like ?")
+ [(toSql $ concat ["%", query, "%"])]
-- cleanup the routes
modifyMVar_ (connState c) $ \cst -> pure $ cst { routeOptions = [] }
- forM_ shops $ \(roomI, mapI, roomS, item, price) -> do
+ forM_ shops $ \(ShopItem roomI mapI roomS item price) -> do
let p = curRoom >>=
\cr -> either (const Nothing) Just (findPath (cPF c) cr roomI)
(n, l) <- case p of
@@ -199,12 +231,12 @@ c2s c leftover = do
Nothing -> sendAll (cClient c)
"No source location is given, and none detected"
Just f' -> do
- fromRooms <- SQLite.query (dbConn c)
+ fromRooms <- map convert <$> quickQuery' (dbConn c)
"select * from rooms where room_short like ? or room_id = ?"
- ((T.concat ["%", f', "%"]), f')
- toRooms <- SQLite.query (dbConn c)
+ [(toSql $ T.concat ["%", f', "%"]), toSql f']
+ toRooms <- map convert <$> quickQuery' (dbConn c)
"select * from rooms where room_short like ? or room_id = ?"
- ((concat ["%", t, "%"]), t)
+ [(toSql $ concat ["%", t, "%"]), toSql t]
let routes = sortOn (\(_, _, p) -> length p) $ rights
[ (\p -> (showRoom from, showRoom to, p)) <$>
findPath (cPF c) (roomID from) (roomID to)
@@ -269,7 +301,7 @@ data ConnState = CS { routeOptions :: [[T.Text]]
data Config = Config { cClient :: Socket
, cServer :: Socket
- , dbConn :: SQLite.Connection
+ , dbConn :: Sqlite3.Connection
, connState :: MVar ConnState
, cPF :: PathFinder
}
@@ -319,13 +351,13 @@ main :: IO ()
main = do
args <- getArgs
case args of
- [quow] ->
+ [quowmap] ->
E.bracket
- (SQLite.open $ quow </> "maps" </> "_quowmap_database.db")
- (SQLite.close) $ \db -> do
- rooms <- SQLite.query_ db
- "select room_id, map_id, xpos, ypos, room_short, room_type from rooms"
- exits <- SQLite.query_ db "select room_id, connect_id, exit from room_exits"
+ (connectSqlite3 quowmap)
+ (disconnect) $ \db -> do
+ rooms <- map convert <$> quickQuery' db
+ "select room_id, map_id, xpos, ypos, room_short, room_type from rooms" []
+ exits <- map convert <$> quickQuery' db "select room_id, connect_id, exit from room_exits" []
let pf = pathFinder rooms exits
mv <- newMVar $ CS [] Nothing
E.bracket mkServer close $ \serverSocket -> forever $ do