packages feed

EtaMOO-0.1.0.0: src/MOO/Builtins/Network.hs

{-# LANGUAGE OverloadedStrings #-}

module MOO.Builtins.Network ( builtins ) where

import Control.Monad (liftM)
import Control.Monad.State (gets)
import Data.Time

import MOO.Types
import MOO.Task
import MOO.Network
import MOO.Database (systemObject)
import MOO.Builtins.Common

import qualified Data.Map as M
import qualified Data.Text as T

{-# ANN module ("HLint: ignore Use camelCase" :: String) #-}

-- | § 4.4.4 Operations on Network Connections
builtins :: [BuiltinSpec]
builtins = [
    ("connected_players",
                    (bf_connected_players, Info 0 (Just 1) [TAny]       TLst))
  , ("connected_seconds",
                    (bf_connected_seconds, Info 1 (Just 1) [TObj]       TInt))
  , ("idle_seconds"  , (bf_idle_seconds  , Info 1 (Just 1) [TObj]       TInt))
  , ("notify"        , (bf_notify        , Info 2 (Just 3) [TObj, TStr,
                                                            TAny]       TAny))
  , ("buffered_output_length",
               (bf_buffered_output_length, Info 0 (Just 1) [TObj]       TInt))
  , ("read"          , (bf_read          , Info 0 (Just 2) [TObj, TAny] TStr))
  , ("force_input"   , (bf_force_input   , Info 2 (Just 3) [TObj, TStr,
                                                            TAny]       TAny))
  , ("flush_input"   , (bf_flush_input   , Info 1 (Just 2) [TObj, TAny] TAny))
  , ("output_delimiters",
                    (bf_output_delimiters, Info 1 (Just 1) [TObj]       TLst))
  , ("boot_player"   , (bf_boot_player   , Info 1 (Just 1) [TObj]       TAny))
  , ("connection_name",
                      (bf_connection_name, Info 1 (Just 1) [TObj]       TStr))
  , ("set_connection_option",
                (bf_set_connection_option, Info 3 (Just 3) [TObj, TStr,
                                                            TAny]       TAny))
  , ("connection_options",
                   (bf_connection_options, Info 1 (Just 1) [TObj]       TLst))
  , ("connection_option",
                    (bf_connection_option, Info 2 (Just 2) [TObj, TStr] TAny))
  , ("open_network_connection",
              (bf_open_network_connection, Info 2 (Just 3) [TStr, TInt,
                                                            TObj]       TObj))
  , ("listen"        , (bf_listen        , Info 2 (Just 3) [TObj, TInt,
                                                            TAny]       TAny))
  , ("unlisten"      , (bf_unlisten      , Info 1 (Just 1) [TInt]       TAny))
  , ("listeners"     , (bf_listeners     , Info 0 (Just 0) []           TLst))
  ]

bf_connected_players optional = do
  world <- getWorld
  let objects = M.keys $ connections world
  return $ objectList $ if include_all then objects else filter (>= 0) objects
  where [include_all] = booleanDefaults optional [False]

connectionSeconds :: ObjId -> (Maybe Connection -> Maybe UTCTime) -> MOO Value
connectionSeconds oid f = do
  world <- getWorld
  case f $ M.lookup oid (connections world) of
    Just utcTime -> secondsSince utcTime
    Nothing      -> raise E_INVARG

  where secondsSince :: UTCTime -> MOO Value
        secondsSince utcTime = do
          now <- gets startTime
          return (Int $ floor $ now `diffUTCTime` utcTime)

bf_connected_seconds [Obj player] =
  connectionSeconds player (connectionEstablishedTime =<<)

bf_idle_seconds [Obj player] =
  connectionSeconds player (connectionActivityTime `fmap`)

bf_notify (Obj conn : Str string : optional) = do
  notify conn string
  return $ truthValue True
  where [no_flush] = booleanDefaults optional [False]

bf_buffered_output_length optional = notyet "buffered_output_length"
bf_read optional = notyet "read"
bf_force_input (Obj conn : Str line : optional) = notyet "force_input"
bf_flush_input (Obj conn : optional) = notyet "flush_input"
bf_output_delimiters [Obj player] = notyet "output_delimiters"
bf_boot_player [Obj player] = notyet "boot_player"

bf_connection_name [Obj player] = do
  checkPermission player
  Str `liftM` getConnectionName player

bf_set_connection_option [Obj conn, Str option, value] =
  notyet "set_connection_option"
bf_connection_options [Obj conn] = notyet "connection_options"
bf_connection_option [Obj conn, Str name] = notyet "connection_option"

bf_open_network_connection (Str host : Int port : optional) = do
  checkWizard
  connId <- openNetworkConnection (T.unpack host) (fromIntegral port) listener
  return (Obj connId)

  where [Obj listener] = defaults optional [Obj systemObject]

bf_listen (Obj object : Int point : optional) = do
  checkWizard
  checkValid object

  canon <- listen (fromIntegral point) object print_messages
  return (Int $ fromIntegral canon)

  where [print_messages] = booleanDefaults optional [False]

bf_unlisten [Int canon] =
  checkWizard >> unlisten (fromIntegral canon) >> return nothing

bf_listeners [] = do
  world <- getWorld
  return $ fromListBy formatListener $ M.elems (listeners world)