add timer tick

This commit is contained in:
Jerry 2023-02-10 13:12:20 +08:00
parent f03c0940da
commit df25aebd60
11 changed files with 132 additions and 6 deletions

View File

@ -12,13 +12,13 @@
`\ZM\Annotation\OneBot\BotCommand` 注解事件类,在经过全局别名后,你也可以使用 `\BotCommand` 作为注解事件,效果相同。
## 别名列表
| 全类名 | 别名 |
|--------------------------------------------------------|-------------------------|
| `\ZM\Annotation\Framework\BindEvent` | `BindEvent` |
| `\ZM\Annotation\Framework\Cron` | `Cron` |
| `\ZM\Annotation\Framework\Init` | `Init` |
| `\ZM\Annotation\Framework\Setup` | `Setup` |
| `\ZM\Annotation\Framework\Tick` | `Tick` |
| `\ZM\Annotation\Http\Controller` | `Controller` |
| `\ZM\Annotation\Http\Route` | `Route` |
| `\ZM\Annotation\Middleware\Middleware` | `Middleware` |

View File

@ -6,6 +6,7 @@ class_alias(\ZM\Annotation\Framework\BindEvent::class, 'BindEvent');
class_alias(\ZM\Annotation\Framework\Cron::class, 'Cron');
class_alias(\ZM\Annotation\Framework\Init::class, 'Init');
class_alias(\ZM\Annotation\Framework\Setup::class, 'Setup');
class_alias(\ZM\Annotation\Framework\Tick::class, 'Tick');
class_alias(\ZM\Annotation\Http\Controller::class, 'Controller');
class_alias(\ZM\Annotation\Http\Route::class, 'Route');

View File

@ -13,6 +13,7 @@ use ZM\Config\ZMConfig;
use ZM\Container\ContainerHolder;
use ZM\Logger\ConsoleLogger;
use ZM\Middleware\MiddlewareHandler;
use ZM\Schedule\Timer;
use ZM\Store\Database\DBException;
use ZM\Store\Database\DBQueryBuilder;
use ZM\Store\Database\DBWrapper;
@ -55,6 +56,29 @@ function zm_sleep(float|int $time)
Adaptive::sleep($time);
}
/**
* 创建一个计时器Timer::tick() 的别名)
*
* @param int $ms 时间(毫秒)
* @param callable $callback 回调函数
* @param int $times 重复次数(如果为 0 -1,则永久循环,其他大于 0 的数为限定次数)
*/
function zm_timer_tick(int $ms, callable $callback, int $times = 0): int
{
return Timer::tick($ms, $callback, $times);
}
/**
* 创建一个延后一次性计时器只在指定毫秒后执行一次即销毁Timer::after() 的别名)
*
* @param int $ms 时间(毫秒)
* @param callable $callback 回调函数
*/
function zm_timer_after(int $ms, callable $callback): int
{
return Timer::after($ms, $callback);
}
/**
* 获取协程接口
*/

View File

@ -8,11 +8,13 @@ use Doctrine\Common\Annotations\AnnotationReader;
use Koriym\Attributes\AttributeReader;
use Koriym\Attributes\DualReader;
use ZM\Annotation\Framework\Cron;
use ZM\Annotation\Framework\Tick;
use ZM\Annotation\Http\Controller;
use ZM\Annotation\Http\Route;
use ZM\Annotation\Interfaces\ErgodicAnnotation;
use ZM\Annotation\Middleware\Middleware;
use ZM\Schedule\Schedule;
use ZM\Schedule\Timer;
use ZM\Store\FileSystem;
use ZM\Utils\HttpUtil;
@ -62,6 +64,7 @@ class AnnotationParser
Route::class => [[$this, 'addRouteAnnotation']],
Closed::class => [fn () => false],
Cron::class => [[resolve(Schedule::class), 'addSchedule']],
Tick::class => [[Timer::class, 'registerTick']],
];
}
}
@ -240,7 +243,13 @@ class AnnotationParser
return $o;
}
public function parseSpecial($annotation, $same_method_annotations = null): ?bool
/**
* 单独解析特殊注解
*
* @param object|string $annotation 注解对象
* @param null|array $same_method_annotations 相同方法下的其他注解列表(可为数组或 null
*/
public function parseSpecial(object|string $annotation, ?array $same_method_annotations = null): ?bool
{
foreach (($this->special_parsers[$annotation::class] ?? []) as $parser) {
$result = $parser($annotation, $same_method_annotations);

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace ZM\Annotation\Framework;
use Symfony\Contracts\Service\Attribute\Required;
use ZM\Annotation\AnnotationBase;
/**
* @Annotation
* @NamedArgumentConstructor()
* @Target("METHOD")
*/
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
class Tick extends AnnotationBase
{
#[Required]
public int $tick_ms;
public function __construct(int $tick_ms, public int $worker_id = 0)
{
$this->tick_ms = $tick_ms;
}
}

View File

@ -199,14 +199,14 @@ class WorkerEventListener
// 从 plugins 目录加载插件,包含 phar 和文件夹形式
$count = PluginManager::addPluginsFromDir($load_dir);
if ($count !== 0) {
logger()->info('Loaded ' . $count . ' user plugins from plugin dir');
logger()->debug('已加载 ' . $count . ' 个普通插件');
}
// 从 composer 依赖加载插件
if (config('global.plugin.composer_plugin_enable', true)) {
$count = PluginManager::addPluginsFromComposer();
if ($count !== 0) {
logger()->info('Loaded ' . $count . ' user plugins from composer');
logger()->info('已加载 ' . $count . ' 个 Composer 插件');
}
}

View File

@ -46,7 +46,7 @@ class Framework
public const VERSION_ID = 681;
/** @var string 版本名称 */
public const VERSION = '3.0.0-beta7';
public const VERSION = '3.0.0-beta8';
/** @var array 传入的参数 */
protected array $argv;

View File

@ -208,7 +208,7 @@ class PluginManager
foreach (self::$plugins as $name => $meta) {
// 除了内建插件外,输出 log 告知启动插件
if ($meta->getPluginType() !== ZM_PLUGIN_TYPE_NATIVE) {
logger()->info('Enabling plugin: ' . $name);
logger()->info('正在启用插件 ' . $name);
}
// 先判断依赖关系,如果声明了依赖,但依赖不合规则报错崩溃
foreach ($meta->getDependencies() as $dep_name => $dep_version) {
@ -257,6 +257,11 @@ class PluginManager
foreach ($entity->getInits() as $init) {
AnnotationMap::addSingleAnnotation($init);
}
// 设置 TimerTick 注解
foreach ($entity->getTimerTicks() as $tick) {
AnnotationMap::addSingleAnnotation($tick);
$parser->parseSpecial($tick);
}
}
// 如果设置了 Autoload file那么将会把 psr-4 的加载路径丢进 parser
foreach ($meta->getAutoloadPsr4() as $namespace => $path) {

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace ZM\Plugin\Traits;
use ZM\Annotation\Framework\Tick;
trait TickTrait
{
protected array $ticks = [];
public function addTimerTick(int $ms, callable $callback, int $worker_id = 0): void
{
$tick = new Tick($ms, $worker_id);
if (is_array($callback)) {
$tick->class = $callback[0];
$tick->method = $callback[1];
} elseif ($callback instanceof \Closure) {
$tick->method = $callback;
}
$this->ticks[] = $tick;
}
public function getTimerTicks(): array
{
return $this->ticks;
}
}

View File

@ -18,4 +18,5 @@ class ZMPlugin
use Traits\PluginLoadTrait;
use Traits\RouteTrait;
use Traits\PluginPackTrait;
use Traits\TickTrait;
}

32
src/ZM/Schedule/Timer.php Normal file
View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace ZM\Schedule;
use ZM\Annotation\Framework\Tick;
use ZM\Framework;
class Timer
{
public static function tick(int $ms, callable $callback, int $times = 0): int
{
return Framework::getInstance()->getDriver()->getEventLoop()->addTimer($ms, $callback, $times);
}
public static function after(int $ms, callable $callback): int
{
return Framework::getInstance()->getDriver()->getEventLoop()->addTimer($ms, $callback);
}
public static function registerTick(Tick $v): void
{
if ($v->class !== '' && $v->method !== '') {
self::tick($v->tick_ms, [resolve($v->class), $v->method]);
} elseif (is_callable($v->method)) {
self::tick($v->tick_ms, $v->method);
} else {
logger()->warning('注册的 Tick 定时器回调函数错误');
}
}
}