from logging import getLogger

from flask import Blueprint, request
from simple_websocket import ConnectionClosed, Server

from platypush.backend.http.app import template_folder
from platypush.backend.http.app.utils import authenticate
from platypush.backend.http.ws import events_redis_topic
from platypush.message.event import Event
from platypush.utils import get_redis


ws = Blueprint('ws', __name__, template_folder=template_folder)

__routes__ = [ws]

logger = getLogger(__name__)


@ws.route('/ws/events', websocket=True)
@authenticate(json=True)
def ws_events_route():
    """
    A websocket endpoint to asynchronously receive events generated from the
    application.

    This endpoint is mainly used by web clients to listen for the events
    generated by the application.
    """

    sock = Server(request.environ, ping_interval=25)
    ws_key = (sock.environ['REMOTE_ADDR'], int(sock.environ['REMOTE_PORT']))
    sub = get_redis().pubsub()
    sub.subscribe(events_redis_topic)
    logger.info('Started websocket connection with %s', ws_key)

    try:
        for msg in sub.listen():
            if (
                msg.get('type') != 'message'
                and msg.get('channel').decode() != events_redis_topic
            ):
                continue

            try:
                evt = Event.build(msg.get('data').decode())
            except Exception as e:
                logger.warning('Error parsing event: %s: %s', msg.get('data'), e)
                continue

            sock.send(str(evt))
    except ConnectionClosed as e:
        logger.info(
            'Websocket connection to %s closed, reason=%s, message=%s',
            ws_key,
            e.reason,
            e.message,
        )
    finally:
        sub.unsubscribe(events_redis_topic)

    return ''


# vim:sw=4:ts=4:et: