# Path: autopush/exceptions.py
# class ItemNotFound(Exception):
#     """Signals missing DynamoDB Item data"""
# 
# class RouterException(AutopushException):
#     """Exception if routing has failed, may include a custom status_code and
#     body to write to the response.
# 
#     """
#     def __init__(self, message, status_code=500, response_body="",
#                  router_data=None, headers=None, log_exception=True,
#                  errno=None, logged_status=None, **kwargs):
#         """Create a new RouterException"""
#         super(AutopushException, self).__init__(message)
#         self.status_code = status_code
#         self.headers = {} if headers is None else headers
#         self.log_exception = log_exception
#         self.response_body = response_body or message
#         self.errno = errno
#         self.logged_status = logged_status
#         self.extra = kwargs
# 
# Path: autopush/metrics.py
# def make_tags(base=None, **kwargs):
#     # type: (Sequence[str], **Any) -> Sequence[str]
#     """Generate a list of tag values"""
#     tags = list(base or [])
#     tags.extend('{}:{}'.format(key, val) for key, val in kwargs.iteritems())
#     return tags
# 
# Path: autopush/protocol.py
# class IgnoreBody(Protocol):
#     """A protocol that discards any data it receives
# 
#     This is necessary to support persistent HTTP connections. If the
#     response body is never read using ``Response.deliverBody``, or
#     ``stopProducing()`` is called, the connection will not be reused.
# 
#     """
#     def __init__(self, response, deferred):
#         self.response = response
#         self.deferred = deferred
# 
#     @classmethod
#     def ignore(cls, response):
#         """Class method helper for ignoring the response"""
#         d = Deferred()
#         if response is not None:
#             response.deliverBody(cls(response, d))
#         return d
# 
#     def dataReceived(self, data):
#         """Ignore received data"""
#         pass
# 
#     def connectionLost(self, reason):
#         """Relay back the loss of connection to the deferred"""
#         if reason.check(ResponseDone):
#             self.deferred.callback(self.response)
#         else:
#             self.deferred.errback(reason)
#         del self.response
#         del self.deferred
# 
# Path: autopush/router/interface.py
# class RouterResponse(object):
#     """Router response if routing has succeeded.
# 
#     If the router data needs to change as a result of this message, either the
#     router got invalidated, or needs updating, then the router_data should be
#     set.
# 
#     """
#     def __init__(self, status_code=200, response_body="", router_data=None,
#                  headers=None, errno=None, logged_status=None):
#         """Create a new RouterResponse"""
#         self.status_code = status_code
#         self.response_body = response_body
#         self.router_data = router_data
#         self.headers = {} if headers is None else headers
#         self.errno = errno
#         self.logged_status = logged_status
# 
# Path: autopush/types.py



import json
import time
from StringIO import StringIO
from typing import Any  # noqa
from botocore.exceptions import ClientError
from twisted.internet.threads import deferToThread
from twisted.web.client import FileBodyProducer
from twisted.internet.defer import (
    inlineCallbacks,
    returnValue,
    CancelledError,
)
from twisted.internet.error import (
    ConnectError,
    ConnectionClosed,
    ConnectionRefusedError,
)
from twisted.logger import Logger
from twisted.web._newclient import ResponseFailed
from twisted.web.http import PotentialDataLoss
from autopush.exceptions import ItemNotFound, RouterException
from autopush.metrics import make_tags
from autopush.protocol import IgnoreBody
from autopush.router.interface import RouterResponse
from autopush.types import JSONDict  # noqa
        url = node_id + "/notif/" + uaid
        return self.agent.request(
            "PUT",
            url.encode("utf8"),
        ).addCallback(IgnoreBody.ignore)

    def _save_notification(self, uaid_data, notification):
        """Saves a notification, returns a deferred.

        This version of the overridden method saves each individual message
        to the message table along with relevant request headers if
        available.

        :type uaid_data: dict

        """
        month_table = uaid_data["current_month"]
        if notification.ttl is None:
            # Note that this URL is temporary, as well as this warning as
            # we will 400 all missing TTL's eventually
            raise RouterException(
                "Missing TTL Header",
                response_body="Missing TTL Header, see: %s" % TTL_URL,
                status_code=400,
                errno=111,
                log_exception=False,
            )
        if notification.ttl == 0:
            location = "%s/m/%s" % (self.conf.endpoint_url,
                                    notification.version)

# Path: autopush/exceptions.py
# class ItemNotFound(Exception):
#     """Signals missing DynamoDB Item data"""
# 
# class RouterException(AutopushException):
#     """Exception if routing has failed, may include a custom status_code and
#     body to write to the response.
# 
#     """
#     def __init__(self, message, status_code=500, response_body="",
#                  router_data=None, headers=None, log_exception=True,
#                  errno=None, logged_status=None, **kwargs):
#         """Create a new RouterException"""
#         super(AutopushException, self).__init__(message)
#         self.status_code = status_code
#         self.headers = {} if headers is None else headers
#         self.log_exception = log_exception
#         self.response_body = response_body or message
#         self.errno = errno
#         self.logged_status = logged_status
#         self.extra = kwargs
# 
# Path: autopush/metrics.py
# def make_tags(base=None, **kwargs):
#     # type: (Sequence[str], **Any) -> Sequence[str]
#     """Generate a list of tag values"""
#     tags = list(base or [])
#     tags.extend('{}:{}'.format(key, val) for key, val in kwargs.iteritems())
#     return tags
# 
# Path: autopush/protocol.py
# class IgnoreBody(Protocol):
#     """A protocol that discards any data it receives
# 
#     This is necessary to support persistent HTTP connections. If the
#     response body is never read using ``Response.deliverBody``, or
#     ``stopProducing()`` is called, the connection will not be reused.
# 
#     """
#     def __init__(self, response, deferred):
#         self.response = response
#         self.deferred = deferred
# 
#     @classmethod
#     def ignore(cls, response):
#         """Class method helper for ignoring the response"""
#         d = Deferred()
#         if response is not None:
#             response.deliverBody(cls(response, d))
#         return d
# 
#     def dataReceived(self, data):
#         """Ignore received data"""
#         pass
# 
#     def connectionLost(self, reason):
#         """Relay back the loss of connection to the deferred"""
#         if reason.check(ResponseDone):
#             self.deferred.callback(self.response)
#         else:
#             self.deferred.errback(reason)
#         del self.response
#         del self.deferred
# 
# Path: autopush/router/interface.py
# class RouterResponse(object):
#     """Router response if routing has succeeded.
# 
#     If the router data needs to change as a result of this message, either the
#     router got invalidated, or needs updating, then the router_data should be
#     set.
# 
#     """
#     def __init__(self, status_code=200, response_body="", router_data=None,
#                  headers=None, errno=None, logged_status=None):
#         """Create a new RouterResponse"""
#         self.status_code = status_code
#         self.response_body = response_body
#         self.router_data = router_data
#         self.headers = {} if headers is None else headers
#         self.errno = errno
#         self.logged_status = logged_status
# 
# Path: autopush/types.py



# Path: autopush/router/webpush.py
import json
import time
from StringIO import StringIO
from typing import Any  # noqa
from botocore.exceptions import ClientError
from twisted.internet.threads import deferToThread
from twisted.web.client import FileBodyProducer
from twisted.internet.defer import (
    inlineCallbacks,
    returnValue,
    CancelledError,
)
from twisted.internet.error import (
    ConnectError,
    ConnectionClosed,
    ConnectionRefusedError,
)
from twisted.logger import Logger
from twisted.web._newclient import ResponseFailed
from twisted.web.http import PotentialDataLoss
from autopush.exceptions import ItemNotFound, RouterException
from autopush.metrics import make_tags
from autopush.protocol import IgnoreBody
from autopush.router.interface import RouterResponse
from autopush.types import JSONDict  # noqa

        url = node_id + "/notif/" + uaid
        return self.agent.request(
            "PUT",
            url.encode("utf8"),
        ).addCallback(IgnoreBody.ignore)

    def _save_notification(self, uaid_data, notification):
        """Saves a notification, returns a deferred.

        This version of the overridden method saves each individual message
        to the message table along with relevant request headers if
        available.

        :type uaid_data: dict

        """
        month_table = uaid_data["current_month"]
        if notification.ttl is None:
            # Note that this URL is temporary, as well as this warning as
            # we will 400 all missing TTL's eventually
            raise RouterException(
                "Missing TTL Header",
                response_body="Missing TTL Header, see: %s" % TTL_URL,
                status_code=400,
                errno=111,
                log_exception=False,
            )
        if notification.ttl == 0:
            location = "%s/m/%s" % (self.conf.endpoint_url,
                                    notification.version)

            raise RouterException("Finished Routing", status_code=201,