This is the first part of an occasional series where I will use the UCMA API to create a functioning bot over IM. Unlike my first UCMA series, I will not post new parts every day but over time I will create a series on this.
Today’s post starts from the sample I displayed at TechEd. This is very similar to the sixteen part series I recently finished and it is basically the server from that example modified to send alerts and respond to messages. To communicate with the bot, just send it a message and it will respond.
I have posted the code in this blog and most of the code is very straightforward with one change from my last series. I chose going forward to use Communicator as my client and only worry about developing the middle tier server piece. Note that this is the preferred use for the UCMA API – it is not intended to create client applications. For client applications – use UCCA or CWA (which I hope to cover sometime later).
The problem that I ran into is Communicator has a peculiarity where it will send the MESSAGE immediately after sending the INVITE. The code I posted in my sixteen part series expected the INVITE dialog to be setup first and only then the MESSAGE to be sent. Since Communicator sends both one after another, the INVITE would succeed but the MESSAGE would fail. Subsequent MESSAGE messages would succeed because by then the INVITE dialog was setup. The reason this occurred was the default behavior if we do not handle the MessageReceived event is to refuse the MESSAGE. Since we did not setup the event until the dialog was setup (after the call to EndParticipate), our application was not listening at the time the MESSAGE was received and therefore UCMA refused the message.
Fixing this was a little tricky, but is essential for any middle tier bot that wishes to communicate with Communicator. The first change was the move the call to BeginParticipate to my AllInOneSession class, which means that accepting the session is now the job of the AllInOneSession object. When I receive a session, I immediately create an AllInOneSession object and have it manage the call to Participate and EndParticipate.
This allowed my AllInOneSession class to immediately setup a handler for the MessageReceived event, which meant the MESSAGE would no longer be rejected. I still had one slight problem though – what if the MESSAGE arrived before we had finished accepting the session? Actually the real problem here is our response to the message. If the user sends a “hello” message and we want to response “hello”, we must wait for the session to be established. In order to accomplish this, I created a boolean to track whether the session has been established and then queue all messages to send until the session has been established. Once the session is established, I look for any messages on the queue and send them. In order for this to be thread safe, I needed to add some synchronization logic.
Admittedly, my bot logic is rather crude. For now all I do is compare the string to some known strings and respond accordingly. In terms of signaling, we actually have most of the logic we need right now. The area we will need to improve on in the future is making our bot smarter in its responses.