Ejemplo n.º 1
0
 def add_service_listener(self, listener, info_filter=None, initial=False):
     """
     Listens for changes in services that are available. listener is a
     function listener(service_id, host, port, info, event) which will be
     called whenever a service becomes available, a service disappears, or
     the host/port that should be used to access a particular service
     changes. service_id is the id of the service; host/port is the host/port
     at which the service can be found, info is the service's info object,
     and event is one of DISCOVERED, UNDISCOVERED, or CHANGED.
     
     If info_filter is a dictionary, only services with info objects matching
     that particular filter (as per the filter_matches function) will cause
     the listener to be called. If info_filter is None (the default), or the
     empty dictionary (since all info objects match the empty dictionary),
     the listener will be called for all services.
     
     If initial is True, the listener will be immediately (and synchronously)
     called once for each service that already exists, passing in DISCOVERED
     as the event. Otherwise, the listener will only be called once the next
     
     """
     # Add the listener to our list of listeners
     self.service_listeners.append((info_filter, listener))
     # Check to see if we're supposed to notify the listener about all
     # matching services that already exist
     if initial:
         # Scan all of the services
         for service_id, discovered_service in self.discovered_services.items():
             if filter_matches(discovered_service.info, info_filter):
                 # If this service matches, notify the listener about it
                 host, port = discovered_service.locations.keys()[0]
                 with print_exceptions:
                     listener(service_id, host, port, discovered_service.info, DISCOVERED)
Ejemplo n.º 2
0
 def connect_to(self, info_filter, timeout=10, open_listener=None, close_listener=None, fail_listener=None, lock=None):
     """
     Locates the first service in the list of discovered services and uses
     self.connect to connect to it. The connection is then returned.
     
     This function will be going away soon. Service proxies (which can be
     obtained using self.get_service_proxy) are the replacement; a single
     service proxy is quite similar to this method, but it can follow the
     service across restarts of the underlying process publishing the
     service, which this method can't.
     """
     with self.lock:
         for service_id, d in self.discovered_services.items():
             if filter_matches(d.info, info_filter):
                 host, port = d.locations.keys()[0]
                 return self.connect(host, port, service_id, timeout, open_listener, close_listener, fail_listener, lock)
         raise exceptions.NoMatchingServiceException()
Ejemplo n.º 3
0
 def remove_service_listener(self, listener, initial=False):
     # Scan the list of listeners and remove this one. Inefficient, it's
     # true, and I hope to make it more efficient later on.
     for index, (info_filter, l) in enumerate(self.service_listeners[:]):
         # See if we've hit the right listener
         if l == listener:
             # If we have, remove the listener
             del self.service_listeners[index]
             if initial:
                 # Scan through the list of services
                 for service_id, discovered_service in self.discovered_services.items():
                     if filter_matches(discovered_service.info, info_filter):
                         # This service matched, so we notify this
                         # listener that the service was removed
                         with print_exceptions:
                             listener(service_id, None, None, None, UNDISCOVERED)
             # We've found our listener and deleted it, so we return now
             return
Ejemplo n.º 4
0
 def notify_service_listeners(self, service_id, host, port, info, event):
     for filter, listener in self.service_listeners:
         if filter_matches(info, filter):
             with print_exceptions:
                 listener(service_id, host, port, info, event)
Ejemplo n.º 5
0
def main():
    args = parser.parse_args()
    if args.mode is None and args.type is None:
        print "Use autosend2 --help for more information."
        return
    if args.mode == "help":
        print parser.format_help().replace("!!!INFO!!!", description.strip())
        return

    mode = args.mode
    if mode is None:
        # Type, at least, will be present, since the "Use autosend2 --help ..."
        # message will have stopped us if it wasn't. So basically we need to
        # check to see if name is present, and if it is, then we call the
        # specified function, and if it isn't, then we search for the
        # introspection service and print a list of all supported functions.
        if args.name is not None:
            mode = "call"
        else:
            mode = "list"

    # Parse out the info filer from the arguments
    info_filter = parse_info_filter(args)

    # Now create a bus.
    with Bus() as bus:
        if mode == "discovery":
            # Print the discovery table header
            print discovery_mode_header
            # Add a listener listening for services that will print out
            # information to stdout
            bus.add_service_listener(partial(discovery_mode_listener, args), info_filter=info_filter, initial=True)
            # Wait until we're interrupted
            wait_for_interrupt()
            # This empty print is to add a new line after the one with ^C on it
            # so that things look a bit prettier when all of the REMOVED
            # messages are printed.
            print
            return
        if mode == "call":
            if not args.name:
                print "You need to specify the name of the function to call."
                return
            if args.multiple:  # Open a multiple-service proxy, with a
                # bind_function that will call the requested function whenever
                # it binds to a service. The advantage of doing this instead of
                # creating the service proxy, waiting a few seconds, then
                # calling the function on it is that the function is called
                # nearly immediately instead of after a delay.
                with bus.get_service_proxy(
                    info_filter, bind_function=partial(call_mode_onbind, args), multiple=True
                ) as proxy:
                    # Wait a few seconds before stopping the service proxy
                    time.sleep(args.time)
            else:  # Open a single-service proxy, wait for it to bind to
                # something, then call the function and pass the result to
                # call_mode_print_result, which prints it out.
                with bus.get_service_proxy(info_filter) as proxy:
                    proxy.wait_for_bind(timeout=args.time)
                    try:
                        call_mode_print_result(proxy[args.name](*parse_value_list(args.values)))
                    except Exception as e:
                        call_mode_print_result(e)
            return
        if mode == "list":
            # Open a service proxy on the available introspection services.
            # Note that we use a multiple service proxy here regardless of
            # what the user requested as we've no guarantee that the first
            # introspection service discovered will provide a service matching
            # the requested criteria. TODO: Perhaps consider watching the proxy
            # in the future if a single-service lookup has been requested to
            # immediately return once a suitable service is found.
            with bus.get_service_proxy({"type": "autobus.details"}, multiple=True) as proxy:
                # Wait a few seconds for the proxy to bind
                time.sleep(args.time)
                # Call the introspection function to get information about the
                # services
                int_results = proxy["get_details"]()
                # int_results will be a dict whose keys are the service ids of
                # the introspection services and whose values are dicts whose
                # keys are the actual service ids. We need to translate this
                # into results, which is simply a dict whose keys are service
                # ids and whose values are services. We also need to strip out
                # entries whose info objects don't match what we're looking for.
                results = {}
                # Iterate over the introspection services
                for _, services_dict in int_results.items():
                    # Iterate over the services this introspector knows about
                    for service_id, service in services_dict.items():
                        # See if the service matches our filter, and see if
                        # we've either specified --all or this service isn't
                        # an introspection service
                        if filter_matches(service["info"], info_filter) and (
                            args.all or not service["info"].get("type", "").startswith("autobus.")
                        ):
                            # It matches, so add it to the results
                            results[service_id] = service
                # We've got the actual results. Now print a message if there
                # weren't any.
                if len(results) == 0:
                    print "No matching services available."
                # If there were results, print them.
                for i, (service_id, service) in enumerate(results.items()):
                    if i > 0:
                        print "#" * 70

                    print "Service %s on %s (%s) -- %r:" % (
                        service["info"].get("type", "<unknown>"),
                        service["info"].get("hostname", "<unknown>"),
                        service_id,
                        service["info"],
                    )
                    if service.get("doc", None):
                        print "\n" + service["doc"]
                    print "=" * 70
                    functions = filter_hidden(args, service["functions"])
                    if len(functions) == 0:
                        print "No functions available on this service."
                    for j, (name, function) in enumerate(functions.items()):
                        if j > 0:
                            print "-" * 70
                        print "Function " + name + ":"
                        if function.get("doc", None):
                            print "\n" + function["doc"]
                    print "=" * 70
                    events = filter_hidden(args, service["events"])
                    if len(events) == 0:
                        print "No events available on this service."
                    for j, (name, event) in enumerate(events.items()):
                        if j > 0:
                            print "-" * 70
                        print "Event " + name + ":"
                        if event.get("doc"):
                            print "\n" + event["doc"]
                    print "=" * 70
                    objects = filter_hidden(args, service["objects"])
                    if len(objects) == 0:
                        print "No objects available on this service."
                    for j, (name, object) in enumerate(objects.items()):
                        if j > 0:
                            print "-" * 70
                        print "Object " + name + ":"
                        if object.get("doc"):
                            print "\n" + object["doc"]
                return
        print "Unsupported mode used: " + str(mode)