Skip to content

Commit 8a6f544

Browse files
committed
initial commit
0 parents  commit 8a6f544

File tree

10 files changed

+303
-0
lines changed

10 files changed

+303
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Voryx LLC
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# File Watcher Component
2+
3+
Watch files for changes with RxPHP
4+
5+
Requires [fswatch](https://github.com/emcrisostomo/fswatch) to be installed.

composer.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "rx/fswatch",
3+
"type": "library",
4+
"description": "Library for monitoring file changes with RxPHP",
5+
"keywords": [
6+
"fswatch",
7+
"child process",
8+
"rxphp",
9+
"reactivex",
10+
"react",
11+
"reactphp",
12+
"rx.php"
13+
],
14+
"license": "MIT",
15+
"authors": [
16+
{
17+
"name": "David Dan",
18+
"email": "[email protected]",
19+
"role": "Developer"
20+
},
21+
{
22+
"name": "Matt Bonneau",
23+
"email": "[email protected]",
24+
"role": "Developer"
25+
}
26+
],
27+
"autoload": {
28+
"psr-4": {
29+
"Rx\\React\\": "src/"
30+
}
31+
},
32+
"require": {
33+
"voryx/event-loop": "^0.2.0",
34+
"rx/child-process": "^0.0.1"
35+
}
36+
}

examples/watch_dir.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use Rx\React\FsWatch;
4+
use Rx\React\WatchEvent;
5+
6+
require __DIR__ . '/../vendor/autoload.php';
7+
8+
$watch = new FsWatch('~/');
9+
10+
$watch->subscribeCallback(function (WatchEvent $e) {
11+
echo "file: ", $e->getFile(), PHP_EOL;
12+
echo "event types: ", json_encode($e->getEvents()), PHP_EOL;
13+
});

examples/watch_extension.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
use Rx\React\FsWatch;
4+
use Rx\React\WatchEvent;
5+
6+
require __DIR__ . '/../vendor/autoload.php';
7+
8+
$watch = new FsWatch(__DIR__, ' -e ".*" -i "\\\.txt$"');
9+
10+
$touch = (new \Rx\React\ProcessSubject('echo hey > ' . __DIR__ . '/test.txt'))->skip(1);
11+
12+
$watch
13+
->merge($touch)
14+
->subscribeCallback(function (WatchEvent $e) {
15+
echo "file: ", $e->getFile(), PHP_EOL;
16+
echo "event types: ", json_encode($e->getEvents()), PHP_EOL;
17+
});

examples/watch_file.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
use Rx\React\FsWatch;
4+
use Rx\React\WatchEvent;
5+
6+
require __DIR__ . '/../vendor/autoload.php';
7+
8+
$watch = new FsWatch(__DIR__ .'/test.txt');
9+
10+
$touch = (new \Rx\React\ProcessSubject('echo hmmm > '.__DIR__ . '/test.txt'))->skip(1);
11+
12+
$watch
13+
->merge($touch)
14+
->subscribeCallback(function (WatchEvent $e) {
15+
echo "file: ", $e->getFile(), PHP_EOL;
16+
echo "event types: ", json_encode($e->getEvents()), PHP_EOL;
17+
});
18+
19+
20+
//file: .../test.txt
21+
//event types: ["CREATED"]

phpunit.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<phpunit
3+
backupGlobals="false"
4+
backupStaticAttributes="false"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnFailure="false"
11+
syntaxCheck="false"
12+
bootstrap="tests/bootstrap.php">
13+
<testsuites>
14+
<testsuite name="Rx/FsWatch Tests">
15+
<directory>tests/</directory>
16+
</testsuite>
17+
</testsuites>
18+
19+
</phpunit>

src/FsWatch.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Rx\React;
4+
5+
use React\EventLoop\LoopInterface;
6+
use Rx\Observable;
7+
use Rx\ObserverInterface;
8+
use Rx\SchedulerInterface;
9+
use Rx\Subject\Subject;
10+
11+
class FsWatch extends Observable
12+
{
13+
private $process;
14+
private $errors;
15+
16+
public function __construct($path, $options = null, LoopInterface $loop = null)
17+
{
18+
$cmd = "fswatch -xrn {$path} " . $options;
19+
20+
$this->errors = new Subject();
21+
$this->process = new ProcessSubject($cmd, $this->errors, null, null, [], $loop);
22+
}
23+
24+
public function subscribe(ObserverInterface $observer, SchedulerInterface $scheduler = null)
25+
{
26+
return $this->process
27+
->merge($this->errors->map(function (\Exception $ex) {
28+
throw $ex;
29+
}))
30+
->map(function ($data) {
31+
list($file, $bitwise) = explode(" ", $data);
32+
return new WatchEvent($file, (int)$bitwise);
33+
})
34+
->subscribe($observer, $scheduler);
35+
}
36+
}

src/WatchEvent.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
3+
namespace Rx\React;
4+
5+
class WatchEvent
6+
{
7+
private $bitwise;
8+
private $file;
9+
private $events = [];
10+
11+
const NO_OP = 0;
12+
const PLATFORM_SPECIFIC = 1;
13+
const CREATED = 2;
14+
const UPDATED = 4;
15+
const REMOVED = 8;
16+
const RENAMED = 16;
17+
const OWNER_MODIFIED = 32;
18+
const ATTRIBUTE_MODIFIED = 64;
19+
const MOVED_FROM = 128;
20+
const MOVED_TO = 256;
21+
const IS_FILE = 512;
22+
const IS_DIR = 1024;
23+
const IS_SYM_LINK = 2048;
24+
const LINK = 4096;
25+
const OVERFLOW = 8192;
26+
27+
public function __construct($file, $bitwise)
28+
{
29+
$this->bitwise = $bitwise;
30+
$this->file = $file;
31+
}
32+
33+
public function getBitwise()
34+
{
35+
return $this->bitwise;
36+
}
37+
38+
public function getFile()
39+
{
40+
return $this->file;
41+
}
42+
43+
public function getEvents()
44+
{
45+
if ($this->bitwise & self::NO_OP) $this->events[] = "NO_OP";
46+
if ($this->bitwise & self::ATTRIBUTE_MODIFIED) $this->events[] = "ATTRIBUTE_MODIFIED";
47+
if ($this->bitwise & self::OWNER_MODIFIED) $this->events[] = "OWNER_MODIFIED";
48+
if ($this->bitwise & self::CREATED) $this->events[] = "CREATED";
49+
if ($this->bitwise & self::REMOVED) $this->events[] = "REMOVED";
50+
if ($this->bitwise & self::RENAMED) $this->events[] = "RENAMED";
51+
if ($this->bitwise & self::UPDATED) $this->events[] = "UPDATED";
52+
if ($this->bitwise & self::MOVED_FROM) $this->events[] = "MOVED_FROM";
53+
if ($this->bitwise & self::MOVED_TO) $this->events[] = "MOVED_TO";
54+
if ($this->bitwise & self::OVERFLOW) $this->events[] = "OVERFLOW";
55+
56+
return $this->events;
57+
}
58+
59+
public function isFile()
60+
{
61+
return (bool)$this->bitwise & self::IS_FILE;
62+
}
63+
64+
public function isDir()
65+
{
66+
return (bool)$this->bitwise & self::IS_DIR;
67+
}
68+
69+
public function isSymbolicLink()
70+
{
71+
return (bool)$this->bitwise & self::IS_SYM_LINK;
72+
}
73+
74+
public function isLink()
75+
{
76+
return (bool)$this->bitwise & self::LINK;
77+
}
78+
79+
public function noOp()
80+
{
81+
return (bool)$this->bitwise & self::NO_OP;
82+
}
83+
84+
public function attributeModified()
85+
{
86+
return (bool)$this->bitwise & self::ATTRIBUTE_MODIFIED;
87+
}
88+
89+
public function ownerModified()
90+
{
91+
return (bool)$this->bitwise & self::OWNER_MODIFIED;
92+
}
93+
94+
public function created()
95+
{
96+
return (bool)$this->bitwise & self::CREATED;
97+
}
98+
99+
public function removed()
100+
{
101+
return (bool)$this->bitwise & self::REMOVED;
102+
}
103+
104+
public function renamed()
105+
{
106+
return (bool)$this->bitwise & self::RENAMED;
107+
}
108+
109+
public function updated()
110+
{
111+
return (bool)$this->bitwise & self::UPDATED;
112+
}
113+
}

tests/bootstrap.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Find the auto loader file
4+
*/
5+
$locations = [
6+
__DIR__ . '/../',
7+
__DIR__ . '/../../',
8+
__DIR__ . '/../../../',
9+
__DIR__ . '/../../../../',
10+
];
11+
12+
13+
foreach ($locations as $location) {
14+
15+
$file = $location . "vendor/autoload.php";
16+
17+
if (file_exists($file)) {
18+
$loader = require_once $file;
19+
$loader->addPsr4('Rx\\React\\Tests\\', __DIR__);
20+
break;
21+
}
22+
}

0 commit comments

Comments
 (0)