Completed
Push — master ( 669135...206d6a )
by Robin
03:18
created

NotifyHandler::checkForError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
ccs 3
cts 5
cp 0.6
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2.2559
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Robin Appelman <[email protected]>
4
 * This file is licensed under the Licensed under the MIT license:
5
 * http://opensource.org/licenses/MIT
6
 *
7
 */
8
9
namespace Icewind\SMB;
10
11
12
use Icewind\SMB\Exception\Exception;
13
14
class NotifyHandler implements INotifyHandler {
15
	/**
16
	 * @var Connection
17
	 */
18
	private $connection;
19
20
	/**
21
	 * @var string
22
	 */
23
	private $path;
24
25
	private $listening = true;
26
27
	// todo replace with static once <5.6 support is dropped
28
	// see error.h
29
	private static $exceptionMap = [
30
		ErrorCodes::RevisionMismatch => '\Icewind\SMB\Exception\RevisionMismatchException',
31
	];
32
33
	/**
34
	 * @param Connection $connection
35
	 * @param string $path
36
	 */
37 10
	public function __construct(Connection $connection, $path) {
38 10
		$this->connection = $connection;
39 10
		$this->path = $path;
40 10
	}
41
42
	/**
43
	 * Get all changes detected since the start of the notify process or the last call to getChanges
44
	 *
45
	 * @return Change[]
46
	 */
47 8
	public function getChanges() {
48 8
		if (!$this->listening) {
49 2
			return [];
50
		}
51 6
		stream_set_blocking($this->connection->getOutputStream(), 0);
52 6
		$lines = [];
53 6
		while (($line = $this->connection->readLine())) {
54 6
			$this->checkForError($line);
55 6
			$lines[] = $line;
56 6
		}
57 6
		stream_set_blocking($this->connection->getOutputStream(), 1);
58 6
		return array_values(array_filter(array_map([$this, 'parseChangeLine'], $lines)));
59
	}
60
61
	/**
62
	 * Listen actively to all incoming changes
63
	 *
64
	 * Note that this is a blocking process and will cause the process to block forever if not explicitly terminated
65
	 *
66
	 * @param callable $callback
67
	 */
68 4
	public function listen($callback) {
69 4
		if ($this->listening) {
70 4
			$this->connection->read(function ($line) use ($callback) {
71 4
				$this->checkForError($line);
72 4
				$change = $this->parseChangeLine($line);
73 4
				if ($change) {
74 4
					return $callback($change);
75
				}
76 4
			});
77 4
		}
78 4
	}
79
80 8
	private function parseChangeLine($line) {
81 8
		$code = (int)substr($line, 0, 4);
82 8
		if ($code === 0) {
83 6
			return null;
84
		}
85 8
		$subPath = str_replace('\\', '/', substr($line, 5));
86 8
		if ($this->path === '') {
87 6
			return new Change($code, $subPath);
88
		} else {
89 2
			return new Change($code, $this->path . '/' . $subPath);
90
		}
91
	}
92
93 8
	private function checkForError($line) {
94 8
		if (substr($line, 0, 16) === 'notify returned ') {
95
			$error = substr($line, 16);
96
			throw Exception::fromMap(self::$exceptionMap, $error, 'Notify is not supported with the used smb version');
97
		}
98 8
	}
99
100 10
	public function stop() {
101 10
		$this->listening = false;
102 10
		$this->connection->close();
103 10
	}
104
105 10
	public function __destruct() {
106 10
		$this->stop();
107 10
	}
108
}
109