Last active
          August 29, 2015 14:08 
        
      - 
      
- 
        Save alejandrobernardis/957fe8b4ad45902ae8d2 to your computer and use it in GitHub Desktop. 
    (Tornado Async) A little hack for boto.SESConnections
  
        
  
    
      This file contains hidden or 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 python2.7 | |
| # -*- coding: utf-8 -*- | |
| # Copyright (c) 2014 Asumi Kamikaze Inc. | |
| # Licensed under the MIT License. | |
| # Author: Alejandro M. Bernardis | |
| # Email: alejandro (dot) bernardis (at) asumikamikaze (dot) com | |
| # Created: 06/Nov/2014 19:27 | |
| import boto | |
| from boto import jsonresponse | |
| from boto.connection import AWSAuthConnection | |
| from boto.ses import SESConnection | |
| from tornado import gen | |
| from tornado.httpclient import AsyncHTTPClient, HTTPRequest, HTTPResponse | |
| from urllib import urlencode | |
| __all__ = ( | |
| 'AsyncSESConnection', | |
| 'AWS_SES_ENDPOINTS', | |
| 'AWS_SES_SUPPORTED_ARGS' | |
| ) | |
| class SESHTTPResponse(object): | |
| def __init__(self, status, reason): | |
| self.status = status | |
| self.reason = reason | |
| class AsyncAWSAuthConnection(AWSAuthConnection): | |
| @gen.coroutine | |
| def _mexe(self, request, sender=None, *args, **kwargs): | |
| if not isinstance(request.body, bytes) \ | |
| and hasattr(request.body, 'encode'): | |
| request.body = request.body.encode('utf-8') | |
| request.authorize(connection=self) | |
| boto.log.debug('Method: %s' % request.method) | |
| boto.log.debug('Path: %s' % request.path) | |
| boto.log.debug('Data: %s' % request.body) | |
| boto.log.debug('Headers: %s' % request.headers) | |
| boto.log.debug('Host: %s' % request.host) | |
| boto.log.debug('Port: %s' % request.port) | |
| boto.log.debug('Params: %s' % request.params) | |
| url = '{protocol}://{host}:{port}{path}'\ | |
| .format(protocol=request.protocol, host=request.host, | |
| port=request.port, path=request.path) | |
| async_request = HTTPRequest(url) | |
| async_request.method = request.method | |
| async_request.headers = request.headers | |
| if request.body: | |
| async_request.body = request.body | |
| if callable(sender): | |
| async_response = yield sender(async_request) | |
| else: | |
| async_response = yield AsyncHTTPClient().fetch(async_request) | |
| raise gen.Return(async_response) | |
| AWS_SES_ENDPOINTS = { | |
| "eu-west-1": "email.eu-west-1.amazonaws.com", | |
| "us-east-1": "email.us-east-1.amazonaws.com", | |
| "us-west-2": "email.us-west-2.amazonaws.com", | |
| "eu-central-1": "email.eu-central-1.amazonaws.com" | |
| } | |
| AWS_SES_SUPPORTED_ARGS = ( | |
| 'aws_access_key_id', 'aws_secret_access_key', 'is_secure', 'port', | |
| 'proxy', 'proxy_port', 'proxy_user', 'proxy_pass', 'debug', | |
| 'https_connection_factory', 'region', 'path', 'security_token', | |
| 'validate_certs', 'profile_name' | |
| ) | |
| class AsyncSESConnection(AsyncAWSAuthConnection, SESConnection): | |
| _content_type = 'application/x-www-form-urlencoded; charset=UTF-8' | |
| @gen.coroutine | |
| def _make_request(self, action, params=None): | |
| headers = {'Content-Type': self._content_type} | |
| try: | |
| if not params: | |
| params = {} | |
| params['Action'] = action | |
| for key, value in params.items(): | |
| if not isinstance(value, unicode): | |
| continue | |
| params[key] = value.encode() | |
| response = yield self.make_request( | |
| 'POST', '/', headers=headers, data=urlencode(params)) | |
| if isinstance(response, HTTPResponse): | |
| body = response.body.decode('utf-8') | |
| if response.code == 200: | |
| response = jsonresponse.Element( | |
| list_marker=('VerifiedEmailAddresses', 'Identities', | |
| 'DkimTokens', 'VerificationAttributes', | |
| 'SendDataPoints'), | |
| item_marker=('member', 'item', 'entry') | |
| ) | |
| json_response = jsonresponse.XmlHandler(response, None) | |
| json_response.parse(body) | |
| else: | |
| response = SESHTTPResponse(response.code, response.reason) | |
| self._handle_error(response, body) | |
| else: | |
| response = ValueError('Bad response') | |
| except Exception, e: | |
| response = ValueError(str(e)) | |
| raise gen.Return(response) | |
| # --- test --- | |
| @gen.coroutine | |
| def run(): | |
| from boto.regioninfo import RegionInfo | |
| AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") | |
| keys = ['key', 'secret_key'] | |
| region = RegionInfo(None, 'us-west-2', 'email.us-west-2.amazonaws.com') | |
| ses = AsyncSESConnection(region=region, *keys) | |
| try: | |
| res = yield ses.list_verified_email_addresses() | |
| print res | |
| except Exception, e: | |
| print e | |
| ioloop.IOLoop.instance().stop() | |
| run() | |
| from tornado import ioloop | |
| ioloop.IOLoop.instance().start() | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment