Passed
Push — master ( 46ff08...39265b )
by Biao
05:26
created

Inotify::addExcludedDirs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Hhxsv5\LaravelS\Swoole;
4
5
class Inotify
6
{
7
    private $fd;
8
    private $watchPath;
9
    private $watchMask;
10
    private $watchHandler;
11
    private $doing        = false;
12
    private $fileTypes    = [];
13
    private $excludedDirs = [];
14
    private $wdPath       = [];
15
    private $pathWd       = [];
16
17
    public function __construct($watchPath, $watchMask, callable $watchHandler)
18
    {
19
        $this->fd = inotify_init();
20
        $this->watchPath = $watchPath;
21
        $this->watchMask = $watchMask;
22
        $this->watchHandler = $watchHandler;
23
    }
24
25
    public function addFileType($type)
26
    {
27
        $type = '.' . trim($type, '.');
28
        $this->fileTypes[$type] = true;
29
    }
30
31
    public function addFileTypes(array $types)
32
    {
33
        foreach ($types as $type) {
34
            $this->addFileType($type);
35
        }
36
    }
37
38
    public function addExcludedDir($dir)
39
    {
40
        $dir = realpath($dir);
41
        $this->excludedDirs[$dir] = $dir;
42
    }
43
44
    public function addExcludedDirs(array $dirs)
45
    {
46
        foreach ($dirs as $dir) {
47
            $this->addExcludedDir($dir);
48
        }
49
    }
50
51
    public function isExcluded($path)
52
    {
53
        foreach ($this->excludedDirs as $excludedDir) {
54
            if ($excludedDir === $path || strpos($path, $excludedDir . '/') === 0) {
55
                return true;
56
            }
57
        }
58
        return false;
59
    }
60
61
    public function watch()
62
    {
63
        $this->_watch($this->watchPath);
64
    }
65
66
    protected function _watch($path)
67
    {
68
        if ($this->isExcluded($path)) {
69
            return false;
70
        }
71
        $wd = inotify_add_watch($this->fd, $path, $this->watchMask);
72
        if ($wd === false) {
73
            return false;
74
        }
75
        $this->bind($wd, $path);
76
77
        if (is_dir($path)) {
78
            $files = scandir($path);
79
            foreach ($files as $file) {
80
                if ($file === '.' || $file === '..' || $this->isExcluded($file)) {
81
                    continue;
82
                }
83
                $file = $path . DIRECTORY_SEPARATOR . $file;
84
                if (is_dir($file)) {
85
                    $this->_watch($file);
86
                }
87
88
                $fileType = strrchr($file, '.');
89
                if (isset($this->fileTypes[$fileType])) {
90
                    $wd = inotify_add_watch($this->fd, $file, $this->watchMask);
91
                    if ($wd === false) {
92
                        return false;
93
                    }
94
                    $this->bind($wd, $file);
95
                }
96
            }
97
        }
98
        return true;
99
    }
100
101
    protected function clearWatch()
102
    {
103
        foreach ($this->wdPath as $wd => $path) {
104
            @inotify_rm_watch($this->fd, $wd);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for inotify_rm_watch(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

104
            /** @scrutinizer ignore-unhandled */ @inotify_rm_watch($this->fd, $wd);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
105
        }
106
        $this->wdPath = [];
107
        $this->pathWd = [];
108
    }
109
110
    protected function bind($wd, $path)
111
    {
112
        $this->pathWd[$path] = $wd;
113
        $this->wdPath[$wd] = $path;
114
    }
115
116
    protected function unbind($wd, $path = null)
117
    {
118
        unset($this->wdPath[$wd]);
119
        if ($path !== null) {
120
            unset($this->pathWd[$path]);
121
        }
122
    }
123
124
    public function start()
125
    {
126
        swoole_event_add($this->fd, function ($fp) {
0 ignored issues
show
Bug introduced by
$this->fd of type resource is incompatible with the type integer expected by parameter $sock of swoole_event_add(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

126
        swoole_event_add(/** @scrutinizer ignore-type */ $this->fd, function ($fp) {
Loading history...
127
            $events = inotify_read($fp);
128
            foreach ($events as $event) {
129
                if ($event['mask'] == IN_IGNORED) {
130
                    continue;
131
                }
132
133
                $fileType = strchr($event['name'], '.');
134
                if (!isset($this->fileTypes[$fileType])) {
135
                    continue;
136
                }
137
138
                if ($this->doing) {
139
                    continue;
140
                }
141
142
                swoole_timer_after(100, function () use ($event) {
143
                    call_user_func_array($this->watchHandler, [$event]);
144
                    $this->doing = false;
145
                });
146
                $this->doing = true;
147
                break;
148
            }
149
        });
150
        swoole_event_wait();
151
    }
152
153
    public function stop()
154
    {
155
        swoole_event_del($this->fd);
0 ignored issues
show
Bug introduced by
$this->fd of type resource is incompatible with the type integer expected by parameter $sock of swoole_event_del(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
        swoole_event_del(/** @scrutinizer ignore-type */ $this->fd);
Loading history...
156
        fclose($this->fd);
157
    }
158
159
    public function getWatchedFileCount()
160
    {
161
        return count($this->wdPath);
162
    }
163
164
    public function __destruct()
165
    {
166
        $this->stop();
167
    }
168
}
169