# Path: sockjs/protocol.py
# STATE_NEW = 0
# 
# STATE_OPEN = 1
# 
# STATE_CLOSING = 2
# 
# STATE_CLOSED = 3
# 
# Path: sockjs/protocol.py
# FRAME_OPEN = "o"
# 
# FRAME_CLOSE = "c"
# 
# Path: sockjs/protocol.py
# FRAME_MESSAGE = "a"
# 
# FRAME_MESSAGE_BLOB = "a1"
# 
# FRAME_HEARTBEAT = "h"
# 
# Path: sockjs/exceptions.py
# class SessionIsAcquired(SockjsException):
#     """Session is acquired."""
# 
# class SessionIsClosed(SockjsException):
#     """Session is closed."""
# 
# Path: sockjs/protocol.py
# MSG_CLOSE = 3
# 
# MSG_MESSAGE = 2
# 
# Path: sockjs/protocol.py
# def close_frame(code, reason):
#     return FRAME_CLOSE + json.dumps([code, reason], **kwargs)
# 
# def message_frame(message):
#     return FRAME_MESSAGE + json.dumps([message], **kwargs)
# 
# def messages_frame(messages):
#     return FRAME_MESSAGE + json.dumps(messages, **kwargs)
# 
# Path: sockjs/protocol.py
# ENCODING = "utf-8"
# STATE_NEW = 0
# STATE_OPEN = 1
# STATE_CLOSING = 2
# STATE_CLOSED = 3
# FRAME_OPEN = "o"
# FRAME_CLOSE = "c"
# FRAME_MESSAGE = "a"
# FRAME_MESSAGE_BLOB = "a1"
# FRAME_HEARTBEAT = "h"
# IFRAME_HTML = """<!DOCTYPE html>
# <html>
# <head>
# <meta http-equiv="X-UA-Compatible" content="IE=edge" />
# <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
#   <script src="%s"></script>
#   <script>
#     document.domain = document.domain;
#     SockJS.bootstrap_iframe();
#   </script>
# </head>
# <body>
#   <h2>Don't panic!</h2>
#   <p>This is a SockJS hidden iframe. It's used for cross domain magic.</p>
# </body>
# </html>
# """.strip()
# IFRAME_MD5 = hashlib.md5(IFRAME_HTML.encode()).hexdigest()
# ENCODING = "utf-8"
# MSG_OPEN = 1
# MSG_MESSAGE = 2
# MSG_CLOSE = 3
# MSG_CLOSED = 4
#     def dthandler(obj):
# def dumps(data):
# def close_frame(code, reason):
# def message_frame(message):
# def messages_frame(messages):
#     def tp(self):
# class SockjsMessage(collections.namedtuple("SockjsMessage", ["type", "data"])):


import warnings
import asyncio
import collections
import logging
from datetime import datetime, timedelta
from asyncio import ensure_future
from .protocol import STATE_NEW, STATE_OPEN, STATE_CLOSING, STATE_CLOSED
from .protocol import FRAME_OPEN, FRAME_CLOSE
from .protocol import FRAME_MESSAGE, FRAME_MESSAGE_BLOB, FRAME_HEARTBEAT
from .exceptions import SessionIsAcquired, SessionIsClosed
from .protocol import MSG_CLOSE, MSG_MESSAGE
from .protocol import close_frame, message_frame, messages_frame
from .protocol import SockjsMessage, OpenMessage, ClosedMessage
    def stop(self):
        if self._hb_handle is not None:
            self._hb_handle.cancel()
            self._hb_handle = None
        if self._hb_task is not None:
            self._hb_task.cancel()
            self._hb_task = None

    def _heartbeat(self):
        if self._hb_task is None:
            self._hb_task = ensure_future(self._heartbeat_task())

    async def _heartbeat_task(self):
        sessions = self.sessions

        if sessions:
            now = datetime.now()

            idx = 0
            while idx < len(sessions):
                session = sessions[idx]

                session._heartbeat()

                if session.expires < now:
                    # Session is to be GC'd immedietely
                    if session.id in self.acquired:
                        await self.release(session)
                    if session.state == STATE_OPEN:
                        await session._remote_close()

# Path: sockjs/protocol.py
# STATE_NEW = 0
# 
# STATE_OPEN = 1
# 
# STATE_CLOSING = 2
# 
# STATE_CLOSED = 3
# 
# Path: sockjs/protocol.py
# FRAME_OPEN = "o"
# 
# FRAME_CLOSE = "c"
# 
# Path: sockjs/protocol.py
# FRAME_MESSAGE = "a"
# 
# FRAME_MESSAGE_BLOB = "a1"
# 
# FRAME_HEARTBEAT = "h"
# 
# Path: sockjs/exceptions.py
# class SessionIsAcquired(SockjsException):
#     """Session is acquired."""
# 
# class SessionIsClosed(SockjsException):
#     """Session is closed."""
# 
# Path: sockjs/protocol.py
# MSG_CLOSE = 3
# 
# MSG_MESSAGE = 2
# 
# Path: sockjs/protocol.py
# def close_frame(code, reason):
#     return FRAME_CLOSE + json.dumps([code, reason], **kwargs)
# 
# def message_frame(message):
#     return FRAME_MESSAGE + json.dumps([message], **kwargs)
# 
# def messages_frame(messages):
#     return FRAME_MESSAGE + json.dumps(messages, **kwargs)
# 
# Path: sockjs/protocol.py
# ENCODING = "utf-8"
# STATE_NEW = 0
# STATE_OPEN = 1
# STATE_CLOSING = 2
# STATE_CLOSED = 3
# FRAME_OPEN = "o"
# FRAME_CLOSE = "c"
# FRAME_MESSAGE = "a"
# FRAME_MESSAGE_BLOB = "a1"
# FRAME_HEARTBEAT = "h"
# IFRAME_HTML = """<!DOCTYPE html>
# <html>
# <head>
# <meta http-equiv="X-UA-Compatible" content="IE=edge" />
# <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
#   <script src="%s"></script>
#   <script>
#     document.domain = document.domain;
#     SockJS.bootstrap_iframe();
#   </script>
# </head>
# <body>
#   <h2>Don't panic!</h2>
#   <p>This is a SockJS hidden iframe. It's used for cross domain magic.</p>
# </body>
# </html>
# """.strip()
# IFRAME_MD5 = hashlib.md5(IFRAME_HTML.encode()).hexdigest()
# ENCODING = "utf-8"
# MSG_OPEN = 1
# MSG_MESSAGE = 2
# MSG_CLOSE = 3
# MSG_CLOSED = 4
#     def dthandler(obj):
# def dumps(data):
# def close_frame(code, reason):
# def message_frame(message):
# def messages_frame(messages):
#     def tp(self):
# class SockjsMessage(collections.namedtuple("SockjsMessage", ["type", "data"])):


# Path: sockjs/session.py
import warnings
import asyncio
import collections
import logging
from datetime import datetime, timedelta
from asyncio import ensure_future
from .protocol import STATE_NEW, STATE_OPEN, STATE_CLOSING, STATE_CLOSED
from .protocol import FRAME_OPEN, FRAME_CLOSE
from .protocol import FRAME_MESSAGE, FRAME_MESSAGE_BLOB, FRAME_HEARTBEAT
from .exceptions import SessionIsAcquired, SessionIsClosed
from .protocol import MSG_CLOSE, MSG_MESSAGE
from .protocol import close_frame, message_frame, messages_frame
from .protocol import SockjsMessage, OpenMessage, ClosedMessage

    def stop(self):
        if self._hb_handle is not None:
            self._hb_handle.cancel()
            self._hb_handle = None
        if self._hb_task is not None:
            self._hb_task.cancel()
            self._hb_task = None

    def _heartbeat(self):
        if self._hb_task is None:
            self._hb_task = ensure_future(self._heartbeat_task())

    async def _heartbeat_task(self):
        sessions = self.sessions

        if sessions:
            now = datetime.now()

            idx = 0
            while idx < len(sessions):
                session = sessions[idx]

                session._heartbeat()

                if session.expires < now:
                    # Session is to be GC'd immedietely
                    if session.id in self.acquired:
                        await self.release(session)
                    if session.state == STATE_OPEN:
                        await session._remote_close()

                    if session.state == STATE_CLOSING: