class ProtoEventHandler(BatchHandler):
    """Http handler for receiving proto event batches."""

    def init_input_format(self, body):
        proto_request = EventMessage_pb2.BatchEventRequest()
        proto_request.ParseFromString(body)
        return proto_request

    def unpack_batch(self, request):
        return request.events

    def create_request(self, requests):
        valid_requests = []
        validator = ProtoEventValidator()
        for request in requests:
            if validator.validate_single(request):
                valid_requests.append(EventRequestSingle(request.user_id, request.event_id, {pair.key:pair.value for pair in request.pairs}, request.timestamp))
            else:
                context.main_logger.error("Request not valid: {req}".format(req=str(request.__dict__)))

        return EventRequestBatch(valid_requests) class JsonEventHandler(BatchHandler):
    """Http handler for receiving JSON event batches."""

    def init_input_format(self, body):
        return json.loads(body)

    def unpack_batch(self, request):
        return request['events']

    def create_request(self, requests):
        valid_requests = []
        validator = JsonEventValidator()
        for request in requests:
            if validator.validate_single(request):
                valid_requests.append(EventRequestSingle(request['user_id'], request['event_id'], request['pairs'] if 'pairs' in request else {}, request['timestamp']))

        return EventRequestBatch(valid_requests) class ProtoNotificationHandler(BatchHandler):
    """Http handler for receiving proto notification batches."""

    def init_input_format(self, body):
        proto_request = PushNotificationMessage_pb2.BatchNotificationRequest()
        proto_request.ParseFromString(body)
        return proto_request

    def unpack_batch(self, request_proto):
        return request_proto.notifications

    def create_request(self, requests):
        valid_requests = []
        validator = ProtoNotificationValidator()
        for request in requests:
            if validator.validate_single(request):
                valid_requests.append(NotificationRequestSingle(request.login_id, request.title, request.content))

        return NotificationRequestBatch(valid_requests) class JsonNotificationHandler(BatchHandler):
    """Http handler for receiving JSON notification batches."""

    def init_input_format(self, body):
        return json.loads(body)

    def unpack_batch(self, request):
        return request['notifications']

    def create_request(self, requests):
        valid_requests = []
        validator = JsonNotificationValidator()
        for request in requests:
            if validator.validate_single(request):
                valid_requests.append(NotificationRequestSingle(request['login_id'], request['title'], request['content']))

        return NotificationRequestBatch(valid_requests) class RequestProcessor(ProcessPool):
    """Background thread pool for doing blocking tasks from server requests and offloading notifications to other processes."""

    def __init__(self):
        ProcessPool.__init__(self, self.__class__.__name__, config.request_processor_num_threads,
                            config.request_queue_limit)
        self.sender_manager = NotificationSenderManager()

    def process(self):
        while True:
            item = self.task_queue.get()
            t0 = time.time()
            worker_name = threading.current_thread().name
            try:
                item.process()
                context.main_logger.debug(
                    "{worker} took: {took} seconds to process {item}".format(worker=worker_name, took=time.time() - t0,
                                                                             item=item.__class__.__name__))
            except Exception:
                context.main_logger.exception("RequestProcessor failed to process item: {}".format(item))

    def start(self):
        ProcessPool.start(self)
        self.sender_manager.start() class EventHandlerManager():
    """Responsible for invoking event handlers for given events."""

    def __init__(self):
        self._event_handler_map = defaultdict(list)
        self._build()

    def _add_event_handler(self, handler):
        self._event_handler_map[handler.event_id].append(handler)

    def _build(self):
        self._add_event_handler(LoginEventHandler())
        self._add_event_handler(TurnOffNotificationEventHandler())
        event_to_message_mapping = database.get_event_to_message_mapping()
        for event_id, message_ids in event_to_message_mapping.iteritems():
            self._add_event_handler(EventToMessagesHandler(event_id, message_ids))

    def get_handlers(self, event_id):
        return self._event_handler_map[event_id]

    def get_event_ids(self):
        return self._event_handler_map.keys() class RequestQueueHandler(tornado.web.RequestHandler):
    """Responds with number of items in RequestProcessor."""

    def get(self):
        try:
            queue_size = context.request_processor.queue_size()
            self.write(str(queue_size))
        except:
            context.main_logger.exception(
                "Could not get queue size for request processor!")
            raise tornado.web.HTTPError(400) class ApnSenderQueueHandler(tornado.web.RequestHandler):
    """Responds with number of items in ApnSenderProcessor."""

    def get(self):
        try:
            sender_name = 'pushkin.sender.senders.ApnNotificationSender'
            queue_size = context.request_processor.sender_manager.sender_by_name[sender_name].queue_size()
            self.write(str(queue_size))
        except:
            context.main_logger.exception(
                "Could not get queue size for sender {}!".format(sender_name))
            raise tornado.web.HTTPError(400) class GcmSenderQueueHandler(tornado.web.RequestHandler):
    """Responds with number of items in GcmSenderProcessor."""

    def get(self):
        try:
            sender_name = 'pushkin.sender.senders.GcmNotificationSender'
            queue_size = context.request_processor.sender_manager.sender_by_name[sender_name].queue_size()
            self.write(str(queue_size))
        except:
            context.main_logger.exception(
                "Could not get queue size for sender {}!".format(sender_name))
            raise tornado.web.HTTPError(400) class NotificationPostProcessorQueue(tornado.web.RequestHandler):
    """Responds with number of items in NotificationPostProcessor."""

    def get(self):
        try:
            queue_size = context.request_processor.sender_manager.notification_post_processor.queue_size()
            self.write(str(queue_size))
        except:
            context.main_logger.exception(
                "Could not get queue size for notification post processor!")
            raise tornado.web.HTTPError(400) PERSIST_LOGGER_PREFFIX = 'persist_'
def setup_loggers():
def setup_configuration(configuration_filename):
def start_processors(): ENGINE = None
SESSION = None
ALEMBIC_CONFIG = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'alembic.ini')
        ENGINE = create_engine(config.sqlalchemy_url, poolclass=pool.NullPool)
        SESSION = sessionmaker(bind=ENGINE)
def init_db():
def create_database():
def upgrade_database():
def get_head_revision():
def get_current_revision():
def execute_query(query):
def execute_query_with_results(query):
def session_scope():
def get_device_tokens(login_id):
def get_raw_messages(login_id, title, content, screen, game, world_id, dry_run, message_id=0, event_ts_bigint=None,
                     expiry_millis=None, priority=GCM2.PRIORITY_NORMAL, filter_platform_id=None, filter_device_token=None):
def update_canonicals(canonicals):
def update_unregistered_devices(unregistered):
def process_user_login(login_id, language_id, platform_id, device_token, application_version):
def upsert_login(login_id, language_id):
def upsert_device(login_id, platform_id, device_token, application_version, unregistered_ts=None):
def get_all_logins():
def get_all_message_blacklist():
def upsert_message_blacklist(login_id, blacklist):
def get_login(login_id):
def get_devices(login):
def delete_login(login):
def delete_device(device):
def get_localized_message(login_id, message_id):
def upsert_message(message_name, cooldown_ts, trigger_event_id, screen, expiry_millis, priority):
def upsert_message_localization(message_name, language_id, message_title, message_text):
def add_message(message_name, language_id, message_title, message_text, trigger_event_id=None, cooldown_ts=None,
                screen='', expiry_millis=None, priority=GCM2.PRIORITY_NORMAL):
def get_all_messages():
def get_message(message_name):
def get_message_localizations(message):
def delete_message(message):
def delete_message_localization(message_localization):
def get_event_to_message_mapping():
def get_and_update_messages_to_send(user_message_set): DATABASE_CONFIG_SECTION = 'Database'
SERVER_SPECIFIC_CONFIG_SECTION = 'ServerSpecific'
EVENT_CONFIG_SECTION = 'Event'
LOG_CONFIG_SECTION = 'Log'
SERVER_CONFIG_SECTION = 'Server'
MESSENGER_CONFIG_SECTION = 'Messenger'
REQUEST_PROCESSOR_CONFIG_SECTION = 'RequestProcessor'
SENDER_CONFIG_SECTION = 'Sender'
REQUEST_HANDLER_SECTION = 'RequestHandler'
def init(configuration_file):
import argparse
import tornado.httpserver
import tornado.ioloop
import tornado.web
import atexit
import sys
import signal
import os
import os.path
import multiprocessing
from pushkin.requesthandlers.events import ProtoEventHandler, JsonEventHandler
from pushkin.requesthandlers.notifications import ProtoNotificationHandler, JsonNotificationHandler
from pushkin.request.request_processor import RequestProcessor
from pushkin.request.event_handlers import EventHandlerManager
from pushkin.requesthandlers.monitoring import RequestQueueHandler
from pushkin.requesthandlers.monitoring import ApnSenderQueueHandler
from pushkin.requesthandlers.monitoring import GcmSenderQueueHandler
from pushkin.requesthandlers.monitoring import NotificationPostProcessorQueue
from pushkin import context
from pushkin.database import database
from pushkin import config
#!/usr/bin/env python2
'''
The MIT License (MIT)
Copyright (c) 2016 Nordeus LLC

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''



CONFIGURATION_FILENAME = None
def init():
    context.request_processor = RequestProcessor()
    database.init_db()
    context.event_handler_manager = EventHandlerManager()

    current_revision = database.get_current_revision()
    head_revision = database.get_head_revision()
    if head_revision != current_revision:
        print("Database is not up to date! "
              "To upgrade database run pushkin --configuration {cfg} --upgrade-db".format(cfg=CONFIGURATION_FILENAME))
        sys.exit(1)

    context.log_queue = multiprocessing.Queue()
    context.message_blacklist = {row.login_id:set(row.blacklist) for row in database.get_all_message_blacklist()}


def create_app():
    application = tornado.web.Application([
        (config.proto_event_handler_url, ProtoEventHandler),
        (config.proto_notification_handler_url, ProtoNotificationHandler),
        (config.json_event_handler_url, JsonEventHandler),
        (config.json_notification_handler_url, JsonNotificationHandler),
        (config.request_queue_handler_url, RequestQueueHandler),
        (config.apn_sender_queue_handler_url, ApnSenderQueueHandler),
        (config.gcm_sender_queue_handler_url, GcmSenderQueueHandler),

        (config.notification_post_processor_queue_handler_url, NotificationPostProcessorQueue),