Cloud World

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Tuesday, 30 July 2013

Multi-Channel Chat with Twilio and Google App Engine

Posted on 06:00 by Unknown
Today’s post comes from Kevin Whinnery, Developer Evangelist at Twilio. In this post, Kevin describes how to build a multi-channel chat application using Google App Engine and Twilio. You can follow Kevin on Twitter at @kevinwhinnery or on Google+.







Google App Engine enables developers to focus on their application’s logic by providing a scalable infrastructure and high-level APIs for persistence, file management, and other common web app needs. XMPP and Channels are among these APIs, making it ridiculously easy to write awesome real-time communications apps in the browser.



Today, we’re going to break down an example application (view it live, source code) that integrates these two App Engine services (plus SMS messaging from Twilio) in a group chat application that connects users via SMS, XMPP, and browser-based chat clients.



We won’t go through every line of code, but at a high level, this application is about receiving inbound messages and sending outbound messages. Let’s see how we do this via SMS, XMPP, and Channels.



Twilio SMS

Sending SMS text messages with the Twilio API requires signing up for a Twilio account. Once you’ve signed up for an account, you can use your account SID and auth token to make authenticated requests against the Twilio REST API. You could just use App Engine’s built-in URL fetch service to interact with the Twilio API, but our official helper library for Java makes authenticating requests and serializing data much easier, providing a POJO interface to Twilio resources and functionality. We’ll be using the Twilio helper in this example. If you’re looking for App Engine specific reference examples, our friends at Google included this reference documentation in their doc site.



In our chat application, all outbound communication and message dispatching is handled by the MultichannelChatManager class. In this application, we add subscribers to the chat room to an in-memory set. When it’s time to send out a message, we iterate over the members of this set and send out messages to all subscribers. We send out messages to SMS subscribers using the Twilio helper on line #56:

TwilioRestClient client = new TwilioRestClient("ACCOUNT_SID", "AUTH_TOKEN");

Map params = new HashMap();
params.put("Body", messageBody);
params.put("To", sub);
params.put("From", "+16122948105");

SmsFactory messageFactory = client.getAccount().getSmsFactory();

try {
Sms message = messageFactory.create(params);
System.out.println(message.getSid());
} catch (TwilioRestException e) {
e.printStackTrace();
}
To receive inbound communication, you will need to purchase a Twilio phone number or use the one given to you when you signed up for a Twilio account. You can configure this phone number to send an HTTP POST to a URL that you choose when an SMS message is received (this callback pattern is called a webhook). In this sample application, we have a Java servlet with a web.xml file configured to accept inbound SMS. In your Twilio number configuration, you would enter https://yourappname.appspot.com/sms, as below:



In the actual servlet, we handle inbound SMS messages first by looking for a “STOP” command, which will indicate that this user no longer wants to receive text messages from the app. Then, we confirm that the user is subscribed (by looking for their telephone number). Finally, we send out a message using our MultichannelChatManager class.



When Twilio sends your app the details of an SMS message with an HTTP request, it expects your app to respond with an XML format called TwiML. TwiML is a simple set of fewer than 20 XML tags that tells Twilio how to respond to inbound communication. The output of our SMS servlet is an XML (TwiML) document, which will send an SMS back to a user if they unsubscribe:

public class TwilioSmsServlet extends HttpServlet {
// Handle Incoming SMS
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
TwiMLResponse twiml = new TwiMLResponse();

// parse the body, looking for a command
String smsBody = request.getParameter("Body");
String smsFrom = request.getParameter("From");

// Unsubscribe, if requested
if (smsBody.startsWith("STOP")) {
MultichannelChatManager.removeSub(smsFrom);
com.twilio.sdk.verbs.Sms bye = new com.twilio.sdk.verbs.Sms("You have been unsubscribed. Thank You!");
twiml.append(bye);
} else {
// If they aren't subscribed, subscribe them
if (!MultichannelChatManager.isSubscribed(smsFrom)) {
MultichannelChatManager.addSub(smsFrom);
}
MultichannelChatManager.sendMessage(smsBody, "sms");
}

response.setContentType("application/xml");
response.getWriter().print(twiml.toXML());

} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
}
}
}

App Engine XMPP Integration

App Engine provides a simple API for sending and receiving XMPP chat messages. Our chat application can receive new messages over XMPP and send them back out to all subscribed clients, similar to how our app behaves for SMS.



App Engine applications have an XMPP username associated with them by default, which takes the form of “appname@appspot.com”. The former part of the username is your unique App Engine app ID and the latter is the appspot domain that your app runs on. To send a message via XMPP to our chat app we need to send a chat message to “twiliosandbox@appspot.com” from a chat client that supports XMPP. If you used the desktop chat client Adium for Google Talk, the interaction might look something like this:



For our application to receive inbound XMPP messages, we need to configure an inbound message handler servlet in our web.xml configuration file. This webhook callback design is the same type of event mechanism used by Twilio to deliver SMS messages to our application. In this servlet, we receive an inbound POST request with information about an inbound chat message:

public class XMPPReceiverServlet extends HttpServlet {
// Handle Incoming XMPP Chat messages
public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
XMPPService xmpp = XMPPServiceFactory.getXMPPService();
Message msg = xmpp.parseMessage(req);

// The "JID" is the unique ID of this chat client, which we use to subscribe
JID fromJid = msg.getFromJid();
String body = msg.getBody();

// Unsubscribe, if requested
if (body.startsWith("STOP")) {
MultichannelChatManager.removeSub(fromJid.getId());
} else {
// If they aren't subscribed, subscribe them
if (!MultichannelChatManager.isSubscribed(fromJid.getId())) {
MultichannelChatManager.addSub(fromJid.getId());
}
MultichannelChatManager.sendMessage(body, "xmpp");
}
}
}
To send outbound messages, we use the App Engine platform APIs to send an outbound message to a specific JID, which uniquely identifies a connected XMPP client:

JID jid = new JID(sub);
Message msg = new MessageBuilder().withRecipientJids(jid).withBody(messageBody).build();
XMPPService xmpp = XMPPServiceFactory.getXMPPService();
xmpp.sendMessage(msg);

Channel API

The Channel API allows server-side push to connected clients in an App Engine application. In our chat application, we will utilize this API to push new chat messages to browser-based clients.



In order for our server to push chat messages to a browser, the client needs to be issued an ID by our server. We configure a servlet to handle issuing these IDs (and to handle incoming chat messages created by the browser in JavaScript) in web.xml. The servlet generates a unique ID for a connected client, based on the current system time:

//Generate a client token for the GAE Channel API
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
ChannelService channelService = ChannelServiceFactory.getChannelService();

//The token must be based on some unique identifier for the client - I am using the current time
//for demo purposes...
String clientId = String.valueOf(System.currentTimeMillis());
String token = channelService.createChannel(clientId);

//Subscribe this client
MultichannelChatManager.addSub(clientId);

//Reply with the token
res.setContentType("text/plain");
res.getWriter().print(token);
}
In the browser, we get an ID for the current user via XHR. First, we include the Channel client JavaScript library by requesting a special URL on the App Engine server. Then we use jQuery to issue a GET request to our server to obtain a client ID:

//Get a client token to use with the channel API
$.ajax('/chat',{
method:'GET',
dataType:'text',
success: function(token) {
console.log(token);
var channel = new goog.appengine.Channel(token);
var socket = channel.open();

//Assign our handler function to the open socket
socket.onmessage = onMessage;
}
});
When we get our client ID, we use that to configure the App Engine channel service in the browser for data pushed from the server. Data pushed from the server is handled in a callback function, which updates the textarea on the page. When the user enters a chat message in the browser, we issue a POST request to our ChatServlet, which uses the MultichannelChatManager class to publish a message to all connected clients. This is where we use the channel API to push data to connected web browsers:

ChannelService channelService = ChannelServiceFactory.getChannelService();
channelService.sendMessage(new ChannelMessage(sub,messageBody));

Wrapping Up

In this walkthrough, we explored three messaging APIs that work nicely on App Engine: Twilio SMS, XMPP, and Channels. Our example used Java, but all three APIs will work with Python and Go as well (Twilio has a helper library you might use for Python also).



Using platforms like Twilio and App Engine, developers can create communications applications, which previously would have required expert knowledge and infrastructure to build, in a fraction of the time. I hope you’ll be able to use these APIs to engage with your users wherever they happen to be.



Application source code is available on GitHub here.



- Contributed by Kevin Whinnery, Developer Evangelist, Twilio
Email ThisBlogThis!Share to XShare to Facebook
Posted in | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • Bridging Mobile Backend as a Service to Enterprise Systems with Google App Engine and Kinvey
    The following post was contributed by Ivan Stoyanov , VP of Engineering for Kinvey, a mobile Backend as a Service provider and Google Cloud ...
  • Tutorial: Adding a cloud backend to your application with Android Studio
    Android Studio lets you easily add a cloud backend to your application, right from your IDE. A backend allows you to implement functionality...
  • 2013 Year in review: topping 100,000 requests-per-second
    2013 was a busy year for Google Cloud Platform. Watch this space: each day, a different Googler who works on Cloud Platform will be sharing ...
  • Easy Performance Profiling with Appstats
    Since App Engine debuted 2 years ago, we’ve written extensively about best practices for writing scalable apps on App Engine. We make writ...
  • TweetDeck and Google App Engine: A Match Made in the Cloud
    I'm Reza and work in London, UK for a startup called TweetDeck . Our vision is to develop the best tools to manage and filter real time ...
  • Scaling with the Kindle Fire
    Today’s blog post comes to us from Greg Bayer of Pulse , a popular news reading application for iPhone, iPad and Android devices. Pulse has ...
  • Who's at Google I/O: Mojo Helpdesk
    This post is part of Who's at Google I/O , a series of guest blog posts written by developers who are appearing in the Developer Sandbox...
  • A Day in the Cloud, new articles on scaling, and fresh open source projects for App Engine
    The latest release of Python SDK 1.2.3, which introduced the Task Queue API and integrated support for Django 1.0, may have received a lot ...
  • SendGrid gives App Engine developers a simple way of sending transactional email
    Today’s guest post is from Adam DuVander, Developer Communications Director at SendGrid. SendGrid is a cloud-based email service that deliv...
  • Qubole helps you run Hadoop on Google Compute Engine
    This guest post comes form Praveen Seluka, Software Engineer at Qubole, a leading provider of Hadoop-as-a-service.  Qubole is a leading pr...

Categories

  • 1.1.2
  • agile
  • android
  • Announcements
  • api
  • app engine
  • appengine
  • batch
  • bicycle
  • bigquery
  • canoe
  • casestudy
  • cloud
  • Cloud Datastore
  • cloud endpoints
  • cloud sql
  • cloud storage
  • cloud-storage
  • community
  • Compute Engine
  • conferences
  • customer
  • datastore
  • delete
  • developer days
  • developer-insights
  • devfests
  • django
  • email
  • entity group
  • events
  • getting started
  • google
  • googlenew
  • gps
  • green
  • Guest Blog
  • hadoop
  • html5
  • index
  • io2010
  • IO2013
  • java
  • kaazing
  • location
  • mapreduce
  • norex
  • open source
  • partner
  • payment
  • paypal
  • pipeline
  • put
  • python
  • rental
  • research project
  • solutions
  • support
  • sustainability
  • taskqueue
  • technical
  • toolkit
  • twilio
  • video
  • websockets
  • workflows

Blog Archive

  • ▼  2013 (143)
    • ►  December (33)
    • ►  November (15)
    • ►  October (17)
    • ►  September (13)
    • ►  August (4)
    • ▼  July (15)
      • How Safari Books Online uses Google BigQuery for b...
      • Multi-Channel Chat with Twilio and Google App Engine
      • Google App Engine: Hello World using Push-to-Deploy
      • SendGrid gives App Engine developers a simple way ...
      • Create dynamic web projects in Eclipse
      • New in Google Cloud Storage: auto-delete, regional...
      • Dedicated memcache preview now available on Google...
      • Google App Engine 1.8.2 released
      • Help us improve Google Cloud Platform by participa...
      • Get up and Running with Cassandra on Google Comput...
      • Lock-in, what lock-in?
      • Development in the Cloud with Codenvy and Google C...
      • See how to test drive Virtual Machines on Google C...
      • IT Operations Management for Google Compute Engine...
      • Google App Engine takes the pain out of sending iO...
    • ►  June (12)
    • ►  May (15)
    • ►  April (4)
    • ►  March (4)
    • ►  February (9)
    • ►  January (2)
  • ►  2012 (43)
    • ►  December (2)
    • ►  November (2)
    • ►  October (8)
    • ►  September (2)
    • ►  August (3)
    • ►  July (4)
    • ►  June (2)
    • ►  May (3)
    • ►  April (4)
    • ►  March (5)
    • ►  February (3)
    • ►  January (5)
  • ►  2011 (46)
    • ►  December (3)
    • ►  November (4)
    • ►  October (4)
    • ►  September (5)
    • ►  August (3)
    • ►  July (4)
    • ►  June (3)
    • ►  May (8)
    • ►  April (2)
    • ►  March (5)
    • ►  February (3)
    • ►  January (2)
  • ►  2010 (38)
    • ►  December (2)
    • ►  October (2)
    • ►  September (1)
    • ►  August (5)
    • ►  July (5)
    • ►  June (6)
    • ►  May (3)
    • ►  April (5)
    • ►  March (5)
    • ►  February (2)
    • ►  January (2)
  • ►  2009 (47)
    • ►  December (4)
    • ►  November (3)
    • ►  October (6)
    • ►  September (5)
    • ►  August (3)
    • ►  July (3)
    • ►  June (4)
    • ►  May (3)
    • ►  April (5)
    • ►  March (3)
    • ►  February (7)
    • ►  January (1)
  • ►  2008 (46)
    • ►  December (4)
    • ►  November (3)
    • ►  October (10)
    • ►  September (5)
    • ►  August (6)
    • ►  July (4)
    • ►  June (2)
    • ►  May (5)
    • ►  April (7)
Powered by Blogger.

About Me

Unknown
View my complete profile