diff --git a/README.md b/README.md index 918e40b..9c75836 100644 --- a/README.md +++ b/README.md @@ -1 +1,23 @@ # Inotify library for ReactPHP + +## Installing + +```bash +$ composer repo add noccylabs composer https://dev.noccylabs.info/api/packages/noccylabs/composer +$ composer require noccylabs/react-inotify +``` + +## Usage + +```php +// Create instance; you can pass a poll interval and a custom event loop. +$inotify = new NoccyLabs\React\Inotify\Inotify(0.1); + +// Listen for events +$in->on("event", function ($event) { + var_dump($event); +}); + +// Add a watch +$in->addWatch(__DIR__."/config", IN_CREATE|IN_DELETE|IN_MODIFY); +``` diff --git a/src/Inotify.php b/src/Inotify.php index 0977601..e9859c3 100644 --- a/src/Inotify.php +++ b/src/Inotify.php @@ -5,8 +5,15 @@ namespace NoccyLabs\React\Inotify; use Evenement\EventEmitterInterface; use Evenement\EventEmitterTrait; use React\EventLoop\Loop; +use React\EventLoop\LoopInterface; use React\EventLoop\TimerInterface; +use function inotify_init; +use function inotify_add_watch; +use function inotify_queue_len; +use function inotify_rm_watch; +use function inotify_read; + class Inotify implements EventEmitterInterface { use EventEmitterTrait; @@ -15,10 +22,18 @@ class Inotify implements EventEmitterInterface private ?TimerInterface $timer = null; - public function __construct() + private LoopInterface $loop; + + public function __construct(float $pollInterval = 1.0, ?LoopInterface $loop = null) { - $this->fd = \inotify_init(); - $this->timer = Loop::addPeriodicTimer(0.1, $this->tick(...)); + + if (!is_callable('inotify_init')) { + throw new InotifyException("inotify PHP extension not installed"); + } + + $this->loop = $loop ?? Loop::get(); + $this->fd = inotify_init(); + $this->timer = $this->loop->addPeriodicTimer($pollInterval, $this->tick(...)); } public function __destruct() @@ -28,14 +43,14 @@ class Inotify implements EventEmitterInterface $this->fd = null; } if ($this->timer instanceof TimerInterface) { - Loop::clearTimer($this->timer); + $this->loop->cancelTimer($this->timer); $this->timer = null; } } public function addWatch(string $path, int $mask): int { - $descriptor = \inotify_add_watch($this->fd, $path, $mask); + $descriptor = inotify_add_watch($this->fd, $path, $mask); if (false === $descriptor) throw new WatchErrorException("Failed to add watch for path \"{$path}\""); @@ -45,16 +60,18 @@ class Inotify implements EventEmitterInterface public function removeWatch(int $descriptor): void { - \inotify_rm_watch($this->fd, $descriptor); + if (!inotify_rm_watch($this->fd, $descriptor)) { + throw new WatchErrorException("Unable to remove watch descriptor {$descriptor}"); + } } private function tick(): void { - $len = \inotify_queue_len($this->fd); + $len = inotify_queue_len($this->fd); if ($len === 0) return; - $reads = \inotify_read($this->fd); + $reads = inotify_read($this->fd); while ($read = array_shift($reads)) { $event = new InotifyEvent(...$read); $this->emit("event", [ $event ]); @@ -62,4 +79,3 @@ class Inotify implements EventEmitterInterface } } - diff --git a/src/InotifyException.php b/src/InotifyException.php new file mode 100644 index 0000000..afafa63 --- /dev/null +++ b/src/InotifyException.php @@ -0,0 +1,10 @@ +