1<?php
2
3/**
4 * Hoa
5 *
6 *
7 * @license
8 *
9 * New BSD License
10 *
11 * Copyright © 2007-2017, Hoa community. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *     * Redistributions of source code must retain the above copyright
16 *       notice, this list of conditions and the following disclaimer.
17 *     * Redistributions in binary form must reproduce the above copyright
18 *       notice, this list of conditions and the following disclaimer in the
19 *       documentation and/or other materials provided with the distribution.
20 *     * Neither the name of the Hoa nor the names of its contributors may be
21 *       used to endorse or promote products derived from this software without
22 *       specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37namespace Hoa\File;
38
39use Hoa\Event;
40
41/**
42 * Class \Hoa\File\Watcher.
43 *
44 * A naive file system watcher that fires three events: new, move and modify.
45 *
46 * @copyright  Copyright © 2007-2017 Hoa community
47 * @license    New BSD License
48 */
49class Watcher extends Finder implements Event\Listenable
50{
51    use Event\Listens;
52
53    /**
54     * Latency.
55     *
56     * @var int
57     */
58    protected $_latency = 1;
59
60
61
62    /**
63     * Constructor.
64     *
65     * @param   int  $latency    Latency (in seconds).
66     */
67    public function __construct($latency = null)
68    {
69        parent::__construct();
70
71        $this->setListener(
72            new Event\Listener(
73                $this,
74                [
75                    'new',
76                    'modify',
77                    'move'
78                ]
79            )
80        );
81
82        if (null !== $latency) {
83            $this->setLatency($latency);
84        }
85
86        return;
87    }
88
89    /**
90     * Run the watcher.
91     *
92     * Listenable events:
93     *     • new, when a file is new, i.e. found by the finder;
94     *     • modify, when a file has been modified;
95     *     • move, when a file has moved, i.e. no longer found by the finder.
96     *
97     * @return  void
98     */
99    public function run()
100    {
101        $iterator = $this->getIterator();
102        $previous = iterator_to_array($iterator);
103        $current  = $previous;
104
105        while (true) {
106            foreach ($current as $name => $c) {
107                if (!isset($previous[$name])) {
108                    $this->getListener()->fire(
109                        'new',
110                        new Event\Bucket([
111                            'file' => $c
112                        ])
113                    );
114
115                    continue;
116                }
117
118                if (null === $c->getHash()) {
119                    unset($current[$name]);
120
121                    continue;
122                }
123
124                if ($previous[$name]->getHash() != $c->getHash()) {
125                    $this->getListener()->fire(
126                        'modify',
127                        new Event\Bucket([
128                            'file' => $c
129                        ])
130                    );
131                }
132
133                unset($previous[$name]);
134            }
135
136            foreach ($previous as $p) {
137                $this->getListener()->fire(
138                    'move',
139                    new Event\Bucket([
140                        'file' => $p
141                    ])
142                );
143            }
144
145            usleep($this->getLatency() * 1000000);
146
147            $previous = $current;
148            $current  = iterator_to_array($iterator);
149        }
150
151        return;
152    }
153
154    /**
155     * Set latency.
156     *
157     * @param   int  $latency    Latency (in seconds).
158     * @return  int
159     */
160    public function setLatency($latency)
161    {
162        $old            = $this->_latency;
163        $this->_latency = $latency;
164
165        return $old;
166    }
167
168    /**
169     * Get latency.
170     *
171     * @return  int
172     */
173    public function getLatency()
174    {
175        return $this->_latency;
176    }
177}
178