Files
kiri-core/kiri-actor/Actor.php
T

238 lines
3.2 KiB
PHP
Raw Normal View History

2022-10-11 14:33:33 +08:00
<?php
namespace Kiri\Actor;
2022-10-11 17:35:42 +08:00
use Exception;
2022-10-11 15:19:48 +08:00
use JsonSerializable;
2022-10-11 15:51:01 +08:00
use Swoole\Coroutine;
2022-10-11 14:33:33 +08:00
use Swoole\Coroutine\Channel;
2022-10-11 18:00:22 +08:00
/**
* @Actor
*/
2022-10-11 15:19:48 +08:00
abstract class Actor implements ActorInterface, JsonSerializable
2022-10-11 14:33:33 +08:00
{
/**
* @var Channel
*/
private Channel $channel;
/**
* @var bool
*/
private bool $isShutdown = false;
2022-10-11 17:33:00 +08:00
/**
* @var int
*/
private int $messageId = -1;
2022-10-11 15:58:20 +08:00
/**
* @var int
*/
private int $coroutineId = -1;
2022-10-11 14:33:33 +08:00
/**
* @var ActorState
*/
private ActorState $state;
/**
* @var float
*/
private float $startTime = 0;
2022-10-11 17:33:00 +08:00
/**
* @var int
*/
private int $refreshInterval = 0;
2022-10-11 14:33:33 +08:00
/**
* @return ActorState
*/
public function getState(): ActorState
{
return $this->state;
}
/**
* @param ActorState $state
*/
public function setState(ActorState $state): void
{
$this->state = $state;
}
/**
* @return float
*/
public function getRunTime(): float
{
return microtime(true) - $this->startTime;
}
/**
* @param string $uniqueId
*/
private function __construct(readonly public string $uniqueId)
{
2022-10-11 15:19:48 +08:00
$this->channel = new Channel(99);
2022-10-11 14:33:33 +08:00
$this->startTime = microtime(true);
}
2022-10-11 15:27:48 +08:00
/**
* @return void
*/
public function init(): void
{
}
2022-10-11 17:33:00 +08:00
/**
* @return bool
*/
public function isShutdown(): bool
{
return $this->isShutdown;
}
2022-10-11 14:33:33 +08:00
/**
* @param $id
* @return static
*/
public static function newActor($id): static
{
2022-10-11 15:51:01 +08:00
$actor = new static($id);
2022-10-11 15:58:20 +08:00
$actor->listen();
2022-10-11 15:51:01 +08:00
return $actor;
2022-10-11 14:33:33 +08:00
}
2022-10-11 15:58:20 +08:00
/**
* @return void
*/
private function listen(): void
{
Coroutine::create(function (Actor $actor) {
$actor->coroutineId = Coroutine::getCid();
$this->run();
}, $this);
}
2022-10-11 14:33:33 +08:00
/**
* @return string
*/
public function getName(): string
{
return $this->uniqueId;
}
/**
* @param mixed $response
* @return bool
*/
public function write(mixed $response): bool
{
return $this->channel->push($response);
}
/**
* @return void
*/
public function shutdown(): void
{
$this->isShutdown = true;
2022-10-11 17:33:00 +08:00
Coroutine::cancel($this->coroutineId);
if ($this->messageId > -1) {
Coroutine::cancel($this->messageId);
}
2022-10-11 14:33:33 +08:00
$this->channel->close();
}
2022-10-11 17:33:00 +08:00
/**
* @return void
*/
2022-10-11 17:55:03 +08:00
public function onUpdate(): void
{
}
2022-10-11 17:33:00 +08:00
2022-10-11 14:33:33 +08:00
/**
* @return void
2022-10-11 17:35:42 +08:00
* @throws Exception
2022-10-11 14:33:33 +08:00
*/
public function run(): void
{
2022-10-11 17:35:42 +08:00
if ($this->refreshInterval < 1) {
throw new Exception('Refresh interval must be greater than 1');
}
2022-10-11 14:33:33 +08:00
$this->setState(ActorState::BUSY);
2022-10-11 15:27:48 +08:00
$this->init();
2022-10-11 17:33:00 +08:00
$this->messageId = Coroutine::create(fn() => $this->loop());
$this->interval();
2022-10-11 14:33:33 +08:00
$this->setState(ActorState::IDLE);
2022-10-11 15:19:48 +08:00
}
/**
2022-10-11 17:33:00 +08:00
* @return void
*/
private function interval(): void
{
if ($this->isShutdown()) {
return;
}
2022-10-11 17:35:42 +08:00
try {
$this->onUpdate();
} catch (\Throwable $exception) {
\Kiri::getLogger()->error(throwable($exception));
}
2022-10-11 17:33:00 +08:00
Coroutine::sleep($this->refreshInterval / 1000);
$this->interval();
}
/**
* @return bool
2022-10-11 15:19:48 +08:00
*/
2022-10-11 17:33:00 +08:00
private function loop(): bool
2022-10-11 15:19:48 +08:00
{
2022-10-11 17:33:00 +08:00
if ($this->messageId == -1) {
$this->messageId = Coroutine::getCid();
}
2022-10-11 15:19:48 +08:00
if ($this->channel->errCode == SWOOLE_CHANNEL_CLOSED) {
$this->channel = new Channel(99);
2022-10-11 14:33:33 +08:00
}
2022-10-11 15:19:48 +08:00
$message = $this->channel->pop();
$this->process($message);
2022-10-11 17:33:00 +08:00
if ($this->isShutdown()) {
return true;
}
2022-10-11 15:19:48 +08:00
return $this->loop();
2022-10-11 14:33:33 +08:00
}
}