Skip to content

Instantly share code, notes, and snippets.

@rgaudin
Created May 1, 2013 14:02
Show Gist options
  • Save rgaudin/5495424 to your computer and use it in GitHub Desktop.
Save rgaudin/5495424 to your computer and use it in GitHub Desktop.
Kannel Formhub Gateway
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4 nu
''' Example Kannel Service Gateway for use with Formhub
This gateway will receive a message from Kannel and forward it to
the Formhub SMS API.
The Formhub SMS API will reply with a status for the submission and
a text message for the end user.
The gateway will forward the message to the SMS sender via Kannel
If the submission is accepted, an `id` is provided.
Statuses:
SMS_SUBMISSION_ACCEPTED
SMS_API_ERROR
SMS_PARSING_ERROR
SMS_SUBMISSION_ACCEPTED
SMS_SUBMISSION_REFUSED
SMS_INTERNAL_ERROR
This code is meant to be an example of querying the Formhub API.
Please refer to formhub.org for extended documentation.
Dependencies:
requests (pip install requests)
cherrypy (pip install cherrypy)
Sample Kannel configuration:
group = sms-service
keyword = default
catch-all = yes
accepted-smsc = usb0-modem
max-messages = 0
get-url = http://localhost:8000/new/?identity=%p&text=%a '''
import json
import logging as log
import cherrypy
import requests
# Port for this script's HTTP server. Must match Kannel's config
LOCAL_SERVER_PORT = 8080
# URL of the Kannel HTTP send-message API
KANNEL_URL = 'http://localhost:13013/cgi-bin/sendsms'
# Use this to set parameters to the send-sms API of Kannel.
# Example:
# KANNEL_PAYLOAD = {'smsc': 'usb0-modem', 'from': '+199887766',
# 'username': 'anton', 'password': 'xxxxx'}
KANNEL_PAYLOAD = {}
# setting your formhub username is mandatory.
# it's the username of the owner of the target form.
FORMHUB_USERNAME = 'reg'
# the `id_string` of the form to submit text submissions to.
# If set to None, the form-unaware endpoint will be called
# and message will be routed according to the `sms_keyword` inside the text.
FORMHUB_FORM = None
# Formhub endpoints (don't change)
FORMHUB_SMS_SUBMISSION = 'http://localhost:8000/{username}/sms_submission' \
.format(username=FORMHUB_USERNAME,
id_string=FORMHUB_FORM)
FORMHUB_SMS_SUBMISSION_FORM = 'https://formhub.org/{username}/forms/' \
'%(id_string)s/sms_submission' \
.format(username=FORMHUB_USERNAME,
id_string=FORMHUB_FORM)
def send_message_to_kannel(identity, text):
''' send response SMS via Kannel's send-sms API '''
params = KANNEL_PAYLOAD
params.update({'to': identity, 'text': text})
try:
req = requests.get(KANNEL_URL, params=params)
req.raise_for_status()
except (requests.exceptions.HTTPError, requests.ConnectionError) as e:
# unable to send the reply via kannel. We should log the message
# and retry later.
log.critical(u"Unable to send response to Kannel – %r" % e)
return False
return True
class SMSReceiver:
@cherrypy.expose
def index(self):
return "SMS receiver working."
@cherrypy.expose
def new(self, identity=None, text=None):
# we're not into empty or anonymous message
if not identity or not text:
return
# selecting endpoint based on knwoledge of Form's id_string.
url = FORMHUB_SMS_SUBMISSION if FORMHUB_FORM is None \
else FORMHUB_SMS_SUBMISSION_FORM
try:
# sends the text message to Formhub and create a submission.
req = requests.get(url, params={'identity': identity,
'text': text})
# raise an Exception if status not in 200/201
req.raise_for_status()
except (requests.exceptions.HTTPError, requests.ConnectionError):
# this should prevent kannel from discarding the
# incoming sms and add it to retry spool.
log.critical("can't connect to formhub.")
raise cherrypy.HTTPError(500, u"Formhub reply incorrect.")
# retrieve formhub's response
response = json.loads(req.content)
if response.get('code') == 'SMS_SUBMISSION_ACCEPTED':
# do something with the submission ID
log.info(u"Submission %(id)s created by %(identity)s"
% {'id': response.get('id'), 'identity': identity})
else:
# the submission failed (it did not create a submission)
log.debug(u"%(identity)s sent an erroneous submission -- %(text)s"
% {'identity': identity, 'text': text})
if send_message_to_kannel(identity, response.get('message')):
log.debug(u"Response sent to sender via kannel")
return "Message Processed."
def main():
cherrypy.quickstart(SMSReceiver(), '/',
{'global': {'server.socket_port': LOCAL_SERVER_PORT}})
if __name__ == '__main__':
try:
log.info("started.")
main()
log.shutdown()
except KeyboardInterrupt:
log.warning("shutdown with ^C.")
log.shutdown()
exit()
except Exception, e:
log.error("shutdown by exception: %r" % e)
log.shutdown()
exit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment