Code cleanup and misc fixes

* Properly implement exceptions.
* Allow passing custom eventloop and poll interval to constructor.
* Fix some typos, cleanup code.
This commit is contained in:
Christopher Vagnetoft
2026-01-09 15:47:44 +01:00
parent 904b426a00
commit b8a0dbf2bf
4 changed files with 65 additions and 9 deletions

View File

@@ -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);
```

View File

@@ -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
}
}

10
src/InotifyException.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace NoccyLabs\React\Inotify;
use Exception;
class InotifyException extends Exception
{
}

View File

@@ -0,0 +1,8 @@
<?php
namespace NoccyLabs\React\Inotify;
class WatchErrorException extends InotifyException
{
}