ScaleConf Workshop - Writing an Application

In this section we’ll be writing a minimal Twitter clone in Python using SMS as the communication channel. @imsickofmaps suggested we call it “smitter”.

Setting up the SMS Transport

First, to use SMS we need to setup the SMS transport. This is the same procedure as setting up the USSD transport. Use this as the template and save it in a file called “sms_transport.yaml” (note that we’re using a different value for ‘transport_name’):

transport_name: sms_transport
account_key: <your account key>
access_token: <your acccess token>
conversation_key: <your conversation key>

middleware:
    - logging_mw: vumi.middleware.logging.LoggingMiddleware

logging_mw:
    log_level: debug

Add the following bits to the “supervisord.conf” file created earlier:

[program:sms_transport]
command=twistd -n
    --pidfile=./tmp/pids/%(program_name)s.pid
    vumi_worker
    --worker-class=vumi.transports.vumi_bridge.GoConversationTransport
    --config=./sms_transport.yaml
stdout_logfile=./logs/%(program_name)s_%(process_num)s.log
stderr_logfile=./logs/%(program_name)s_%(process_num)s.err

[program:smitter]
command=twistd -n
    --pidfile=./tmp/pids/%(program_name)s.pid
    vumi_worker
    --worker-class=scaleconf.SmitterApplication
    --set-option=worker_name:smitter_worker
    --set-option=transport_name:sms_transport
stdout_logfile=./logs/%(program_name)s_%(process_num)s.log
stderr_logfile=./logs/%(program_name)s_%(process_num)s.err

Writing your application

Create a file called scaleconf.py put in the following code and replace the place holder text with your South African phone number as a string:

from vumi.application import ApplicationWorker


class SmitterApplication(ApplicationWorker):

    def setup_application(self):
        return self.send_to("27.....", 'hi there!')

    def consume_user_message(self, message):
        return self.reply_to(message, 'thanks!')

Tell supervisord to add the new processes:

$ supervisorctl -c etc/supervisord.conf update

Within a few seconds you should receive an SMS from your application. If you reply to this number then you’ll receive “thanks” back.

Making things more interesting

What we want to do is the following:

  1. People join by SMSing ‘+’ to your SMS longcode.
  2. People leave by SMSing in ‘-‘ to your SMS longcode.
  3. Anything else is broadcast to all known users currently joined.
from twisted.internet.defer import inlineCallbacks

from vumi.application import ApplicationWorker


class SmitterApplication(ApplicationWorker):

    def setup_application(self):
        self.members = set()

    @inlineCallbacks
    def consume_user_message(self, message):
        if message['content'] == '+':
            self.members.add(message.user())
            yield self.reply_to(
                message, 'You have joined Smitter! SMS "-" to leave.')
        elif message['content'] == '-':
            self.members.remove(message.user())
            yield self.reply_to(
                message, 'You have left Smitter. SMS "+" to join.')
        else:
            yield self.reply_to(
                message, 'Broadcast to %s members' % (len(self.members) - 1,))
            for member in self.members:
                if member != message.user():
                    yield self.send_to(member, message['content'])

Tell supervisord to restart the smitter application:

$ supervisorctl -c etc/supervisord.conf restart smitter

SMS ‘+’ to the SMS longcode and you should receive a confirmation. Ask someone else to join and test if the broadcasting and leaving works.

More Features!

Now that we’ve got a very minimal application running, here are some features you could look at adding to make improve it.

  1. Add the ability to form groups.
  2. Add the ability to invite people to join via SMS.
  3. Add persistence via vumi.persist.txredis_manager.TxRedisManager to allow multiple Smitter processes to run in Supervisord while sharing data.