{-# LANGUAGE OverloadedStrings
, DeriveGeneric
, LambdaCase
, BlockArguments
, ExtendedDefaultRules
#-}
module HGreet.Packet ( Request(..), Response(..), AuthMessageType(..), ErrorType(..)
, encodeRequest, decodeResponse, encodeLen, decodeLen) where
import Data.Maybe
import Data.Aeson hiding (Success, Error)
import GHC.Generics
import System.Endian
import Sound.OSC.Coding.Byte (encode_u32, encode_u32_le, decode_u32, decode_u32_le)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Sound.OSC as HGreet
data Request
= CreateSession { Request -> String
username :: String }
| PostAuthMessageResponse { Request -> Maybe String
respone :: Maybe String }
| StartSession { Request -> [String]
cmd :: [String] }
| CancelSession
deriving ((forall x. Request -> Rep Request x)
-> (forall x. Rep Request x -> Request) -> Generic Request
forall x. Rep Request x -> Request
forall x. Request -> Rep Request x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Request x -> Request
$cfrom :: forall x. Request -> Rep Request x
Generic, Int -> Request -> ShowS
[Request] -> ShowS
Request -> String
(Int -> Request -> ShowS)
-> (Request -> String) -> ([Request] -> ShowS) -> Show Request
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Request] -> ShowS
$cshowList :: [Request] -> ShowS
show :: Request -> String
$cshow :: Request -> String
showsPrec :: Int -> Request -> ShowS
$cshowsPrec :: Int -> Request -> ShowS
Show, Request -> Request -> Bool
(Request -> Request -> Bool)
-> (Request -> Request -> Bool) -> Eq Request
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Request -> Request -> Bool
$c/= :: Request -> Request -> Bool
== :: Request -> Request -> Bool
$c== :: Request -> Request -> Bool
Eq)
data Response
= Success
| Error {Response -> ErrorType
error_type :: ErrorType, Response -> String
description :: String}
| AuthMessage {Response -> AuthMessageType
auth_message_type :: AuthMessageType, Response -> String
auth_message :: String}
deriving ((forall x. Response -> Rep Response x)
-> (forall x. Rep Response x -> Response) -> Generic Response
forall x. Rep Response x -> Response
forall x. Response -> Rep Response x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Response x -> Response
$cfrom :: forall x. Response -> Rep Response x
Generic, Int -> Response -> ShowS
[Response] -> ShowS
Response -> String
(Int -> Response -> ShowS)
-> (Response -> String) -> ([Response] -> ShowS) -> Show Response
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Response] -> ShowS
$cshowList :: [Response] -> ShowS
show :: Response -> String
$cshow :: Response -> String
showsPrec :: Int -> Response -> ShowS
$cshowsPrec :: Int -> Response -> ShowS
Show, Response -> Response -> Bool
(Response -> Response -> Bool)
-> (Response -> Response -> Bool) -> Eq Response
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Response -> Response -> Bool
$c/= :: Response -> Response -> Bool
== :: Response -> Response -> Bool
$c== :: Response -> Response -> Bool
Eq)
data AuthMessageType
= Visible
| Secret
| Info
| ErrorType
deriving (Int -> AuthMessageType -> ShowS
[AuthMessageType] -> ShowS
AuthMessageType -> String
(Int -> AuthMessageType -> ShowS)
-> (AuthMessageType -> String)
-> ([AuthMessageType] -> ShowS)
-> Show AuthMessageType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [AuthMessageType] -> ShowS
$cshowList :: [AuthMessageType] -> ShowS
show :: AuthMessageType -> String
$cshow :: AuthMessageType -> String
showsPrec :: Int -> AuthMessageType -> ShowS
$cshowsPrec :: Int -> AuthMessageType -> ShowS
Show, AuthMessageType -> AuthMessageType -> Bool
(AuthMessageType -> AuthMessageType -> Bool)
-> (AuthMessageType -> AuthMessageType -> Bool)
-> Eq AuthMessageType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AuthMessageType -> AuthMessageType -> Bool
$c/= :: AuthMessageType -> AuthMessageType -> Bool
== :: AuthMessageType -> AuthMessageType -> Bool
$c== :: AuthMessageType -> AuthMessageType -> Bool
Eq)
data ErrorType
= AuthError
| OtherError
deriving (Int -> ErrorType -> ShowS
[ErrorType] -> ShowS
ErrorType -> String
(Int -> ErrorType -> ShowS)
-> (ErrorType -> String)
-> ([ErrorType] -> ShowS)
-> Show ErrorType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ErrorType] -> ShowS
$cshowList :: [ErrorType] -> ShowS
show :: ErrorType -> String
$cshow :: ErrorType -> String
showsPrec :: Int -> ErrorType -> ShowS
$cshowsPrec :: Int -> ErrorType -> ShowS
Show, ErrorType -> ErrorType -> Bool
(ErrorType -> ErrorType -> Bool)
-> (ErrorType -> ErrorType -> Bool) -> Eq ErrorType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ErrorType -> ErrorType -> Bool
$c/= :: ErrorType -> ErrorType -> Bool
== :: ErrorType -> ErrorType -> Bool
$c== :: ErrorType -> ErrorType -> Bool
Eq)
instance ToJSON Request where
toJSON :: Request -> Value
toJSON (CreateSession String
username) = [Pair] -> Value
object [Key
"type" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= String
"create_session", Key
"username" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= String
username]
toJSON (PostAuthMessageResponse Maybe String
response) = [Pair] -> Value
object [Key
"type" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= String
"post_auth_message_response", Key
"response" Key -> Maybe String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Maybe String
response]
toJSON (StartSession [String]
cmd) = [Pair] -> Value
object [Key
"type" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= String
"start_session", Key
"cmd" Key -> [String] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= [String]
cmd]
toJSON Request
CancelSession = [Pair] -> Value
object [Key
"type" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= String
"cancel_session"]
instance FromJSON Response where
parseJSON :: Value -> Parser Response
parseJSON = String -> (Object -> Parser Response) -> Value -> Parser Response
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"Response" ((Object -> Parser Response) -> Value -> Parser Response)
-> (Object -> Parser Response) -> Value -> Parser Response
forall a b. (a -> b) -> a -> b
$ \Object
v -> do
Object
v Object -> Key -> Parser Value
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"type" Parser Value -> (Value -> Parser Response) -> Parser Response
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> (Text -> Parser Response) -> Value -> Parser Response
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"type" \case
Text
"success" -> Response -> Parser Response
forall (m :: * -> *) a. Monad m => a -> m a
return Response
Success
Text
"error" -> ErrorType -> String -> Response
Error (ErrorType -> String -> Response)
-> Parser ErrorType -> Parser (String -> Response)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Key -> Parser ErrorType
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"error_type" Parser (String -> Response) -> Parser String -> Parser Response
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser String
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"description"
Text
"auth_message" -> AuthMessageType -> String -> Response
AuthMessage (AuthMessageType -> String -> Response)
-> Parser AuthMessageType -> Parser (String -> Response)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Key -> Parser AuthMessageType
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"auth_message_type" Parser (String -> Response) -> Parser String -> Parser Response
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Key -> Parser String
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"auth_message"
Text
_ -> String -> Parser Response
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid response type"
instance FromJSON AuthMessageType where
parseJSON :: Value -> Parser AuthMessageType
parseJSON = String
-> (Text -> Parser AuthMessageType)
-> Value
-> Parser AuthMessageType
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"AuthMessageType" \case
Text
"visible" -> AuthMessageType -> Parser AuthMessageType
forall (m :: * -> *) a. Monad m => a -> m a
return AuthMessageType
Visible
Text
"secret" -> AuthMessageType -> Parser AuthMessageType
forall (m :: * -> *) a. Monad m => a -> m a
return AuthMessageType
Secret
Text
"info" -> AuthMessageType -> Parser AuthMessageType
forall (m :: * -> *) a. Monad m => a -> m a
return AuthMessageType
Info
Text
"error" -> AuthMessageType -> Parser AuthMessageType
forall (m :: * -> *) a. Monad m => a -> m a
return AuthMessageType
ErrorType
Text
_ -> String -> Parser AuthMessageType
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid auth message type"
instance FromJSON ErrorType where
parseJSON :: Value -> Parser ErrorType
parseJSON = String -> (Text -> Parser ErrorType) -> Value -> Parser ErrorType
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"ErrorType" \case
Text
"auth_error" -> ErrorType -> Parser ErrorType
forall (m :: * -> *) a. Monad m => a -> m a
return ErrorType
AuthError
Text
"error" -> ErrorType -> Parser ErrorType
forall (m :: * -> *) a. Monad m => a -> m a
return ErrorType
OtherError
Text
_ -> String -> Parser ErrorType
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Invalid error type"
encodeRequest :: Request
-> B.ByteString
encodeRequest :: Request -> ByteString
encodeRequest Request
request = ByteString -> ByteString
BL.toStrict ByteString
packet where
encodedRequest :: ByteString
encodedRequest = Request -> ByteString
forall a. ToJSON a => a -> ByteString
encode Request
request
encodedLength :: ByteString
encodedLength = Int -> ByteString
encodeLen (Int -> ByteString) -> Int -> ByteString
forall a b. (a -> b) -> a -> b
$ Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Int) -> Int64 -> Int
forall a b. (a -> b) -> a -> b
$ ByteString -> Int64
BL.length ByteString
encodedRequest
packet :: ByteString
packet = ByteString
encodedLength ByteString -> ByteString -> ByteString
`BL.append` ByteString
encodedRequest
decodeResponse :: B.ByteString
-> Response
decodeResponse :: ByteString -> Response
decodeResponse = Maybe Response -> Response
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe Response -> Response)
-> (ByteString -> Maybe Response) -> ByteString -> Response
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe Response
forall a. FromJSON a => ByteString -> Maybe a
decode (ByteString -> Maybe Response)
-> (ByteString -> ByteString) -> ByteString -> Maybe Response
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BL.fromStrict
encodeLen :: Int -> BL.ByteString
encodeLen :: Int -> ByteString
encodeLen = case Endianness
getSystemEndianness of
Endianness
BigEndian -> Int -> ByteString
encode_u32
Endianness
LittleEndian -> Int -> ByteString
encode_u32_le
decodeLen :: BL.ByteString -> Int
decodeLen :: ByteString -> Int
decodeLen = case Endianness
getSystemEndianness of
Endianness
BigEndian -> ByteString -> Int
decode_u32
Endianness
LittleEndian -> ByteString -> Int
decode_u32_le