move the asynchronous registration of handlers to a dedicated PluginManager function

This commit is contained in:
ShockedPlot7560 2023-10-27 21:58:43 +02:00
parent 5beaa3ce4e
commit cc6e8ef232
No known key found for this signature in database
GPG Key ID: D7539B420F1FA86E
2 changed files with 49 additions and 16 deletions

View File

@ -31,5 +31,5 @@ final class ListenerMethodTags{
public const HANDLE_CANCELLED = "handleCancelled"; public const HANDLE_CANCELLED = "handleCancelled";
public const NOT_HANDLER = "notHandler"; public const NOT_HANDLER = "notHandler";
public const PRIORITY = "priority"; public const PRIORITY = "priority";
public const NO_CONCURRENT_CALL = "noConcurrentCall"; public const EXCLUSIVE_CALL = "exclusiveCall";
} }

View File

@ -629,29 +629,33 @@ class PluginManager{
throw new PluginException("Event handler " . Utils::getNiceClosureName($handlerClosure) . "() declares invalid @" . ListenerMethodTags::HANDLE_CANCELLED . " value \"" . $tags[ListenerMethodTags::HANDLE_CANCELLED] . "\""); throw new PluginException("Event handler " . Utils::getNiceClosureName($handlerClosure) . "() declares invalid @" . ListenerMethodTags::HANDLE_CANCELLED . " value \"" . $tags[ListenerMethodTags::HANDLE_CANCELLED] . "\"");
} }
} }
$noConcurrentCall = false; $exclusiveCall = false;
if(isset($tags[ListenerMethodTags::NO_CONCURRENT_CALL])){ if(isset($tags[ListenerMethodTags::EXCLUSIVE_CALL])){
if(!is_a($eventClass, AsyncEvent::class, true)){ if(!is_a($eventClass, AsyncEvent::class, true)){
throw new PluginException(sprintf( throw new PluginException(sprintf(
"Event handler %s() declares @%s for non-async event of type %s", "Event handler %s() declares @%s for non-async event of type %s",
Utils::getNiceClosureName($handlerClosure), Utils::getNiceClosureName($handlerClosure),
ListenerMethodTags::NO_CONCURRENT_CALL, ListenerMethodTags::EXCLUSIVE_CALL,
$eventClass $eventClass
)); ));
} }
switch(strtolower($tags[ListenerMethodTags::NO_CONCURRENT_CALL])){ switch(strtolower($tags[ListenerMethodTags::EXCLUSIVE_CALL])){
case "true": case "true":
case "": case "":
$noConcurrentCall = true; $exclusiveCall = true;
break; break;
case "false": case "false":
break; break;
default: default:
throw new PluginException("Event handler " . Utils::getNiceClosureName($handlerClosure) . "() declares invalid @" . ListenerMethodTags::NO_CONCURRENT_CALL . " value \"" . $tags[ListenerMethodTags::NO_CONCURRENT_CALL] . "\""); throw new PluginException("Event handler " . Utils::getNiceClosureName($handlerClosure) . "() declares invalid @" . ListenerMethodTags::EXCLUSIVE_CALL . " value \"" . $tags[ListenerMethodTags::EXCLUSIVE_CALL] . "\"");
} }
} }
$this->registerEvent($eventClass, $handlerClosure, $priority, $plugin, $handleCancelled, $noConcurrentCall); if(is_subclass_of($eventClass, AsyncEvent::class) && $this->canHandleAsyncEvent($handlerClosure)){
$this->registerAsyncEvent($eventClass, $handlerClosure, $priority, $plugin, $handleCancelled, $exclusiveCall);
}else{
$this->registerEvent($eventClass, $handlerClosure, $priority, $plugin, $handleCancelled);
}
} }
} }
@ -660,11 +664,11 @@ class PluginManager{
* *
* @phpstan-template TEvent of Event * @phpstan-template TEvent of Event
* @phpstan-param class-string<TEvent> $event * @phpstan-param class-string<TEvent> $event
* @phpstan-param (\Closure(TEvent) : void)|(\Closure(AsyncEvent&TEvent) : Promise<null>) $handler * @phpstan-param \Closure(TEvent) : void $handler
* *
* @throws \ReflectionException * @throws \ReflectionException
*/ */
public function registerEvent(string $event, \Closure $handler, int $priority, Plugin $plugin, bool $handleCancelled = false, bool $noConcurrentCall = false) : RegisteredListener{ public function registerEvent(string $event, \Closure $handler, int $priority, Plugin $plugin, bool $handleCancelled = false) : RegisteredListener{
if(!is_subclass_of($event, Event::class)){ if(!is_subclass_of($event, Event::class)){
throw new PluginException($event . " is not an Event"); throw new PluginException($event . " is not an Event");
} }
@ -677,11 +681,38 @@ class PluginManager{
$timings = Timings::getEventHandlerTimings($event, $handlerName, $plugin->getDescription()->getFullName()); $timings = Timings::getEventHandlerTimings($event, $handlerName, $plugin->getDescription()->getFullName());
if(is_subclass_of($event, AsyncEvent::class) && $this->canHandleAsyncEvent($handler)){ $registeredListener = new RegisteredListener($handler, $priority, $plugin, $handleCancelled, $timings);
$registeredListener = new RegisteredAsyncListener($handler, $priority, $plugin, $handleCancelled, $noConcurrentCall, $timings); HandlerListManager::global()->getListFor($event)->register($registeredListener);
}else{ return $registeredListener;
$registeredListener = new RegisteredListener($handler, $priority, $plugin, $handleCancelled, $timings); }
/**
* @param string $event Class name that extends Event and AsyncEvent
*
* @phpstan-template TEvent of Event&AsyncEvent
* @phpstan-param class-string<TEvent> $event
* @phpstan-param \Closure(TEvent) : Promise<null> $handler
*
* @throws \ReflectionException
*/
public function registerAsyncEvent(string $event, \Closure $handler, int $priority, Plugin $plugin, bool $handleCancelled = false, bool $exclusiveCall = false) : RegisteredAsyncListener{
if(!is_subclass_of($event, Event::class)){
throw new PluginException($event . " is not an Event");
} }
if(!is_subclass_of($event, AsyncEvent::class)){
throw new PluginException($event . " is not an AsyncEvent");
}
$handlerName = Utils::getNiceClosureName($handler);
if(!$plugin->isEnabled()){
throw new PluginException("Plugin attempted to register event handler " . $handlerName . "() to event " . $event . " while not enabled");
}
$timings = Timings::getEventHandlerTimings($event, $handlerName, $plugin->getDescription()->getFullName());
$registeredListener = new RegisteredAsyncListener($handler, $priority, $plugin, $handleCancelled, $exclusiveCall, $timings);
HandlerListManager::global()->getListFor($event)->register($registeredListener); HandlerListManager::global()->getListFor($event)->register($registeredListener);
return $registeredListener; return $registeredListener;
} }
@ -689,8 +720,10 @@ class PluginManager{
/** /**
* Check if the given handler return type is async-compatible (equal to Promise) * Check if the given handler return type is async-compatible (equal to Promise)
* *
* @phpstan-template TEvent of Event * @phpstan-template TEvent of Event&AsyncEvent
* @phpstan-param (\Closure(TEvent) : void)|(\Closure(AsyncEvent&TEvent) : Promise<null>) $handler * @phpstan-param \Closure(TEvent) : Promise<null> $handler
*
* @throws \ReflectionException
*/ */
private function canHandleAsyncEvent(\Closure $handler) : bool{ private function canHandleAsyncEvent(\Closure $handler) : bool{
$reflection = new \ReflectionFunction($handler); $reflection = new \ReflectionFunction($handler);