예제 #1
0
 def message_handler(self, message: Union[FriendMessage, GroupMessage]):
   "一句话只能触发一个指令."
   after_prefix = None
   for prefix_pattern in self.command_prefix:
     after_prefix = \
       oit.chain_regex_match_headpop(
         copy.copy(message.messageChain),
         prefix_pattern
       )
     if after_prefix:
       break
   else:
     return
   
   # 如果到了这里, 就说明这句话试图触发一个指令
   matched_command_entity = None
   matched_command_params = None
   special_handle_for_raw_string = None
   matched_result = None
   for command in self.commands:
     matched_command_entity = command
     for command_match in [command.match, *command.aliases]:
       matched_info = oit.chain_match(command_match, 
         MessageChain(__root__=after_prefix.__root__[1:])
       )
       if matched_info: # 匹配到了.
         matched_result, special_handle_for_raw_string = matched_info
         break
     else: # 没匹配到
       return
     
   # 处理 matched_command_params
   optional_params = {
     param.name: param.default \
       for param in \
         argument_signature(matched_command_entity.execator)
   }
   return {
     "command": matched_command_entity,
     "parameters": {
       **({
         # 因为蜜汁原因, 导致我们还得判断一步...但这应该在外部执行(要获取 execator 的 default...)
         # 多出来的这一步是因为 python-mirai 内部逻辑的缺点...我们必须克服它.
         k: special_handle_for_raw_string(v) if isinstance(v, str) else 
           (v if v != None else optional_params.get(k))
         for k, v in matched_result.items()
       })
     }
   }
예제 #2
0
 def checkFuncAnnotations(self, callable_target: Callable):
     restraint_mapping = self.getRestraintMapping()
     registered_events = self.getFuncRegisteredEvents(callable_target)
     for name, annotation, default in argument_signature(callable_target):
         if not default:
             if not registered_events:
                 raise ValueError(f"error in annotations checker: {callable_target} is invaild.")
             for event_name in registered_events:
                 try:
                     if not restraint_mapping[annotation](type(event_name, (object,), {})()):
                         raise ValueError(
                             f"error in annotations checker: {callable_target}.[{name}:{annotation}]: {event_name}")
                 except KeyError:
                     raise ValueError(
                         f"error in annotations checker: {callable_target}.[{name}:{annotation}] is invaild.")
                 except ValueError:
                     raise
예제 #3
0
 def checkDependencies(self, depend_target: Depend):
     self.checkEventBodyAnnotations()
     for name, annotation, default in argument_signature(depend_target.func):
         if type(default) == Depend:
             self.checkDependencies(default)
예제 #4
0
    async def executor(self,
                       executor_protocol: ExecutorProtocol,
                       event_context,
                       extra_parameter={},
                       lru_cache_sets=None
                       ):
        lru_cache_sets = lru_cache_sets or {}
        executor_protocol: ExecutorProtocol
        for depend in executor_protocol.dependencies:
            if not inspect.isclass(depend.func):
                depend_func = depend.func
            elif hasattr(depend.func, "__call__"):
                depend_func = depend.func.__call__
            else:
                raise TypeError("must be callable.")

            if depend_func in lru_cache_sets and depend.cache:
                depend_func = lru_cache_sets[depend_func]
            else:
                if depend.cache:
                    original = depend_func
                    if inspect.iscoroutinefunction(depend_func):
                        depend_func = alru_cache(depend_func)
                    else:
                        depend_func = lru_cache(depend_func)
                    lru_cache_sets[original] = depend_func

            result = await self.executor_with_middlewares(
                depend_func, depend.middlewares, event_context, lru_cache_sets
            )
            if result is TRACEBACKED:
                return TRACEBACKED

        ParamSignatures = argument_signature(executor_protocol.callable)
        PlaceAnnotation = self.get_annotations_mapping()
        CallParams = {}
        for name, annotation, default in ParamSignatures:
            if default:
                if isinstance(default, Depend):
                    if not inspect.isclass(default.func):
                        depend_func = default.func
                    elif hasattr(default.func, "__call__"):
                        depend_func = default.func.__call__
                    else:
                        raise TypeError("must be callable.")

                    if depend_func in lru_cache_sets and default.cache:
                        depend_func = lru_cache_sets[depend_func]
                    else:
                        if default.cache:
                            original = depend_func
                            if inspect.iscoroutinefunction(depend_func):
                                depend_func = alru_cache(depend_func)
                            else:
                                depend_func = lru_cache(depend_func)
                            lru_cache_sets[original] = depend_func

                    CallParams[name] = await self.executor_with_middlewares(
                        depend_func, default.middlewares, event_context, lru_cache_sets
                    )
                    continue
                else:
                    raise RuntimeError("checked a unexpected default value.")
            else:
                if annotation in PlaceAnnotation:
                    CallParams[name] = PlaceAnnotation[annotation](event_context)
                    continue
                else:
                    if name not in extra_parameter:
                        raise RuntimeError(f"checked a unexpected annotation: {annotation}")

        try:
            async with AsyncExitStack() as stack:
                sorted_middlewares = self.sort_middlewares(executor_protocol.middlewares)
                for async_middleware in sorted_middlewares['async']:
                    await stack.enter_async_context(async_middleware)
                for normal_middleware in sorted_middlewares['normal']:
                    stack.enter_context(normal_middleware)

                return await self.run_func(executor_protocol.callable, **CallParams, **extra_parameter)
        except exceptions.Cancelled:
            return TRACEBACKED
        except Exception as e:
            await self.put_exception(event_context, e)
            return TRACEBACKED