Completed
Push — master ( 89f47c...f4d8bc )
by Robin
03:18
created

NotifyHandler   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 94
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 91.11%

Importance

Changes 0
Metric Value
wmc 14
c 0
b 0
f 0
lcom 1
cbo 3
dl 0
loc 94
ccs 41
cts 45
cp 0.9111
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A parseChangeLine() 0 12 3
A checkForError() 0 6 2
A stop() 0 4 1
A __destruct() 0 3 1
A getChanges() 0 13 3
A listen() 0 11 3
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\Wrapped;
10
11
12
use Icewind\SMB\Change;
13
use Icewind\SMB\Exception\Exception;
14
use Icewind\SMB\Exception\RevisionMismatchException;
15
use Icewind\SMB\INotifyHandler;
16
17
class NotifyHandler implements INotifyHandler {
18
	/**
19
	 * @var Connection
20
	 */
21
	private $connection;
22
23
	/**
24
	 * @var string
25
	 */
26
	private $path;
27
28
	private $listening = true;
29
30
	// see error.h
31
	const EXCEPTION_MAP = [
32
		ErrorCodes::RevisionMismatch => RevisionMismatchException::class,
33
	];
34
35
	/**
36
	 * @param Connection $connection
37
	 * @param string $path
38
	 */
39 10
	public function __construct(Connection $connection, $path) {
40 10
		$this->connection = $connection;
41 10
		$this->path = $path;
42 10
	}
43
44
	/**
45
	 * Get all changes detected since the start of the notify process or the last call to getChanges
46
	 *
47
	 * @return Change[]
48
	 */
49 8
	public function getChanges() {
50 8
		if (!$this->listening) {
51 2
			return [];
52
		}
53 6
		stream_set_blocking($this->connection->getOutputStream(), 0);
54 6
		$lines = [];
55 6
		while (($line = $this->connection->readLine())) {
56 6
			$this->checkForError($line);
57 6
			$lines[] = $line;
58
		}
59 6
		stream_set_blocking($this->connection->getOutputStream(), 1);
60 6
		return array_values(array_filter(array_map([$this, 'parseChangeLine'], $lines)));
61
	}
62
63
	/**
64
	 * Listen actively to all incoming changes
65
	 *
66
	 * Note that this is a blocking process and will cause the process to block forever if not explicitly terminated
67
	 *
68
	 * @param callable $callback
69
	 */
70 4
	public function listen($callback) {
71 4
		if ($this->listening) {
72 4
			$this->connection->read(function ($line) use ($callback) {
73 4
				$this->checkForError($line);
74 4
				$change = $this->parseChangeLine($line);
75 4
				if ($change) {
76 4
					return $callback($change);
77
				}
78 4
			});
79
		}
80 4
	}
81
82 8
	private function parseChangeLine($line) {
83 8
		$code = (int)substr($line, 0, 4);
84 8
		if ($code === 0) {
85 6
			return null;
86
		}
87 8
		$subPath = str_replace('\\', '/', substr($line, 5));
88 8
		if ($this->path === '') {
89 6
			return new Change($code, $subPath);
90
		} else {
91 2
			return new Change($code, $this->path . '/' . $subPath);
92
		}
93
	}
94
95 8
	private function checkForError($line) {
96 8
		if (substr($line, 0, 16) === 'notify returned ') {
97
			$error = substr($line, 16);
98
			throw Exception::fromMap(array_merge(self::EXCEPTION_MAP, Parser::EXCEPTION_MAP), $error, 'Notify is not supported with the used smb version');
99
		}
100 8
	}
101
102 10
	public function stop() {
103 10
		$this->listening = false;
104 10
		$this->connection->close();
105 10
	}
106
107 10
	public function __destruct() {
108 10
		$this->stop();
109 10
	}
110
}
111