packages feed

socketson-0.1.0.0: doc/sample/Main.hs

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Network.Socketson
import Network.Socketson.Protocol

import Data.Aeson (ToJSON (..), FromJSON (..), object, (.=), (.:), Value (..))
import Data.List (isPrefixOf)
import Control.Monad.Trans.Either

import System.Environment (getArgs)

-- from server perspective:
-- outgoing object
data SObject = SObject Int String

instance ToJSON SObject where
  toJSON (SObject i s) = object [ "int" .= i, "str" .= s ]


-- incoming object
data RObject = RObject String

instance FromJSON RObject where
  parseJSON (Object v) = RObject <$>
                          v .: "str"

type SessionData = Int

{- We implement the following protocol:

  Incoming objects (sent by client): RObject, { "str" : <some string> }
  Outgoing objects (sent to client): SObject, { "str" : <same string>, "int" : <counter> }

where `<counter>` gets increment each time an object was received (on server side). This is realized via session data.

If `RObject "quit"` (on server side) is received, a close request gets sent.

If `RObject ("error":e)` is received, an user error with description `e` is thrown on server side (i.e. reported).

-}
protocolFunction :: (Maybe SessionData -> RObject -> EitherT String IO (Maybe SessionData, Reaction SObject))
protocolFunction msd (RObject str) =
  let n = case msd of
            Nothing -> 0
            Just i   -> i + 1
      sobj = SObject n str
  in case str of
        "quit"                      -> return (Just n, Close)
        e | "error:" `isPrefixOf` e -> left (drop 6 e)
          | otherwise               -> return (Just n, Send sobj)


main :: IO ()
main =
  do as <- getArgs
     case as of
       [port, path] -> do putStrLn $ "starting socketson at " ++ port
                          socketson path 2 (read port) protocolFunction
       _            -> putStrLn "usage: socketson-sample <port> <path for session storage>"