@ -13,10 +13,11 @@ import Network.Xmpp.Concurrent.Basic
import Network.Xmpp.Concurrent.Types
import Network.Xmpp.Concurrent.Types
import Network.Xmpp.Types
import Network.Xmpp.Types
-- | Sends an IQ, returns Right 'TMVar' that will be filled with the first
-- | Sends an IQ, returns an STM action that returns the first inbound IQ with a
-- inbound IQ with a matching ID that has type @result@ or @error@ or Nothing if
-- matching ID that has type @result@ or @error@ or Nothing if the timeout was
-- the stanza could not be sent.
-- reached.
-- Returns Left 'XmppFailure' when sending the stanza failed
--
-- When sending the action fails, an XmppFailure is returned.
sendIQ :: Maybe Integer -- ^ Timeout . When the timeout is reached the response
sendIQ :: Maybe Integer -- ^ Timeout . When the timeout is reached the response
-- TMVar will be filled with 'IQResponseTimeout' and the
-- TMVar will be filled with 'IQResponseTimeout' and the
-- id is removed from the list of IQ handlers. 'Nothing'
-- id is removed from the list of IQ handlers. 'Nothing'
@ -27,7 +28,7 @@ sendIQ :: Maybe Integer -- ^ Timeout . When the timeout is reached the response
-- default)
-- default)
-> Element -- ^ The IQ body (there has to be exactly one)
-> Element -- ^ The IQ body (there has to be exactly one)
-> Session
-> Session
-> IO ( Either XmppFailure ( TMVar ( Maybe ( Annotated IQResponse ) ) ) )
-> IO ( Either XmppFailure ( S TM ( Maybe ( Annotated IQResponse ) ) ) )
sendIQ timeOut to tp lang body session = do
sendIQ timeOut to tp lang body session = do
newId <- idGenerator session
newId <- idGenerator session
j <- case to of
j <- case to of
@ -47,7 +48,7 @@ sendIQ timeOut to tp lang body session = do
Just t -> void . forkIO $ do
Just t -> void . forkIO $ do
delay t
delay t
doTimeOut ( iqHandlers session ) newId ref
doTimeOut ( iqHandlers session ) newId ref
return $ Right ref
return . Right $ readTMVar ref
Left e -> return $ Left e
Left e -> return $ Left e
where
where
doTimeOut handlers iqid var = atomically $ do
doTimeOut handlers iqid var = atomically $ do
@ -68,7 +69,7 @@ sendIQA' :: Maybe Integer
sendIQA' timeout to tp lang body session = do
sendIQA' timeout to tp lang body session = do
ref <- sendIQ timeout to tp lang body session
ref <- sendIQ timeout to tp lang body session
either ( return . Left . IQSendError ) ( fmap ( maybe ( Left IQTimeOut ) Right )
either ( return . Left . IQSendError ) ( fmap ( maybe ( Left IQTimeOut ) Right )
. atomically . takeTMVar ) ref
. atomically ) ref
-- | Like 'sendIQ', but waits for the answer IQ. Discards plugin Annotations
-- | Like 'sendIQ', but waits for the answer IQ. Discards plugin Annotations
sendIQ' :: Maybe Integer
sendIQ' :: Maybe Integer
@ -80,21 +81,17 @@ sendIQ' :: Maybe Integer
-> IO ( Either IQSendError IQResponse )
-> IO ( Either IQSendError IQResponse )
sendIQ' timeout to tp lang body session = fmap fst <$> sendIQA' timeout to tp lang body session
sendIQ' timeout to tp lang body session = fmap fst <$> sendIQA' timeout to tp lang body session
-- | Retrieves an IQ listener channel. If the namespace/'IQRequestType' is not
-- | Register your interest in inbound IQ stanzas of a specific type and
-- already handled, a new 'TChan' is created and returned as a 'Right' value.
-- namespace. The returned STM action yields the received, matching IQ stanzas.
-- Otherwise, the already existing channel will be returned wrapped in a 'Left'
-- value. The 'Left' channel might need to be duplicated in order not
-- to interfere with existing consumers.
--
--
-- Note thet every 'IQRequest' must be answered exactly once. To insure this,
-- If a handler for IQ stanzas with the given type and namespace is already
-- the incoming requests are wrapped in an 'IQRequestTicket' that prevents
-- registered, the producer will be wrapped in Left. In this case the returned
-- multiple responses. Use 'iqRequestBody' to extract the corresponding request
-- request tickets may already be processed elsewhere.
-- and 'answerIQ' to send the response
listenIQ :: IQRequestType -- ^ Type of IQs to receive ('Get' or 'Set')
listenIQChan :: IQRequestType -- ^ Type of IQs to receive ('Get' or 'Set')
-> Text -- ^ Namespace of the child element
-> Text -- ^ Namespace of the child element
-> Session
-> Session
-> IO ( Either ( TChan IQRequestTicket ) ( TChan IQRequestTicket ) )
-> IO ( Either ( STM IQRequestTicket ) ( STM IQRequestTicket ) )
listenIQChan tp ns session = do
listenIQ tp ns session = do
let handlers = ( iqHandlers session )
let handlers = ( iqHandlers session )
atomically $ do
atomically $ do
( byNS , byID ) <- readTVar handlers
( byNS , byID ) <- readTVar handlers
@ -105,18 +102,20 @@ listenIQChan tp ns session = do
iqCh
iqCh
byNS
byNS
writeTVar handlers ( byNS' , byID )
writeTVar handlers ( byNS' , byID )
return $ case present of
case present of
Nothing -> Right iqCh
Nothing -> return . Right $ readTChan iqCh
Just iqCh' -> Left iqCh'
Just iqCh' -> do
clonedChan <- cloneTChan iqCh'
return . Left $ readTChan clonedChan
-- | Unregister a previously acquired IQ channel. Please make sure that you
-- | Unregister a previously registered IQ handler. No more IQ stanzas will be
-- where the one who acquired it in the first place as no check for ownership
-- delivered to any of the returned producers.
-- can be made
unlistenIQ :: IQRequestType -- ^ Type of IQ ('Get' or 'Set')
dropIQChan :: IQRequestType -- ^ Type of IQ ('Get' or 'Set')
-> Text -- ^ Namespace of the child element
-> Text -- ^ Namespace of the child element
-> Session
-> Session
-> IO ()
-> IO ()
dropIQChan tp ns session = do
unlistenIQ tp ns session = do
let handlers = ( iqHandlers session )
let handlers = ( iqHandlers session )
atomically $ do
atomically $ do
( byNS , byID ) <- readTVar handlers
( byNS , byID ) <- readTVar handlers