/src/Models/Connection.hs

http://github.com/biilmann/eventsource-broker · Haskell · 90 lines · 61 code · 19 blank · 10 comment · 2 complexity · 394103af9c171c46281f4aad5f4eb268 MD5 · raw file

  1. {-# LANGUAGE OverloadedStrings #-}
  2. module Models.Connection where
  3. import Prelude hiding (lookup)
  4. import Data.Time.Clock (UTCTime, getCurrentTime)
  5. import Data.Time.Clock.POSIX (getPOSIXTime, posixSecondsToUTCTime)
  6. import Data.UString (UString)
  7. import DB
  8. -- |An eventSource connection to the broker persisted in mongoDB
  9. data Connection = Connection
  10. { socketId :: UString
  11. , brokerId :: UString
  12. , userId :: UString
  13. , channel :: UString
  14. , presenceId :: Maybe UString
  15. , disconnectAt :: Maybe Int -- Seconds from current time
  16. }
  17. -- |Store a "connection" to the broker in the database
  18. -- If the disconnect is set, the connection will be marked for
  19. -- disconnection during a coming sweep
  20. store :: DB -> Connection -> IO (Either Failure ())
  21. store db conn= do
  22. time <- disconnectTime (disconnectAt conn)
  23. run db $ repsert (select s "connections") (d time)
  24. where
  25. s = ["_id" =: socketId conn, "channel" =: channel conn, "user_id" =: userId conn]
  26. d (Just time) = s ++ presence ++ ["broker" =: brokerId conn, "disconnect_at" =: time]
  27. d Nothing = s ++ presence ++ ["broker" =: brokerId conn]
  28. presence = case presenceId conn of
  29. Just pid -> ["presence_id" =: pid]
  30. Nothing -> []
  31. -- |Mark a connection. Marked connections will be removed by a later
  32. -- sweep
  33. mark :: DB -> Connection -> IO (Either Failure ())
  34. mark db conn = do
  35. case disconnectAt conn of
  36. Just offset -> do
  37. time <- disconnectTime (Just offset)
  38. run db $ modify (select s "connections") (m time)
  39. Nothing -> return $ Right ()
  40. where
  41. s = ["_id" =: (socketId conn), "user_id" =: userId conn]
  42. m time = ["$set" =: ["disconnect_at" =: time]]
  43. -- |Sweep connections. All marked connections with a disconnect_at less
  44. -- than the current time will be removed.
  45. sweep :: DB -> UString -> IO (Either Failure ())
  46. sweep db bid = do
  47. time <- getCurrentTime
  48. run db $ delete (select ["broker" =: bid, "disconnect_at" =: ["$lte" =: time]] "connections")
  49. -- |Remove all connections from a broker from the db
  50. remove :: DB -> UString -> IO (Either Failure ())
  51. remove db bid =
  52. run db $ delete (select ["broker" =: bid] "connections")
  53. get :: DB -> UString -> IO (Either Failure (Maybe Connection))
  54. get db sid = do
  55. result <- run db $ findOne (select ["_id" =: sid] "connections")
  56. return $ returnModel constructor result
  57. constructor :: Document -> Connection
  58. constructor doc = Connection {
  59. brokerId = at "broker" doc
  60. , socketId = at "_id" doc
  61. , userId = at "user_id" doc
  62. , channel = at "channel" doc
  63. , presenceId = lookup "presence_id" doc
  64. , disconnectAt = Nothing
  65. }
  66. count :: DB -> UString -> IO (Either Failure Int)
  67. count db bid =
  68. run db $ DB.count (select ["broker" =: bid] "connections")
  69. disconnectTime :: Maybe Int -> IO (Maybe UTCTime)
  70. disconnectTime (Just offset) = fmap (Just . posixSecondsToUTCTime . (+ (fromIntegral offset))) getPOSIXTime
  71. disconnectTime Nothing = return Nothing