[asterisk-dev] [Code Review] New application JabberReceive, implement SendText in chan_gtalk and chan_jingle
John Todd
jtodd at digium.com
Sat Dec 13 00:59:40 CST 2008
On Dec 12, 2008, at 12:37 PM, Philippe Sultan wrote:
>> After some thought, I'd have to agree with Russell on this as well -
>> there needs to be some way to capture messages that would be sent
>> prior to the JabberRecieve being called.
>
> Agreed too :).
>
>> [note: the next two paragraphs are the start of what will become a
>> very, very long set of religious discussions and gnashing of teeth
>> and
>> tearing of hair]
>>
>> Why? Because I suspect that this will almost immediately become
>> another API method for Asterisk. It's an ugly, horrible, nasty
>> hackish API but guess what - it'll work for most people doing
>> lightweight interactions who are already using Jabber. Machine-to-
>> Machine interactions via XMPP is becoming common, and therefore the
>> responses back from JabberSend will be lightning fast in many
>> instances, and even the time it takes for a few dialplan events may
>> be
>> too long to correctly receive an inbound reply from an outbound
>> message. At the very least, the implementation that gets shipped
>> first should be able to handle immediate responses to transmitted
>> messages that may be generated by other systems otherwise the first
>> impressions will be the last impressions someone gets on using this
>> method, and it will create bogus summaries and manual pages that will
>> be difficult or impossible to correct later - "You can't use the
>> JabberSend/JabberReceive apps in Asterisk for fast responses because
>> they will lose messages." would be an example of what I do NOT want
>> to
>> see. There will certainly be problems with M2M systems using XMPP in
>> this way, but such a significant one I think we should avoid on our
>> first step into the minefield.
>>
>> Of course, an API should have the ability to create actions in a
>> system, but the elements Russell mentions (global receipt of XMPP
>> messages) makes that a fairly simple jump. My opinion is that XMPP
>> messages should be received globally on any JIDs registered in
>> jabber.conf, and then should execute in the dialplan on a per-
>> registration context (just like any other channel) using the
>> registered JID as the $EXTEN, using the remote JID as the caller ID,
>> and setting the text value as a dialplan variable. But... one step
>> at a time, I suppose. :-)
>
> That's really interesting, but wouldn't you loose the ability to call
> JabberReceive within any place in the dialplan then? This is something
> that needs to be investigated.
Now that I think of it that way, yes, it does present a problem. But
I've got a solution a bit further down.
Regardless of any future implementation of XMPP messages creating new
channels, I believe that JabberReceive might be best to understand two
modes, a "non-buffered receive" and a "buffered receive". It may make
sense for default behavior to listen to buffered responses, and an
optional declaration to not look at the buffer. Perhaps (though I
don't outline it below) there would be a timer option as well - "go
back a maximum of X seconds to look for messages that match this
criteria when executing a JabberReceive."
Danger, Danger: If there is a buffer for received XMPP messages, there
should be some hand-tunable timeout for messages that linger in the
buffer, otherwise there is a risk of memory exhaustion from attackers
or unintentionally broken and chatty remote systems.
Of course, now that I've had some more time to think about this, more
obvious problems come to light when using XMPP as a machine-to-machine
transport in a high-volume system. The biggest one you've already
touched on, Philippe, is "threading" in a message. If there are
multiple calls happening that all use the XMPP send/receive methods,
then there needs to be some way that the XMPP handler can ensure (or
try to ensure) that the right messages are handed to the right call
flows. It seems that the "threading" option you mentioned is the best
way to do it, but you also said that it's poorly implemented in
clients. This may not matter so much to anyone using an automated
system, since they'll probably be building their own kit out of fairly
modern code which undersatnds (or can be made to understand) the
thread/ element. For chats with humans, this may actually also be
important - what happens if I get two calls at once and I have an
automated system that sends me messages about sending calls to
voicemail? While my XMPP client might not handle it today (Adium on
Mac) but it appears that as soon as libpurple is ready it may be
useful (http://trac.adiumx.com/ticket/8319).
I know that XEP is in "draft" status, which makes me wonder how M2M
implementations of XMPP are being handled currently. Without knowing
a thread identifier or some other transactional state message, how do
two JIDs communicate about many different simultaneous sessions?
Putting something in the message seems like a hack that is so bad that
it would never be done. Any XMPP experts out there? It does seem
like implementations are at least considering that XEP for similar
reasons.
http://xmpp.org/extensions/xep-0201.html
Here's the hypothetical set of commands with the modification concepts
I talked about:
*CLI> core show application JabberReceive
-= Info about application 'JabberReceive' =-
[Synopsis]
JabberReceive will receive a text message from a remote XMPP client and
store the contents in a given variable.
[Description]
Same as Synopsis.
[Syntax]
JabberReceive(JID,Variable[,Timeout][,Account][,ThreadID][,options])
[Arguments]
JID - Jabber ID of the buddy to receive message from
Variable - Variable to store message in
Timeout - Defaults to 20 seconds
Account - the local named account to listen on (specified in
jabber.conf)
ThreadID - the thread ID for this conversation (ignores other
ThreadIDs if set)
options -
R - accept messages in "realtime", and do not match against
buffered messages
which may have been in the queue before this app was activated
[See Also]
JabberSend, JabberStatus
*CLI>
This would also require JabberSend to get a "ThreadID" setting:
core1*CLI>
-= Info about application 'JabberSend' =-
[Synopsis]
JabberSend will send an arbitrary text message to a given XMPP
destination
[Description]
Same as Description.
[Syntax]
JabberSend(Account,JID,Message[,ThreadID])
[Arguments]
Account - Client or transport Asterisk uses to connect to XMPP
network.
This is the named account in jabber.conf.
JID - XMPP/Jabber JID (Name) of recipient
Message - Text message to be sent to the buddy
ThreadID - (optional) unique ThreadID to associate with message
flow. This
should be either a unique universal value for new sessions or
should be set
to the value expected by the receiver to continue a particular
thread.
[See Also]
JabberReceive, JabberStatus
Things Not To Be Done Right Now: If and when a "call" (new message)
is instantiated to some global receiver of XMPP messages to a specific
JID, the process could be something like this: create a new "call" to
the context= line IF there is no JabberReceive waiting that matches
the correct sending JID AND that JabberReceive does not have a
matching thread identifier. If there are two JabberReceive
applications waiting that match both the sender JID, receiver account
JID, and have an empty or unknown thread/ element, then whatever
JabberReceive has been waiting the longest has the message passed to
it. This, I believe, would lead to the reasonable "expected" response
for all cases I can think of, and would allow XMPP messages to
activate dialplan code. The decisions on what the $EXTEN is and all
that other stuff can be hashed out later.
>> Philippe - I understand that it works now the way you have it, but
>> would it delay implementation significantly? Are you on a roll, and
>> could you keep that momentum going to add the pre-buffering or global
>> receipt that has been discussed above? I think there is an
>> opportunity to have a big leap in functionality of Asterisk, and it's
>> your code that's at the heart of that advancement.
>
> No problem, I'll come up with the new implementation as soon as
> possible. Plus, given the way messages are stored (e.g. in a structure
> within the XMPP client), your suggestion of including the account JID
> we're listening messages on becomes mandatory :)
Sorry for the feature creep issues. This is an interesting track to
take, and I think many people are interested in getting better control
of their Asterisk boxes via XMPP. I'm getting to the point where
almost 100% of my interactions are through XMPP - AOL, MSN, Yahoo, SIP
(yes, SIP messaging), Twitter, Yammer, and one-way Asterisk are all
gatewayed or directly connected via XMPP, and my IM client also
controls Skype and Facebook via APIs (though I wish they were XMPP
gateways as well.) Being able to _control_ my Asterisk system via
XMPP will really, really be useful and will open up another push of
development in the Enterprise area which is now starting to see the
wisdom of XMPP as the protocol of choice. Getting the inbound
messages today is already super-handy - Asterisk burps out missed
calls and other statistical data without my having to be actively
engaged with a console or a web browser or anything. Being eventually
able to TELL my Asterisk system to "call +14102241145" or "show
missed" or "dial missed last" or "voicemail delete last" - that would
be freakin' GREAT. I'm sure that's all possible now with external
programs and AGI scripts and callfiles, but I'd like to do it in a
more integrated way.
PS: We should really change all these "Jabber" terms and app names to
"XMPP".
JT
---
John Todd
jtodd at digium.com +1-256-428-6083
Asterisk Open Source Community Director
More information about the asterisk-dev
mailing list