import local_lib.log_utils as log_utils class URL_Dispatcher: def __init__(self): self.func_registry = {} self.args_registry = {} self.kwargs_registry = {} def register(self, mode, args=None, kwargs=None): """ Decorator function to register a function as a plugin:// url endpoint mode: the mode value passed in the plugin:// url args: a list of strings that are the positional arguments to expect kwargs: a list of strings that are the keyword arguments to expect * Positional argument must be in the order the function expect * kwargs can be in any order * kwargs without positional arguments are supported by passing in a kwargs but no args * If there are no arguments at all, just "mode" can be specified """ if args is None: args = [] if kwargs is None: kwargs = [] def decorator(f): if mode in self.func_registry: message = 'Error: %s already registered as %s' % (str(f), mode) log_utils.log(message, log_utils.LOGERROR) raise Exception(message) # log_utils.log('registering function: |%s|->|%s|' % (mode,str(f)), xbmc.LOGDEBUG) self.func_registry[mode.strip()] = f self.args_registry[mode] = args self.kwargs_registry[mode] = kwargs # log_utils.log('registering args: |%s|-->(%s) and {%s}' % (mode, args, kwargs), xbmc.LOGDEBUG) return f return decorator def dispatch(self, mode, queries): """ Dispatch function to execute function registered for the provided mode mode: the string that the function was associated with queries: a dictionary of the parameters to be passed to the called function """ if mode not in self.func_registry: message = 'Error: Attempt to invoke unregistered mode |%s|' % (mode) log_utils.log(message, log_utils.LOGERROR) raise Exception(message) args = [] kwargs = {} unused_args = queries.copy() if self.args_registry[mode]: # positional arguments are all required for arg in self.args_registry[mode]: arg = arg.strip() if arg in queries: args.append(self.__coerce(queries[arg])) del unused_args[arg] else: message = 'Error: mode |%s| requested argument |%s| but it was not provided.' % (mode, arg) log_utils.log(message, log_utils.LOGERROR) raise Exception(message) if self.kwargs_registry[mode]: # kwargs are optional for arg in self.kwargs_registry[mode]: arg = arg.strip() if arg in queries: kwargs[arg] = self.__coerce(queries[arg]) del unused_args[arg] if 'mode' in unused_args: del unused_args['mode'] # delete mode last in case it's used by the target function log_utils.log('Calling |%s| for mode |%s| with pos args |%s| and kwargs |%s|' % (self.func_registry[mode].__name__, mode, args, kwargs)) if unused_args: log_utils.log('Warning: Arguments |%s| were passed but unused by |%s| for mode |%s|' % (unused_args, self.func_registry[mode].__name__, mode)) self.func_registry[mode](*args, **kwargs) # since all params are passed as strings, do any conversions necessary to get good types (e.g. boolean) def __coerce(self, arg): temp = arg.lower() if temp == 'true': return True elif temp == 'false': return False elif temp == 'none': return None return arg