# Path: fuocore/thread_tcp_server.py
# class TcpServer(object):
#     """A simple TCP server (threading version)
# 
#     There is a better implemented ThreadingTCPServer in stdlib, however,
#     I just want to reinvent the wheel.
# 
#     Happy hacking.
# 
#     >>> import time
#     >>> from threading import Thread
#     >>> def handle(conn, addr, *args): pass
#     >>> server = TcpServer(handle_func=handle, host='0.0.0.0', port=33333)
#     >>> Thread(target=server.run).start()
#     >>> time.sleep(1)
#     >>> server.close()
#     """
#     def __init__(self, host, port, handle_func):
#         self.host = host
#         self.port = port
#         self.handle_func = handle_func
# 
#         self._sock = None
#         self._close_event = Event()
# 
#     def run(self, *args, **kwargs):
#         # TODO: enable TCP_QUICKACK?
#         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#         sock.bind((self.host, self.port))
#         sock.listen()
#         logger.debug('Tcp server running at %s:%d' % (self.host, self.port))
#         self._sock = sock
#         # TODO: choose a better selector?
#         with selectors.DefaultSelector() as sel:
#             # NOTE: use selector timeout and server status flag(threading.Event)
#             # to make tcp server stoppable
#             sel.register(self._sock, selectors.EVENT_READ)
#             while not self._close_event.is_set():
#                 # TODO: better default interval settings?
#                 ready = sel.select(0.5)
#                 if not ready:
#                     continue
#                 try:
#                     conn, addr = sock.accept()
#                 except OSError:  # sock is closed
#                     logger.debug('Tcp server is closed.')
#                     break
#                 except ConnectionError as e:
#                     logger.warning(e)
#                     break
#                 else:
#                     logger.debug('%s:%d connected.' % addr)
#                     Thread(target=self.handle_func, args=(conn, addr, *args),
#                            kwargs=kwargs, name='TcpClientThread').start()
#             logger.debug('Tcp server is stopped.')
# 
#     def close(self):
#         logger.debug('Closing tcp server: %s:%d' % (self.host, self.port))
#         if self._sock is not None:
#             self._sock.close()
#         self._close_event.set()
#         logger.debug('Tcp server closed, it will be stopped in 0.5 seconds.')


from collections import defaultdict
from threading import Thread
from fuocore.thread_tcp_server import TcpServer
import logging
    import time



logger = logging.getLogger(__name__)


class DeadSubscriber(Exception):
    pass


class Subscriber(object):
    def __init__(self, addr, conn):
        self._addr = addr
        self._conn = conn

    def __eq__(self, obj):
        return self._addr == obj._addr

    def __hash__(self):
        return id(self._addr)


def sendto_subscriber(subscriber, msg):
    try:
        subscriber._conn.send(bytes(msg, 'utf-8'))
    except BrokenPipeError:
        subscriber._conn.close()

# Path: fuocore/thread_tcp_server.py
# class TcpServer(object):
#     """A simple TCP server (threading version)
# 
#     There is a better implemented ThreadingTCPServer in stdlib, however,
#     I just want to reinvent the wheel.
# 
#     Happy hacking.
# 
#     >>> import time
#     >>> from threading import Thread
#     >>> def handle(conn, addr, *args): pass
#     >>> server = TcpServer(handle_func=handle, host='0.0.0.0', port=33333)
#     >>> Thread(target=server.run).start()
#     >>> time.sleep(1)
#     >>> server.close()
#     """
#     def __init__(self, host, port, handle_func):
#         self.host = host
#         self.port = port
#         self.handle_func = handle_func
# 
#         self._sock = None
#         self._close_event = Event()
# 
#     def run(self, *args, **kwargs):
#         # TODO: enable TCP_QUICKACK?
#         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#         sock.bind((self.host, self.port))
#         sock.listen()
#         logger.debug('Tcp server running at %s:%d' % (self.host, self.port))
#         self._sock = sock
#         # TODO: choose a better selector?
#         with selectors.DefaultSelector() as sel:
#             # NOTE: use selector timeout and server status flag(threading.Event)
#             # to make tcp server stoppable
#             sel.register(self._sock, selectors.EVENT_READ)
#             while not self._close_event.is_set():
#                 # TODO: better default interval settings?
#                 ready = sel.select(0.5)
#                 if not ready:
#                     continue
#                 try:
#                     conn, addr = sock.accept()
#                 except OSError:  # sock is closed
#                     logger.debug('Tcp server is closed.')
#                     break
#                 except ConnectionError as e:
#                     logger.warning(e)
#                     break
#                 else:
#                     logger.debug('%s:%d connected.' % addr)
#                     Thread(target=self.handle_func, args=(conn, addr, *args),
#                            kwargs=kwargs, name='TcpClientThread').start()
#             logger.debug('Tcp server is stopped.')
# 
#     def close(self):
#         logger.debug('Closing tcp server: %s:%d' % (self.host, self.port))
#         if self._sock is not None:
#             self._sock.close()
#         self._close_event.set()
#         logger.debug('Tcp server closed, it will be stopped in 0.5 seconds.')


# Path: fuocore/pubsub.py
from collections import defaultdict
from threading import Thread
from fuocore.thread_tcp_server import TcpServer
import logging
    import time




logger = logging.getLogger(__name__)


class DeadSubscriber(Exception):
    pass


class Subscriber(object):
    def __init__(self, addr, conn):
        self._addr = addr
        self._conn = conn

    def __eq__(self, obj):
        return self._addr == obj._addr

    def __hash__(self):
        return id(self._addr)


def sendto_subscriber(subscriber, msg):
    try:
        subscriber._conn.send(bytes(msg, 'utf-8'))
    except BrokenPipeError:
        subscriber._conn.close()

        del subscriber