def __init__(self):
        self.usb_bus = UsbBus.Instance()

        self.request_buffer = RequestBuffer()
    def __init__(self):
        self.router = None
        self.poller = None
        self.transmitter_applications = dict()

        self.request_buffer = RequestBuffer()
class UsbPortController:
    def __init__(self):
        self.usb_bus = UsbBus.Instance()

        self.request_buffer = RequestBuffer()

    def handle_event(self, action, device):
        """
        action: the action that caused this event (eg add, remove)
        device: the usb device that prompted the event
        """
        operation = Operation(action)

        if not device.attributes:
            usb_device = self.usb_bus.find_with(path=device.device_path)
            new_op = UsbOperation(operation=operation, usb_device=usb_device)
            message = DocumentMessage(document=new_op.to_json())

            request = Request(
                id=message.id, dispatcher=self.usb_monitor_pair.send_string, args=message.serialize(), hop_limit=10
            )
            self.request_buffer.append(request)
            self.usb_bus.remove(usb_device)
        else:
            usb_device = UsbDevice(device)
            self.usb_bus.add(usb_device)
            new_op = UsbOperation(operation=operation, usb_device=usb_device)
            message = DocumentMessage(document=new_op.to_json())

            request = Request(
                id=message.id, dispatcher=self.usb_monitor_pair.send_string, args=message.serialize(), hop_limit=10
            )
            self.request_buffer.append(message)

    def run(self):
        logger.info("USB Port Controller starting")

        context = pyudev.Context()

        monitor = pyudev.Monitor.from_netlink(context)
        monitor.filter_by(subsystem="usb", device_type="usb_device")

        observer = pyudev.MonitorObserver(monitor, self.handle_event)
        observer.start()

        kbsubscriber = NetworkingManager.KillBroadcastSubscriber()
        usb_monitor_pair = NetworkingManager.UsbMonitorPairServer()

        poller = NetworkingManager.Poller()
        poller.register(kbsubscriber, NetworkingManager.POLLIN)
        poller.register(usb_monitor_pair, NetworkingManager.POLLIN)

        for device in self.usb_bus.devices:
            new_op = UsbOperation(usb_device=device, operation=Operation("add"))
            message = DocumentMessage(document=new_op.to_json())
            request = Request(
                id=message.id, dispatcher=usb_monitor_pair.send_string, args=message.serialize(), hop_limit=10
            )
            self.request_buffer.append(request)

        while True:
            self.request_buffer.dispatch_all()
            socks = dict(poller.poll(50))

            if usb_monitor_pair.contained_in(socks):
                reply = CommandMessage.deserialize(usb_monitor_pair.recv_string())
                self.request_buffer.process_reply(reply)

            if kbsubscriber.contained_in(socks):
                message = CommandMessage.deserialize(kbsubscriber.recv_string())
                reply_structure = None
                try:
                    command = Command(message.command)
                    command_processor = CommandProcessor(self)
                    reply_structure = command_processor.process(command)
                except ExitProcess:
                    observer.stop()
                    usb_monitor_pair.unbind()
                    logger.info("USB Port Controller stopping")
                    break
                finally:
                    # send message if applicable
                    if reply_structure:
                        pass
class TransmitterApplicationController:
    def __init__(self):
        self.router = None
        self.poller = None
        self.transmitter_applications = dict()

        self.request_buffer = RequestBuffer()

    def process_usb_operation(self, usb_operation):
        transmitter = TransmitterIndex.find_matching(usb_operation.usb_device)
        if transmitter:
            if usb_operation.operation is Operation.ADD:
                self.start_transmitter_application(transmitter)
            elif usb_operation.operation is Operation.REMOVE:
                self.stop_transmitter_application(transmitter)

    def start_transmitter_application(self, transmitter):
        for child_id, app in self.transmitter_applications.items():
            if app.transmitter == transmitter:
                logger.error(
                    "Process using "+repr(transmitter)+" already running"
                )
                return

        child_id = NEXT_CHILD_ID()

        controller = TransmitterController(transmitter, child_id)
        process = Process(target=controller.run)

        process.daemon = True
        process.start()

        app = _TransmitterApplication(controller, process)
        self.transmitter_applications[child_id] = app

    def stop_transmitter_application(self, transmitter):
        for child_id, app in self.transmitter_applications.items():
            if app.transmitter == transmitter:
                message = CommandMessage(command=Command.SHUTDOWN)
                request = Request(
                    id=message.id,
                    dispatcher=self.router.send_string,
                    args=[child_id, message.serialize],
                    hop_limit=-1,
                    splat_args=True
                )
                self.request_buffer.append(request)

    def stop_all_transmitter_applications(self):
        for child_id, app in self.transmitter_applications:
            message = CommandMessage(command=Command.SHUTDOWN)
            request = Request(
                id=message.id,
                dispatcher=self.router.send_string,
                args=[child_id, message.serialize],
                hop_limit=-1,
                splat_args=True
            )
            self.request_buffer.append(request)
            app.last_request = message

    def run(self):
        logger.info("Transmitter Application Controller starting")

        # Kill broadcast subscriber
        kbsubscriber = NetworkingManager.KillBroadcastSubscriber()
        usb_monitor_pair = NetworkingManager.UsbMonitorPairClient()
        self.router = NetworkingManager.TACParent()

        self.poller = NetworkingManager.Poller()
        self.poller.register(kbsubscriber, NetworkingManager.POLLIN)
        self.poller.register(usb_monitor_pair, NetworkingManager.POLLIN)
        self.poller.register(self.router, NetworkingManager.POLLIN)

        while True:
            self.request_buffer.dispatch_all()
            socks = dict(self.poller.poll(50))

            if self.router.contained_in(socks):
                child_id, string = self.router.recv_string()
                # do some stuff with reply
                app = self.transmitter_applications[child_id]
                if app.last_request == Command.SHUTDOWN:
                    reply = CommandMessage.deserialize(string)
                    self.request_buffer.process_reply(reply)

                    if app.process.is_alive():
                        app.process.terminate()
                    del self.transmitter_applications[child_id]

            if usb_monitor_pair.contained_in(socks):
                # a message from the usb port controller indicates
                # a usb device has been added or removed from the system
                request = DocumentMessage.deserialize(
                    usb_monitor_pair.recv_string()
                )
                logger.info("Request received: " + request.serialize())
                usb_operation = UsbOperation.from_json(request.contents)
                self.process_usb_operation(usb_operation)
                # send a void reply to confirm receipt
                reply = CommandMessage.VoidReply(request)
                usb_monitor_pair.send_string(reply.serialize())

            if kbsubscriber.contained_in(socks):
                message = CommandMessage.deserialize(
                    kbsubscriber.recv_string()
                )
                reply_structure = None
                try:
                    command = Command(message.command)
                    command_processor = CommandProcessor(self)
                    reply_structure = command_processor.process(command)
                except ExitProcess:
                    self.request_buffer.clear()
                    self.stop_all_transmitter_applications()
                    self.request_buffer.dispatch_all()
                    logger.info("Transmitter Application Controller stopping")
                    break
                finally:
                    if reply_structure:
                        pass