Created
May 1, 2013 14:02
-
-
Save rgaudin/5495424 to your computer and use it in GitHub Desktop.
Kannel Formhub Gateway
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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