Add all session and chat room commands

The account, room host and staff commands are still missing though.
This commit is contained in:
Joscha 2020-01-09 09:34:06 +00:00
parent 70951d30b5
commit 282c1167fd
2 changed files with 323 additions and 66 deletions

View file

@ -11,19 +11,33 @@ module Haboli.Euphoria.Api
, UserType(..) , UserType(..)
, UserId(..) , UserId(..)
-- * Asynchronous events -- * Asynchronous events
-- ** bounce-event
, BounceEvent(..) , BounceEvent(..)
-- ** disconnect-event
, DisconnectEvent(..) , DisconnectEvent(..)
-- ** hello-event
, HelloEvent(..) , HelloEvent(..)
-- ** join-event
, JoinEvent(..) , JoinEvent(..)
-- ** login-event
, LoginEvent(..) , LoginEvent(..)
-- ** logout-event
, LogoutEvent(..) , LogoutEvent(..)
-- ** network-event
, NetworkEvent(..) , NetworkEvent(..)
-- ** nick-event
, NickEvent(..) , NickEvent(..)
-- ** edit-message-event
, EditMessageEvent(..) , EditMessageEvent(..)
-- ** part-event
, PartEvent(..) , PartEvent(..)
-- ** ping-event
, PingEvent(..) , PingEvent(..)
-- ** pm-initiate-event
, PmInitiateEvent(..) , PmInitiateEvent(..)
-- ** send-event
, SendEvent(..) , SendEvent(..)
-- ** snapshot-event
, SnapshotEvent(..) , SnapshotEvent(..)
-- * Session commands -- * Session commands
-- ** auth -- ** auth
@ -33,12 +47,24 @@ module Haboli.Euphoria.Api
, PingCommand(..) , PingCommand(..)
, PingReply(..) , PingReply(..)
-- * Chat room commands -- * Chat room commands
-- ** get-message
, GetMessageCommand(..)
, GetMessageReply(..)
-- ** log
, LogCommand(..)
, LogReply(..)
-- ** nick -- ** nick
, NickCommand(..) , NickCommand(..)
, NickReply(..) , NickReply(..)
-- ** pm-initiate
, PmInitiateCommand(..)
, PmInitiateReply(..)
-- ** send -- ** send
, SendCommand(..) , SendCommand(..)
, SendReply(..) , SendReply(..)
-- ** who
, WhoCommand(..)
, WhoReply(..)
) where ) where
import Control.Monad import Control.Monad
@ -53,13 +79,12 @@ class ToJSONObject a where
toJSONObject :: a -> Object toJSONObject :: a -> Object
fromPacket :: T.Text -> (Object -> Parser a) -> Value -> Parser a fromPacket :: T.Text -> (Object -> Parser a) -> Value -> Parser a
fromPacket packetType parser (Object o) = do fromPacket packetType parser v = parseJSON v >>= \o -> do
actualType <- o .: "type" actualType <- o .: "type"
when (actualType /= packetType) $ when (actualType /= packetType) $
fail $ T.unpack $ "packet type is not " <> packetType fail $ T.unpack $ "packet type is not " <> packetType
packetData <- o .: "data" packetData <- o .: "data"
parser packetData parser packetData
fromPacket _ _ v = typeMismatch "Object" v
toPacket :: T.Text -> Value -> Object toPacket :: T.Text -> Value -> Object
toPacket packetType packetData = HMap.fromList toPacket packetType packetData = HMap.fromList
@ -84,31 +109,30 @@ instance FromJSON AuthOption where
-- a post, or any broadcasted event in a room that should appear in the log. See -- a post, or any broadcasted event in a room that should appear in the log. See
-- <http://api.euphoria.io/#message>. -- <http://api.euphoria.io/#message>.
data Message = Message data Message = Message
{ msgId :: Snowflake { msgId :: Snowflake
, msgParent :: Maybe Snowflake , msgParent :: Maybe Snowflake
-- , msgPreviousEditId :: Maybe Snowflake , msgPreviousEditId :: Maybe Snowflake
, msgTime :: UTCTime , msgTime :: UTCTime
, msgSender :: SessionView , msgSender :: SessionView
, msgContent :: T.Text , msgContent :: T.Text
-- , msgEncryptionKeyId :: Maybe T.Text , msgEncryptionKeyId :: Maybe T.Text
-- , msgEdited :: Maybe UTCTime , msgEdited :: Maybe UTCTime
, msgDeleted :: Maybe UTCTime , msgDeleted :: Maybe UTCTime
, msgTruncated :: Bool , msgTruncated :: Bool
} deriving (Show) } deriving (Show)
instance FromJSON Message where instance FromJSON Message where
parseJSON (Object v) = Message parseJSON v = parseJSON v >>= \o -> Message
<$> v .: "id" <$> o .: "id"
<*> v .:? "parent" <*> o .:? "parent"
-- <*> v .:? "previous_edit_id" <*> o .:? "previous_edit_id"
<*> (posixSecondsToUTCTime <$> v .: "time") <*> (posixSecondsToUTCTime <$> o .: "time")
<*> v .: "sender" <*> o .: "sender"
<*> v .: "content" <*> o .: "content"
-- <*> v .:? "encryption_key_id" <*> o .:? "encryption_key_id"
-- <*> v .:? "edited" <*> o .:? "edited"
<*> (fmap posixSecondsToUTCTime <$> v .:? "deleted") <*> (fmap posixSecondsToUTCTime <$> o .:? "deleted")
<*> v .:? "truncated" .!= False <*> o .:? "truncated" .!= False
parseJSON v = typeMismatch "Object" v
data PersonalAccountView = PersonalAccountView data PersonalAccountView = PersonalAccountView
{ pavId :: Snowflake { pavId :: Snowflake
@ -116,32 +140,37 @@ data PersonalAccountView = PersonalAccountView
, pavEmail :: T.Text , pavEmail :: T.Text
} deriving (Show) } deriving (Show)
instance FromJSON PersonalAccountView where
parseJSON v = parseJSON v >>= \o -> PersonalAccountView
<$> o .: "id"
<*> o .: "name"
<*> o .: "email"
-- | A 'SessionView' describes a session and its identity. See -- | A 'SessionView' describes a session and its identity. See
-- <http://api.euphoria.io/#sessionview>. -- <http://api.euphoria.io/#sessionview>.
data SessionView = SessionView data SessionView = SessionView
{ svId :: UserId { svId :: UserId
, svNick :: T.Text , svNick :: T.Text
, svServerId :: T.Text , svServerId :: T.Text
, svServerEra :: T.Text , svServerEra :: T.Text
, svSessionId :: T.Text , svSessionId :: T.Text
, svIsStaff :: Bool , svIsStaff :: Bool
, svIsManager :: Bool , svIsManager :: Bool
-- , svClientAddress :: Maybe T.Text , svClientAddress :: Maybe T.Text
-- , svRealClientAddress :: Maybe T.Text , svRealClientAddress :: Maybe T.Text
} deriving (Show) } deriving (Show)
instance FromJSON SessionView where instance FromJSON SessionView where
parseJSON (Object v) = SessionView parseJSON v = parseJSON v >>= \o -> SessionView
<$> v .: "id" <$> o .: "id"
<*> v .: "name" <*> o .: "name"
<*> v .: "server_id" <*> o .: "server_id"
<*> v .: "server_era" <*> o .: "server_era"
<*> v .: "session_id" <*> o .: "session_id"
<*> v .:? "is_staff" .!= False <*> o .:? "is_staff" .!= False
<*> v .:? "is_manager" .!= False <*> o .:? "is_manager" .!= False
-- <*> v .:? "client_address" <*> o .:? "client_address"
-- <*> v .:? "real_client_address" <*> o .:? "real_client_address"
parseJSON v = typeMismatch "Object" v
-- | A snowflake is a 13-character string, usually used as a unique identifier -- | A snowflake is a 13-character string, usually used as a unique identifier
-- for some type of object. It is the base-36 encoding of an unsigned, 64-bit -- for some type of object. It is the base-36 encoding of an unsigned, 64-bit
@ -170,27 +199,49 @@ data UserId = UserId
, userSnowflake :: Snowflake , userSnowflake :: Snowflake
} deriving (Show, Eq) } deriving (Show, Eq)
instance ToJSON UserId where
toJSON uid =
let prefix = case userType uid of
Agent -> "agent:"
Account -> "account:"
Bot -> "bot:"
Other -> ""
in String $ prefix <> userSnowflake uid
instance FromJSON UserId where instance FromJSON UserId where
parseJSON (String v) = case T.breakOn ":" v of parseJSON v = parseJSON v >>= \s -> case T.breakOn ":" s of
(snowflake, "") -> pure $ UserId Other snowflake (snowflake, "") -> pure $ UserId Other snowflake
("agent", snowflake) -> pure $ UserId Agent $ T.drop 1 snowflake ("agent", snowflake) -> pure $ UserId Agent $ T.drop 1 snowflake
("account", snowflake) -> pure $ UserId Account $ T.drop 1 snowflake ("account", snowflake) -> pure $ UserId Account $ T.drop 1 snowflake
("bot", snowflake) -> pure $ UserId Bot $ T.drop 1 snowflake ("bot", snowflake) -> pure $ UserId Bot $ T.drop 1 snowflake
_ -> fail "invalid user id label" _ -> fail "invalid user id label"
parseJSON v = typeMismatch "String" v
{- Asynchronous events -} {- Asynchronous events -}
{- bounce-event -}
data BounceEvent = BounceEvent data BounceEvent = BounceEvent
{ bounceReason :: Maybe T.Text { bounceReason :: Maybe T.Text
, bounceAuthOption :: [AuthOption] , bounceAuthOption :: [AuthOption]
} deriving (Show) } deriving (Show)
data DisconnectEvent = DisconnectEvent instance FromJSON BounceEvent where
parseJSON = fromPacket "bounce-event" $ \o -> BounceEvent
<$> o .: "reason"
<*> o .: "auth_options"
{- disconnect-event -}
newtype DisconnectEvent = DisconnectEvent
{ disconnectReason :: T.Text { disconnectReason :: T.Text
} deriving (Show) } deriving (Show)
--TODO: Merge the account stuff with the PersonalAccountView? instance FromJSON DisconnectEvent where
parseJSON = fromPacket "disconnect-evnet" $ \o -> DisconnectEvent
<$> o .: "reason"
{- hello-event -}
data HelloEvent = HelloEvent data HelloEvent = HelloEvent
{ helloAccount :: Maybe PersonalAccountView { helloAccount :: Maybe PersonalAccountView
, helloSessionView :: SessionView , helloSessionView :: SessionView
@ -200,7 +251,18 @@ data HelloEvent = HelloEvent
, helloVersion :: T.Text , helloVersion :: T.Text
} deriving (Show) } deriving (Show)
data JoinEvent = JoinEvent instance FromJSON HelloEvent where
parseJSON = fromPacket "hello-event" $ \o -> HelloEvent
<$> o .: "account"
<*> o .: "session"
<*> o .:? "account_has_access"
<*> o .:? "account_email_verified"
<*> o .: "room_is_private"
<*> o .: "version"
{- join-event -}
newtype JoinEvent = JoinEvent
{ joinSession :: SessionView { joinSession :: SessionView
} deriving (Show) } deriving (Show)
@ -208,19 +270,40 @@ instance FromJSON JoinEvent where
parseJSON = fromPacket "join-event" $ \o -> JoinEvent parseJSON = fromPacket "join-event" $ \o -> JoinEvent
<$> parseJSON (Object o) <$> parseJSON (Object o)
data LoginEvent = LoginEvent {- login-event -}
newtype LoginEvent = LoginEvent
{ loginAccountId :: Snowflake { loginAccountId :: Snowflake
} deriving (Show) } deriving (Show)
instance FromJSON LoginEvent where
parseJSON = fromPacket "login-event" $ \o -> LoginEvent
<$> o .: "acount_id"
{- logout-event -}
data LogoutEvent = LogoutEvent data LogoutEvent = LogoutEvent
deriving (Show) deriving (Show)
instance FromJSON LogoutEvent where
parseJSON = fromPacket "logout-event" $ const (pure LogoutEvent)
{- network-event -}
data NetworkEvent = NetworkEvent data NetworkEvent = NetworkEvent
{ networkType :: T.Text -- always "partition" { networkType :: T.Text -- always "partition"
, networkServerId :: T.Text , networkServerId :: T.Text
, networkServerEra :: T.Text , networkServerEra :: T.Text
} deriving (Show) } deriving (Show)
instance FromJSON NetworkEvent where
parseJSON = fromPacket "network-event" $ \o -> NetworkEvent
<$> o .: "type"
<*> o .: "server_id"
<*> o .: "server_era"
{- nick-event -}
data NickEvent = NickEvent data NickEvent = NickEvent
{ nickSessionId :: T.Text { nickSessionId :: T.Text
, nickId :: UserId , nickId :: UserId
@ -228,12 +311,28 @@ data NickEvent = NickEvent
, nickTo :: T.Text , nickTo :: T.Text
} deriving (Show) } deriving (Show)
instance FromJSON NickEvent where
parseJSON = fromPacket "nick-event" $ \o -> NickEvent
<$> o .: "session_id"
<*> o .: "id"
<*> o .: "from"
<*> o .: "to"
{- edit-message-event -}
data EditMessageEvent = EditMessageEvent data EditMessageEvent = EditMessageEvent
{ editMessageMessage :: Message { editMessageMessage :: Message
, editMessageEditId :: Snowflake , editMessageEditId :: Snowflake
} deriving (Show) } deriving (Show)
data PartEvent = PartEvent instance FromJSON EditMessageEvent where
parseJSON = fromPacket "EditMessageEvent" $ \o -> EditMessageEvent
<$> parseJSON (Object o)
<*> o .: "edit_id"
{- part-event -}
newtype PartEvent = PartEvent
{ partSession :: SessionView { partSession :: SessionView
} deriving (Show) } deriving (Show)
@ -241,6 +340,8 @@ instance FromJSON PartEvent where
parseJSON = fromPacket "part-event" $ \o -> PartEvent parseJSON = fromPacket "part-event" $ \o -> PartEvent
<$> parseJSON (Object o) <$> parseJSON (Object o)
{- ping-event -}
data PingEvent = PingEvent data PingEvent = PingEvent
{ pingTime :: UTCTime { pingTime :: UTCTime
, pingNext :: UTCTime , pingNext :: UTCTime
@ -251,6 +352,8 @@ instance FromJSON PingEvent where
<$> (posixSecondsToUTCTime <$> o .: "time") <$> (posixSecondsToUTCTime <$> o .: "time")
<*> (posixSecondsToUTCTime <$> o .: "next") <*> (posixSecondsToUTCTime <$> o .: "next")
{- pm-initiate-event -}
data PmInitiateEvent = PmInitiateEvent data PmInitiateEvent = PmInitiateEvent
{ pmInitiateFrom :: UserId { pmInitiateFrom :: UserId
, pmInitiateFromNick :: T.Text , pmInitiateFromNick :: T.Text
@ -258,7 +361,16 @@ data PmInitiateEvent = PmInitiateEvent
, pmInitiatePmId :: Snowflake , pmInitiatePmId :: Snowflake
} deriving (Show) } deriving (Show)
data SendEvent = SendEvent instance FromJSON PmInitiateEvent where
parseJSON = fromPacket "pm-initiate-event" $ \o -> PmInitiateEvent
<$> o .: "from"
<*> o .: "from_nick"
<*> o .: "from_room"
<*> o .: "pm_id"
{- send-event -}
newtype SendEvent = SendEvent
{ sendMessage :: Message { sendMessage :: Message
} deriving (Show) } deriving (Show)
@ -294,15 +406,30 @@ instance FromJSON SnapshotEvent where
{- auth -} {- auth -}
data AuthCommand = AuthWithPasscode T.Text newtype AuthCommand = AuthWithPasscode T.Text
deriving (Show) deriving (Show)
instance ToJSONObject AuthCommand where
toJSONObject (AuthWithPasscode password) = toPacket "auth" $ object
[ "type" .= Passcode
, "passcode" .= password
]
data AuthReply = AuthSuccessful | AuthFailed T.Text data AuthReply = AuthSuccessful | AuthFailed T.Text
deriving (Show) deriving (Show)
instance FromJSON AuthReply where
parseJSON = fromPacket "auth-reply" $ \o -> do
success <- o .: "success"
if success
then pure AuthSuccessful
-- The "reason" field *should* be filled in if the authentication fails,
-- but I'm always treating it as optional to be on the safe side.
else AuthFailed <$> o .:? "reason" .!= ""
{- ping -} {- ping -}
data PingCommand = PingCommand UTCTime newtype PingCommand = PingCommand UTCTime
deriving (Show) deriving (Show)
instance ToJSONObject PingCommand where instance ToJSONObject PingCommand where
@ -310,7 +437,7 @@ instance ToJSONObject PingCommand where
[ "time" .= utcTimeToPOSIXSeconds time [ "time" .= utcTimeToPOSIXSeconds time
] ]
data PingReply = PingReply UTCTime newtype PingReply = PingReply UTCTime
deriving (Show) deriving (Show)
instance ToJSONObject PingReply where instance ToJSONObject PingReply where
@ -324,9 +451,48 @@ instance FromJSON PingReply where
{- Chat room commands -} {- Chat room commands -}
{- get-message -}
newtype GetMessageCommand = GetMessageCommand Snowflake
deriving (Show)
instance ToJSONObject GetMessageCommand where
toJSONObject (GetMessageCommand mId) = toPacket "get-message" $ object
[ "id" .= mId
]
newtype GetMessageReply = GetMessageReply Message
deriving (Show)
instance FromJSON GetMessageReply where
parseJSON = fromPacket "get-message-reply" $ \o -> GetMessageReply
<$> parseJSON (Object o)
{- log -}
data LogCommand = LogCommand Int (Maybe Snowflake)
deriving (Show)
instance ToJSONObject LogCommand where
toJSONObject (LogCommand n Nothing) = toPacket "log" $ object
[ "n" .= n
]
toJSONObject (LogCommand n (Just before)) = toPacket "log" $ object
[ "n" .= n
, "before" .= before
]
data LogReply = LogReply [Message] (Maybe Snowflake)
deriving (Show)
instance FromJSON LogReply where
parseJSON = fromPacket "log-reply" $ \o -> LogReply
<$> o .: "log"
<*> o .:? "before"
{- nick -} {- nick -}
data NickCommand = NickCommand T.Text newtype NickCommand = NickCommand T.Text
deriving (Show) deriving (Show)
instance ToJSONObject NickCommand where instance ToJSONObject NickCommand where
@ -348,6 +514,24 @@ instance FromJSON NickReply where
<*> o .: "from" <*> o .: "from"
<*> o .: "to" <*> o .: "to"
{- pm-initiate -}
newtype PmInitiateCommand = PmInitiateCommand UserId
deriving (Show)
instance ToJSONObject PmInitiateCommand where
toJSONObject (PmInitiateCommand userId) = toPacket "pm-initiate" $ object
[ "user_id" .= userId
]
data PmInitiateReply = PmInitiateReply Snowflake T.Text
deriving (Show)
instance FromJSON PmInitiateReply where
parseJSON = fromPacket "pm-intiate-reply" $ \o -> PmInitiateReply
<$> o .: "pm_id"
<*> o .: "to_nick"
{- send -} {- send -}
data SendCommand = SendCommand T.Text (Maybe Snowflake) data SendCommand = SendCommand T.Text (Maybe Snowflake)
@ -359,9 +543,24 @@ instance ToJSONObject SendCommand where
toJSONObject (SendCommand content (Just parent)) = toJSONObject (SendCommand content (Just parent)) =
toPacket "send" $ object ["content" .= content, "parent" .= parent] toPacket "send" $ object ["content" .= content, "parent" .= parent]
data SendReply = SendReply Message newtype SendReply = SendReply Message
deriving (Show) deriving (Show)
instance FromJSON SendReply where instance FromJSON SendReply where
parseJSON = fromPacket "send-reply" $ \o -> SendReply parseJSON = fromPacket "send-reply" $ \o -> SendReply
<$> parseJSON (Object o) <$> parseJSON (Object o)
{- who -}
data WhoCommand = WhoCommand
deriving (Show)
instance ToJSONObject WhoCommand where
toJSONObject WhoCommand = toPacket "who" $ object []
newtype WhoReply = WhoReply [SessionView]
deriving (Show)
instance FromJSON WhoReply where
parseJSON = fromPacket "who-reply" $ \o -> WhoReply
<$> o .: "listing"

View file

@ -27,12 +27,19 @@ module Haboli.Euphoria.Client
, wait , wait
-- ** Euphoria commands -- ** Euphoria commands
-- *** Session commands -- *** Session commands
, auth
, ping
, pingReply , pingReply
-- *** Chat room commands -- *** Chat room commands
, getMessage
, getLog
, getLogBefore
, nick , nick
, Haboli.Euphoria.Client.send , initiatePm
, send
, reply , reply
, reply' , reply'
, who
) where ) where
import Control.Applicative import Control.Applicative
@ -51,7 +58,7 @@ import qualified Data.Map.Strict as Map
import Data.Maybe import Data.Maybe
import qualified Data.Text as T import qualified Data.Text as T
import Data.Time import Data.Time
import Network.Socket import qualified Network.Socket as S
import qualified Network.WebSockets as WS import qualified Network.WebSockets as WS
import qualified Wuss as WSS import qualified Wuss as WSS
@ -172,8 +179,8 @@ runWebsocketThread info =
-- | Configuration for the websocket connection. The websocket connection always -- | Configuration for the websocket connection. The websocket connection always
-- uses https. -- uses https.
data ConnectionConfig = ConnectionConfig data ConnectionConfig = ConnectionConfig
{ cdHost :: HostName { cdHost :: S.HostName
, cdPort :: PortNumber , cdPort :: S.PortNumber
, cdPath :: String , cdPath :: String
, cdPingInterval :: Int , cdPingInterval :: Int
} deriving (Show) } deriving (Show)
@ -205,7 +212,7 @@ withRoom room config = config{cdPath = "/room/" ++ room ++ "/ws"}
-- connection are not caught. This will probably change soon. -- connection are not caught. This will probably change soon.
runClient :: ConnectionConfig -> Client e a -> IO (Either (ClientException e) a) runClient :: ConnectionConfig -> Client e a -> IO (Either (ClientException e) a)
runClient details (Client stack) = runClient details (Client stack) =
withSocketsDo $ S.withSocketsDo $
WSS.runSecureClient (cdHost details) (cdPort details) (cdPath details) $ \connection -> do WSS.runSecureClient (cdHost details) (cdPort details) (cdPath details) $ \connection -> do
awaiting <- newTVarIO Map.empty awaiting <- newTVarIO Map.empty
eventChan <- newTChanIO eventChan <- newTChanIO
@ -457,22 +464,67 @@ sendPacketWithReply packet = do
{- Session commands -} {- Session commands -}
-- | Try to authenticate with a password and return the error reason if it
-- *doesn't* succeed.
auth :: T.Text -> Client e (Either T.Text ())
auth password = do
answer <- sendPacketWithReply $ AuthWithPasscode password
pure $ case answer of
AuthSuccessful -> Right ()
AuthFailed reason -> Left reason
-- | Send a ping (not a websocket ping) to the server, who has to reply with the
-- same time stamp.
ping :: UTCTime -> Client e UTCTime
ping time = do
PingReply time' <- sendPacketWithReply $ PingCommand time
pure time'
-- | Send a reply to a 'PingEvent' sent by the server. -- | Send a reply to a 'PingEvent' sent by the server.
pingReply :: UTCTime -> Client e () pingReply :: UTCTime -> Client e ()
pingReply = void . sendPacket . PingReply pingReply = void . sendPacket . PingReply
{- Chat room commands -} {- Chat room commands -}
-- | Change your own nick. Returns the new nick. -- | Retrieve the full content of a single message in the room.
nick :: T.Text -> Client e T.Text getMessage :: Snowflake -> Client e Message
getMessage mId = do
GetMessageReply msg <- sendPacketWithReply $ GetMessageCommand mId
pure msg
-- | @'getLog' n@ requests @n@ messages from the room's log, starting with the
-- latest message and going backwards by the send time/message id.
getLog :: Int -> Client e [Message]
getLog n = do
LogReply msgs _ <- sendPacketWithReply $ LogCommand n Nothing
pure msgs
-- | @'getLogBefore' n before@ works similar to @'getLog' n@, but it requests
-- messages starting with the latest message before the message with id
-- @before@.
getLogBefore :: Int -> Snowflake -> Client e [Message]
getLogBefore n before = do
LogReply msgs _ <- sendPacketWithReply $ LogCommand n (Just before)
pure msgs
-- | Initiate a PM with another user. Returns a tuple @(pmId, toNick)@, where
-- @pmId@ is the id of the PM room, and @toNick@ is the nick of the user the
-- request was sent to.
initiatePm :: UserId -> Client e (Snowflake, T.Text)
initiatePm uId = do
PmInitiateReply pmId toNick <- sendPacketWithReply $ PmInitiateCommand uId
pure (pmId, toNick)
-- | Change your own nick. Returns a tuple @(oldNick, newNick)@.
nick :: T.Text -> Client e (T.Text, T.Text)
nick targetNick = do nick targetNick = do
answer <- sendPacketWithReply $ NickCommand targetNick answer <- sendPacketWithReply $ NickCommand targetNick
pure $ nickReplyTo answer pure (nickReplyFrom answer, nickReplyTo answer)
-- | Send a new top-level message. Returns the sent message. -- | Send a new top-level message. Returns the sent message.
send :: T.Text -> Client e Message send :: T.Text -> Client e Message
send content = do send content = do
(SendReply msg) <- sendPacketWithReply $ SendCommand content Nothing SendReply msg <- sendPacketWithReply $ SendCommand content Nothing
pure msg pure msg
-- | Reply to a message via its id. Returns the sent message. -- | Reply to a message via its id. Returns the sent message.
@ -486,3 +538,9 @@ reply' messageId content = do
-- This function is equivalent to @'reply'' . 'msgId'@. -- This function is equivalent to @'reply'' . 'msgId'@.
reply :: Message -> T.Text -> Client e Message reply :: Message -> T.Text -> Client e Message
reply = reply' . msgId reply = reply' . msgId
-- | See who is currently connected to the room.
who :: Client e [SessionView]
who = do
WhoReply sessions <- sendPacketWithReply WhoCommand
pure sessions