-- | Description: Client-to-Client messages -- The JSON messages are derived from these Message types. {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE ScopedTypeVariables #-} module Transit.Internal.Messages ( TransitMsg(..) , Ability(..) , AbilityV1(..) , Hint(..) , ConnectionHint(..) , Ack(..) , TransitAck(..) ) where import Protolude import Data.Aeson ( FromJSON(..) , ToJSON(..) , genericToJSON , genericParseJSON , defaultOptions , fieldLabelModifier , constructorTagModifier , sumEncoding , SumEncoding(..) , camelTo2 ) import qualified Data.Set as Set -- | Type to represent the abilities data AbilityV1 = DirectTcpV1 -- ^ Can send directly via TCP | RelayV1 -- ^ Can relay via a relay server deriving (Eq, Show, Generic) instance ToJSON AbilityV1 where toJSON = genericToJSON defaultOptions { constructorTagModifier = camelTo2 '-'} instance FromJSON AbilityV1 where parseJSON = genericParseJSON defaultOptions { constructorTagModifier = camelTo2 '-'} -- | Hints are messages that specify ways that the client -- can connect to the peer. data Hint = Hint { ctype :: AbilityV1 , priority :: Double , hostname :: Text , port :: Word16 } deriving (Eq, Show, Generic) instance Ord Hint where Hint _ p1 _ _ `compare` Hint _ p2 _ _ = Down p1 `compare` Down p2 instance ToJSON Hint where toJSON = genericToJSON defaultOptions { fieldLabelModifier = \name -> case name of "ctype" -> "type" _ -> name } instance FromJSON Hint where parseJSON = genericParseJSON defaultOptions { fieldLabelModifier = \name -> case name of "ctype" -> "type" _ -> name } -- | Connection Hint is currently a direct hint or a relay hint data ConnectionHint = Direct Hint -- ^ Direct Hint | Relay { rtype :: AbilityV1 , hints :: [Hint] } -- ^ Relay hint deriving (Eq, Show, Generic) instance Ord ConnectionHint where Direct _ `compare` Direct _ = EQ Direct _ `compare` Relay _ _ = LT Relay _ h1 `compare` Relay _ h2 = h1 `compare` h2 Relay _ _ `compare` Direct _ = GT instance ToJSON ConnectionHint where toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue , fieldLabelModifier = \name -> case name of "rtype" -> "type" _ -> name } instance FromJSON ConnectionHint where parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue , fieldLabelModifier = \name -> case name of "rtype" -> "type" _ -> name } -- | Ack message type data Ack = FileAck Text -- ^ File Ack | MessageAck Text -- ^ Message Ack deriving (Eq, Show, Generic) instance ToJSON Ack where toJSON = genericToJSON defaultOptions { sumEncoding = ObjectWithSingleField , constructorTagModifier = camelTo2 '_'} instance FromJSON Ack where parseJSON = genericParseJSON defaultOptions { sumEncoding = ObjectWithSingleField , constructorTagModifier = camelTo2 '_'} -- | A newtype specifically for generating Ability JSON messages newtype Ability = Ability { atype :: AbilityV1 } deriving (Eq, Show, Generic) instance ToJSON Ability where toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue , fieldLabelModifier = const "type" } instance FromJSON Ability where parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue , fieldLabelModifier = const "type" } -- | Transit, Answer and Error Message from Client to Client data TransitMsg = Error Text | Answer Ack -- ^ Answer message is sent on a successful transfer | Transit { abilitiesV1 :: [Ability] , hintsV1 :: Set.Set ConnectionHint } -- ^ Transit message deriving (Eq, Show, Generic) instance ToJSON TransitMsg where toJSON = genericToJSON defaultOptions { sumEncoding = ObjectWithSingleField , constructorTagModifier = camelTo2 '-' , fieldLabelModifier = camelTo2 '-' } instance FromJSON TransitMsg where parseJSON = genericParseJSON defaultOptions { sumEncoding = ObjectWithSingleField , constructorTagModifier = camelTo2 '-' , fieldLabelModifier = camelTo2 '-'} -- | Message sent by the receiver of the file to the sender data TransitAck = TransitAck { ack :: Text -- ^ "ack" is "ok" implies a successful transfer , sha256 :: Text } -- ^ expected sha256 sum of the transfered file deriving (Eq, Show, Generic) instance ToJSON TransitAck where toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue } instance FromJSON TransitAck where parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }