Пример #1
0
def forward_device_msg(identity, msg):
    """Forwards a message from plugin->client or client->plugin, editing it to take
    out all identifying information. This way, all identity management stays in
    the router, and plugins/clients talk to each other with no actual knowledge
    of who claims/says what.

    """
    to_alias = msg[0]
    print _ctd
    print _dtc
    to_addr = None
    new_msg = None
    # TODO: Remove [0], make deal with multiclaims. Someday.

    # Plugins aren't allowed to know who owns them, they just see commands from
    # the system. Therefore they set their "to" address as "c", and we replace
    # it with the correct client identity.
    if to_alias == "c":
        new_msg = [identity] + list(msg[1:])
        to_addr = _dtc[identity][0]

    # Client only know their device's provided address (bus address, bluetooth
    # id, etc...). We resolve that to the plugin's socket identity.
    elif to_alias in _dtc.keys():
        # Plugins don't get to know where things come from. Spooooky.
        new_msg = ["s"] + list(msg[1:])
        to_addr = _ctd[identity][0]
    else:
        logging.warning("No claims between %s and %s!", identity, to_addr)
        return

    logging.debug("Forwarding message %s to %s", new_msg, to_addr)
    queue.add(to_addr, new_msg)
Пример #2
0
def _heartbeat(identity, g):
    """Given an identity and its corresponding g, start a heartbeat loop.
    Maintain loop until either g dies or connection does not return a
    BPPing message in a timely manner. If message is not returned, kill
    corresponding g.

    """
    while not g.ready():
        e = event.add(identity, "BPPing")
        queue.add(identity, ["s", "BPPing"])
        try:
            e.get(block=True, timeout=config.get_value("ping_max"))
        except gevent.Timeout:
            logging.info("Identity %s died via heartbeat", identity)
            g.kill()
            return
        except greenlet.BPGreenletExit:
            logging.debug("Heartbeat for %s exiting...", identity)
            return

        if g.ready():
            logging.debug("Heartbeat for %s exiting...", identity)
            return

        try:
            gevent.sleep(config.get_value("ping_rate"))
        except greenlet.BPGreenletExit:
            logging.debug("Heartbeat for %s exiting...", identity)
            return
Пример #3
0
def forward_device_msg(identity, msg):
    """Forwards a message from plugin->client or client->plugin, editing it to take
    out all identifying information. This way, all identity management stays in
    the router, and plugins/clients talk to each other with no actual knowledge
    of who claims/says what.

    """
    to_alias = msg[0]
    print _ctd
    print _dtc
    to_addr = None
    new_msg = None
    # TODO: Remove [0], make deal with multiclaims. Someday.

    # Plugins aren't allowed to know who owns them, they just see commands from
    # the system. Therefore they set their "to" address as "c", and we replace
    # it with the correct client identity.
    if to_alias == "c":
        new_msg = [identity] + list(msg[1:])
        to_addr = _dtc[identity][0]

    # Client only know their device's provided address (bus address, bluetooth
    # id, etc...). We resolve that to the plugin's socket identity.
    elif to_alias in _dtc.keys():
        # Plugins don't get to know where things come from. Spooooky.
        new_msg = ["s"] + list(msg[1:])
        to_addr = _ctd[identity][0]
    else:
        logging.warning("No claims between %s and %s!", identity, to_addr)
        return

    logging.debug("Forwarding message %s to %s", new_msg, to_addr)
    queue.add(to_addr, new_msg)
Пример #4
0
def _handle_internals(identity, msg):
    """Handle a request for internal information (greenlets, connections, etc.). To
    be used by dashboard.

    """
    queue.add(identity, ["s", "BPInternals", greenlet._live_greenlets])
    return True
Пример #5
0
def _handle_internals(identity, msg):
    """Handle a request for internal information (greenlets, connections, etc.). To
    be used by dashboard.

    """
    queue.add(identity, ["s", "BPInternals", greenlet._live_greenlets])
    return True
Пример #6
0
def _run_count_plugin(plugin):
    """Runs the count process for a plugin. Constantly polls for list of devices,
    keeping an internal reference of the devices available from the plugin.

    """
    count_identity = greenlet.random_ident()
    e = event.add(count_identity, "BPPluginRegisterCount")
    count_process_cmd = [plugin.executable_path, "--server_port=%s" %
                         config.get_value("server_address"), "--count"]
    count_process = _start_process(count_process_cmd, count_identity)
    if not count_process:
        logging.warning("%s count process unable to start. removing.",
                        plugin.name)
        return

    try:
        e.get(block=True, timeout=1)
    except gevent.Timeout:
        logging.info("%s count process never registered, removing.",
                     plugin.name)
        return
    except greenlet.BPGreenletExit:
        logging.debug("Shutting down count process for %s", plugin.name)
        return
    logging.info("Count process for %s up on identity %s", plugin.name,
                 count_identity)
    greenlet.add_identity_greenlet(count_identity, gevent.getcurrent())
    hb = heartbeat.spawn_heartbeat(count_identity, gevent.getcurrent())
    _plugins[plugin.name] = plugin
    while True:
        queue.add(count_identity, ["s", "BPPluginDeviceList"])
        e = event.add(count_identity, "BPPluginDeviceList")
        try:
            (i, msg) = e.get(block=True, timeout=1)
        except gevent.Timeout:
            logging.info("%s count process timed out, removing.", plugin.name)
            break
        except greenlet.BPGreenletExit:
            logging.debug("Shutting down count process for %s", plugin.name)
            break
        _devices[plugin.name] = msg[2]
        # TODO: Make this a configuration value
        try:
            gevent.sleep(1)
        except greenlet.BPGreenletExit:
            logging.debug("Shutting down count process for %s", plugin.name)
            break

    # Heartbeat may already be dead if we're shutting down, so check first
    if not hb.ready():
        hb.kill(exception=greenlet.BPGreenletExit, block=True, timeout=1)
    # Remove ourselves, but don't kill since we're already shutting down
    greenlet.remove_identity_greenlet(count_identity, kill_greenlet=False)
    # TODO: If a count process goes down, does every associated device go with
    # it?
    del _plugins[plugin.name]
    queue.add(count_identity, ["s", "BPClose"])
    logging.debug("Count process %s for %s exiting...", count_identity,
                  plugin.name)
Пример #7
0
def _handle_plugin_list(identity, msg):
    """Handle a request for the list of plugins available to the router.

    """
    queue.add(
        identity, ["s", "BPPluginList", [{"name": p.name, "version": p.version} for p in plugin.plugins_available()]]
    )
    return True
Пример #8
0
def _handle_device_list(identity, msg):
    """Handle a request for the list of devices available to router plugins.

    """
    devices = []
    for (k, v) in plugin._devices.items():
        devices.append({"name": k, "devices": v})
    queue.add(identity, ["s", "BPDeviceList", devices])
    return True
Пример #9
0
def _handle_plugin_list(identity, msg):
    """Handle a request for the list of plugins available to the router.

    """
    queue.add(identity, ["s", "BPPluginList",
                         [{"name": p.name,
                           "version": p.version}
                          for p in plugin.plugins_available()]])
    return True
Пример #10
0
def _handle_device_list(identity, msg):
    """Handle a request for the list of devices available to router plugins.

    """
    devices = []
    for (k, v) in plugin._devices.items():
        devices.append({"name": k, "devices": v})
    queue.add(identity, ["s", "BPDeviceList", devices])
    return True
Пример #11
0
def _handle_server_info(identity, msg):
    """Server Info

    - Server Name (Changable by user)

    - Server Software Version (static)

    - Server Build Date (static)

    """
    queue.add(
        identity,
        ["s", "BPServerInfo", [{"name": "B******g", "version": bpinfo.SERVER_VERSION, "date": bpinfo.SERVER_DATE}]],
    )
    return True
Пример #12
0
def _handle_server_info(identity, msg):
    """Server Info

    - Server Name (Changable by user)

    - Server Software Version (static)

    - Server Build Date (static)

    """
    queue.add(identity, ["s", "BPServerInfo",
                         [{"name": "B******g",
                           "version": bpinfo.SERVER_VERSION,
                           "date": bpinfo.SERVER_DATE}]])
    return True
Пример #13
0
def handle_client(identity, msg):
    """Start a greenlet that will survive the duration of client connection.
    Handles replying to client registration, and cleaning up claims on
    disconnect."""
    hb = heartbeat.spawn_heartbeat(identity, gevent.getcurrent())
    greenlet.add_identity_greenlet(identity, gevent.getcurrent())
    # Let the client know we're aware of it
    queue.add(identity, ["s", "BPRegisterClient", True])
    while True:
        try:
            gevent.sleep(1)
        except greenlet.BPGreenletExit:
            break
    plugin.kill_claims(identity)
    if not hb.ready():
        hb.kill(exception=greenlet.BPGreenletExit, block=True, timeout=1)
    # Remove ourselves, but don't kill since we're already shutting down
    greenlet.remove_identity_greenlet(identity, kill_greenlet=False)
    queue.add(identity, ["s", "BPClose"])
    logging.debug("Client keeper %s exiting...", identity)
Пример #14
0
def handle_client(identity, msg):
    """Start a greenlet that will survive the duration of client connection.
    Handles replying to client registration, and cleaning up claims on
    disconnect."""
    hb = heartbeat.spawn_heartbeat(identity, gevent.getcurrent())
    greenlet.add_identity_greenlet(identity, gevent.getcurrent())
    # Let the client know we're aware of it
    queue.add(identity, ["s", "BPRegisterClient", True])
    while True:
        try:
            gevent.sleep(1)
        except greenlet.BPGreenletExit:
            break
    plugin.kill_claims(identity)
    if not hb.ready():
        hb.kill(exception=greenlet.BPGreenletExit, block=True, timeout=1)
    # Remove ourselves, but don't kill since we're already shutting down
    greenlet.remove_identity_greenlet(identity, kill_greenlet=False)
    queue.add(identity, ["s", "BPClose"])
    logging.debug("Client keeper %s exiting...", identity)
Пример #15
0
def run_device_plugin(identity, msg):
    """Execute the plugin claim protocol. This happens whenever a client requests
    to claim a resource advertised by a plugin.

    """
    # Figure out the plugin that owns the device we want
    p = None
    dev_id = msg[2]
    for (plugin_name, device_list) in _devices.items():
        if dev_id in device_list:
            p = _plugins[plugin_name]

    if p is None:
        logging.warning("Cannot find device %s, failing claim", dev_id)
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    # See whether we already have a claim on the device
    if dev_id in _dtc.keys():
        logging.warning("Device %s already claimed, failing claim", dev_id)
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    # Client to system: bring up device process.
    #
    # Just name the new plugin process socket identity after the device id,
    # because why not.
    device_process = _start_process([p.executable_path, "--server_port=%s" %
                                     config.get_value("server_address")],
                                    dev_id)
    if not device_process:
        logging.warning("%s device process unable to start. removing.",
                        p.name)
        return

    # Device process to system: Register with known identity
    e = event.add(dev_id, "BPPluginRegisterClaim")
    try:
        # TODO: Make device open timeout a config option
        (i, m) = e.get(timeout=5)
    except greenlet.BPGreenletExit:
        # If we shut down now, just drop
        return
    except gevent.Timeout:
        # If we timeout, fail the claim
        logging.info("Device %s failed to start...", dev_id)
        queue.add(dev_id, ["s", "BPClose"])
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    greenlet.add_identity_greenlet(dev_id, gevent.getcurrent())

    # Add a heartbeat now that the process is up
    hb = heartbeat.spawn_heartbeat(dev_id, gevent.getcurrent())

    # System to device process: Open device
    queue.add(dev_id, ["s", "BPPluginOpenDevice", dev_id])
    e = event.add(dev_id, "BPPluginOpenDevice")
    try:
        (i, m) = e.get()
    except greenlet.BPGreenletExit:
        queue.add(dev_id, ["s", "BPClose"])
        return

    # Device process to system: Open or fail
    if m[3] is False:
        logging.info("Device %s failed to open...", dev_id)
        queue.add(dev_id, ["s", "BPClose"])
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    # System to client: confirm device claim
    queue.add(identity, ["s", "BPClaimDevice", dev_id, True])

    if identity not in _ctd.keys():
        _ctd[identity] = []
    _ctd[identity].append(dev_id)
    if dev_id not in _dtc.keys():
        _dtc[dev_id] = []
    _dtc[dev_id].append(identity)

    while True:
        try:
            gevent.sleep(1)
        except greenlet.BPGreenletExit:
            break

    if not hb.ready():
        hb.kill(exception=greenlet.BPGreenletExit, block=True, timeout=1)

    _ctd[identity].remove(dev_id)
    del _dtc[dev_id]

    # Remove ourselves, but don't kill since we're already shutting down
    greenlet.remove_identity_greenlet(dev_id, kill_greenlet=False)
    queue.add(dev_id, ["s", "BPClose"])
    logging.debug("Device keeper %s exiting...", dev_id)
Пример #16
0
def _run_count_plugin(plugin):
    """Runs the count process for a plugin. Constantly polls for list of devices,
    keeping an internal reference of the devices available from the plugin.

    """
    count_identity = greenlet.random_ident()
    e = event.add(count_identity, "BPPluginRegisterCount")
    count_process_cmd = [
        plugin.executable_path,
        "--server_port=%s" % config.get_value("server_address"), "--count"
    ]
    count_process = _start_process(count_process_cmd, count_identity)
    if not count_process:
        logging.warning("%s count process unable to start. removing.",
                        plugin.name)
        return

    try:
        e.get(block=True, timeout=1)
    except gevent.Timeout:
        logging.info("%s count process never registered, removing.",
                     plugin.name)
        return
    except greenlet.BPGreenletExit:
        logging.debug("Shutting down count process for %s", plugin.name)
        return
    logging.info("Count process for %s up on identity %s", plugin.name,
                 count_identity)
    greenlet.add_identity_greenlet(count_identity, gevent.getcurrent())
    hb = heartbeat.spawn_heartbeat(count_identity, gevent.getcurrent())
    _plugins[plugin.name] = plugin
    while True:
        queue.add(count_identity, ["s", "BPPluginDeviceList"])
        e = event.add(count_identity, "BPPluginDeviceList")
        try:
            (i, msg) = e.get(block=True, timeout=1)
        except gevent.Timeout:
            logging.info("%s count process timed out, removing.", plugin.name)
            break
        except greenlet.BPGreenletExit:
            logging.debug("Shutting down count process for %s", plugin.name)
            break
        _devices[plugin.name] = msg[2]
        # TODO: Make this a configuration value
        try:
            gevent.sleep(1)
        except greenlet.BPGreenletExit:
            logging.debug("Shutting down count process for %s", plugin.name)
            break

    # Heartbeat may already be dead if we're shutting down, so check first
    if not hb.ready():
        hb.kill(exception=greenlet.BPGreenletExit, block=True, timeout=1)
    # Remove ourselves, but don't kill since we're already shutting down
    greenlet.remove_identity_greenlet(count_identity, kill_greenlet=False)
    # TODO: If a count process goes down, does every associated device go with
    # it?
    del _plugins[plugin.name]
    queue.add(count_identity, ["s", "BPClose"])
    logging.debug("Count process %s for %s exiting...", count_identity,
                  plugin.name)
Пример #17
0
def run_device_plugin(identity, msg):
    """Execute the plugin claim protocol. This happens whenever a client requests
    to claim a resource advertised by a plugin.

    """
    # Figure out the plugin that owns the device we want
    p = None
    dev_id = msg[2]
    for (plugin_name, device_list) in _devices.items():
        if dev_id in device_list:
            p = _plugins[plugin_name]

    if p is None:
        logging.warning("Cannot find device %s, failing claim", dev_id)
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    # See whether we already have a claim on the device
    if dev_id in _dtc.keys():
        logging.warning("Device %s already claimed, failing claim", dev_id)
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    # Client to system: bring up device process.
    #
    # Just name the new plugin process socket identity after the device id,
    # because why not.
    device_process = _start_process([
        p.executable_path,
        "--server_port=%s" % config.get_value("server_address")
    ], dev_id)
    if not device_process:
        logging.warning("%s device process unable to start. removing.", p.name)
        return

    # Device process to system: Register with known identity
    e = event.add(dev_id, "BPPluginRegisterClaim")
    try:
        # TODO: Make device open timeout a config option
        (i, m) = e.get(timeout=5)
    except greenlet.BPGreenletExit:
        # If we shut down now, just drop
        return
    except gevent.Timeout:
        # If we timeout, fail the claim
        logging.info("Device %s failed to start...", dev_id)
        queue.add(dev_id, ["s", "BPClose"])
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    greenlet.add_identity_greenlet(dev_id, gevent.getcurrent())

    # Add a heartbeat now that the process is up
    hb = heartbeat.spawn_heartbeat(dev_id, gevent.getcurrent())

    # System to device process: Open device
    queue.add(dev_id, ["s", "BPPluginOpenDevice", dev_id])
    e = event.add(dev_id, "BPPluginOpenDevice")
    try:
        (i, m) = e.get()
    except greenlet.BPGreenletExit:
        queue.add(dev_id, ["s", "BPClose"])
        return

    # Device process to system: Open or fail
    if m[3] is False:
        logging.info("Device %s failed to open...", dev_id)
        queue.add(dev_id, ["s", "BPClose"])
        queue.add(identity, ["s", "BPClaimDevice", dev_id, False])
        return

    # System to client: confirm device claim
    queue.add(identity, ["s", "BPClaimDevice", dev_id, True])

    if identity not in _ctd.keys():
        _ctd[identity] = []
    _ctd[identity].append(dev_id)
    if dev_id not in _dtc.keys():
        _dtc[dev_id] = []
    _dtc[dev_id].append(identity)

    while True:
        try:
            gevent.sleep(1)
        except greenlet.BPGreenletExit:
            break

    if not hb.ready():
        hb.kill(exception=greenlet.BPGreenletExit, block=True, timeout=1)

    _ctd[identity].remove(dev_id)
    del _dtc[dev_id]

    # Remove ourselves, but don't kill since we're already shutting down
    greenlet.remove_identity_greenlet(dev_id, kill_greenlet=False)
    queue.add(dev_id, ["s", "BPClose"])
    logging.debug("Device keeper %s exiting...", dev_id)