FswatchDriver.php 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Watcher\Driver;
  12. use Hyperf\Engine\Channel;
  13. use Hyperf\Engine\Coroutine;
  14. use Hyperf\Stringable\Str;
  15. use Hyperf\Watcher\Option;
  16. use InvalidArgumentException;
  17. use RuntimeException;
  18. use function Hyperf\Watcher\exec;
  19. class FswatchDriver extends AbstractDriver
  20. {
  21. protected mixed $process = null;
  22. public function __construct(protected Option $option)
  23. {
  24. parent::__construct($option);
  25. $ret = exec('which fswatch');
  26. if (empty($ret['output'])) {
  27. throw new InvalidArgumentException('fswatch not exists. You can `brew install fswatch` to install it.');
  28. }
  29. }
  30. public function watch(Channel $channel): void
  31. {
  32. $cmd = $this->getCmd();
  33. $this->process = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w']], $pipes);
  34. if (! is_resource($this->process)) {
  35. throw new RuntimeException('fswatch failed.');
  36. }
  37. while (! $channel->isClosing()) {
  38. $ret = fread($pipes[1], 8192);
  39. if (is_string($ret) && $ret !== '') {
  40. Coroutine::create(function () use ($ret, $channel) {
  41. $files = array_filter(explode("\n", $ret));
  42. foreach ($files as $file) {
  43. if (Str::endsWith($file, $this->option->getExt())) {
  44. $channel->push($file);
  45. }
  46. }
  47. });
  48. }
  49. }
  50. }
  51. public function stop()
  52. {
  53. parent::stop();
  54. if (is_resource($this->process)) {
  55. $running = proc_get_status($this->process)['running'];
  56. // Kill the child process to exit.
  57. $running && proc_terminate($this->process, SIGKILL);
  58. }
  59. }
  60. protected function getCmd(): string
  61. {
  62. $dir = $this->option->getWatchDir();
  63. $file = $this->option->getWatchFile();
  64. $cmd = 'fswatch ';
  65. if (! $this->isDarwin()) {
  66. $cmd .= ' -m inotify_monitor';
  67. $cmd .= " -E --format '%p' -r ";
  68. $cmd .= ' --event Created --event Updated --event Removed --event Renamed ';
  69. }
  70. return $cmd . implode(' ', $dir) . ' ' . implode(' ', $file);
  71. }
  72. }