Exemplo n.º 1
0
    def __init__(self):
        from twisted.internet import reactor
        self.agent = Agent(reactor)
        self.signature_method = oauth.SignatureMethod_HMAC_SHA1()
        self.previous_tweets = None

        # If we receive tweets before we fetch the old ones, queue them up
        # to be run later
        self.tweet_queue = []
        self.longify = Longifyer()

        self.get_previous_tweets()
Exemplo n.º 2
0
class Tweeter(object):
    TWEET_URL = "https://api.twitter.com/1.1/statuses/update.json"
    TIMELINE_URL = "https://api.twitter.com/1.1/statuses/user_timeline.json"
    PREVIOUS_TWEET_COUNT = 10
    FAILED_RESPONSE_RETRY_SECS = 10

    class StringProducer(object):
        implements(IBodyProducer)

        def __init__(self, body):
            self.body = body
            self.length = len(body)

        def startProducing(self, consumer):
            consumer.write(self.body)
            return succeed(None)

        def pauseProducing(self):
            pass

        def stopProducing(self):
            pass

        def resumeProducing(self):
            pass

    def __init__(self):
        from twisted.internet import reactor
        self.agent = Agent(reactor)
        self.signature_method = oauth.SignatureMethod_HMAC_SHA1()
        self.previous_tweets = None

        # If we receive tweets before we fetch the old ones, queue them up
        # to be run later
        self.tweet_queue = []
        self.longify = Longifyer()

        self.get_previous_tweets()


    def _getAuthorization(self, parameters):
        req = oauth.Request.from_consumer_and_token(
            consumer=CONSUMER,
            token=ACCESS_TOKEN,
            http_method='POST',
            http_url=self.TWEET_URL,
            parameters=parameters,
            is_form_encoded=True
            )

        req.sign_request(self.signature_method,
                         token=ACCESS_TOKEN,
                         consumer=CONSUMER)
        return req.to_postdata()

    def tweet(self, status):
        if self.previous_tweets is None:
            d = Deferred()
            d.addCallback(self.tweet)
            self.tweet_queue = d, status
            return d
        elif status in self.previous_tweets:
            log.msg('Already tweeted "{}"'.format(status),
                    logLevel=logging.WARNING)
            return succeed(('5xx', 'Duplicate tweet'))

        parameters = {'status': status}
        auth_body = self._getAuthorization(parameters)
        headers = {'content-type': ['application/x-www-form-urlencoded']}
        d = self.agent.request('POST', self.TWEET_URL,
                               headers=Headers(headers),
                               bodyProducer=self.StringProducer(auth_body))
        d.addCallback(receive_response)
        # If it's a success, save it.
        d.addCallback(self._save_tweeted)
        return d

    def _save_tweeted(self, response, status):
        self.previous_tweets.add(status)
        # Pass through the response
        return response

    def get_previous_tweets(self):
        params = {'trim_user': True, 'count': self.PREVIOUS_TWEET_COUNT}

        req = oauth.Request.from_consumer_and_token(
            consumer=CONSUMER,
            token=ACCESS_TOKEN,
            http_method='GET',
            http_url=self.TIMELINE_URL,
            parameters=params)
        req.sign_request(self.signature_method,
                         token=ACCESS_TOKEN,
                         consumer=CONSUMER)

        d = self.agent.request('GET', str(req.to_url()))
        d.addErrback(self._retry_on_failure)
        d.addCallback(receive_response)
        d.addCallback(self._lengthen_tweets)
        d.addCallback(self._send_queued_tweets)
        return d

    def _retry_on_failure(self, failure):
        log.err(failure, "Failed to receive previous tweets, trying again in "
                "{}  seconds".format(self.FAILED_RESPONSE_RETRY_SECS))

        from twisted.internet import reactor
        reactor.callLater(self.FAILED_RESPONSE_RETRY_SECS,
                          self.get_previous_tweets)

    def _lengthen_tweets(self, response):
        code, tweet_json = response
        call_later = False
        if code != 200:
            return fail(IOError(
                "Received response code {}: {}".format(code, tweet_json)))
        try:
            previous_tweets = {tweet['text'] for tweet
                                             in json.loads(tweet_json)}
            log.msg("Previous tweets: {}".format(self.previous_tweets))

        except (KeyError, ValueError):
            return fail()
        dl = DeferredList([self.longify.replace_all(tweet)
                           for tweet in previous_tweets])
        dl.addCallback(self._save_tweets)

    def _save_tweets(self, tweets):
        self.previous_tweets = {tweet for status, tweet in tweets}
        log.msg("Lengthed tweets: {}".format(self.previous_tweets))

    def _send_queued_tweets(self, _):
        while self.tweet_queue:
            d, status = self.tweet_queue.pop()
            d.callback(status)