Completed
Push — stable2 ( 929455...10fadc )
by Robin
13:53 queued 12:28
created

NotifyHandler   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 0%

Importance

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

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getChanges() 0 13 3
A listen() 0 11 3
A parseChangeLine() 0 12 3
A checkForError() 0 6 2
A stop() 0 4 1
A __destruct() 0 3 1
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
	public function __construct(Connection $connection, $path) {
38
		$this->connection = $connection;
39
		$this->path = $path;
40
	}
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
	public function getChanges() {
48
		if (!$this->listening) {
49
			return [];
50
		}
51
		stream_set_blocking($this->connection->getOutputStream(), 0);
52
		$lines = [];
53
		while (($line = $this->connection->readLine())) {
54
			$this->checkForError($line);
55
			$lines[] = $line;
56
		}
57
		stream_set_blocking($this->connection->getOutputStream(), 1);
58
		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
	public function listen($callback) {
69
		if ($this->listening) {
70
			$this->connection->read(function ($line) use ($callback) {
71
				$this->checkForError($line);
72
				$change = $this->parseChangeLine($line);
73
				if ($change) {
74
					return $callback($change);
75
				}
76
			});
77
		}
78
	}
79
80
	private function parseChangeLine($line) {
81
		$code = (int)substr($line, 0, 4);
82
		if ($code === 0) {
83
			return null;
84
		}
85
		$subPath = str_replace('\\', '/', substr($line, 5));
86
		if ($this->path === '') {
87
			return new Change($code, $subPath);
88
		} else {
89
			return new Change($code, $this->path . '/' . $subPath);
90
		}
91
	}
92
93
	private function checkForError($line) {
94
		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
	}
99
100
	public function stop() {
101
		$this->listening = false;
102
		$this->connection->close();
103
	}
104
105
	public function __destruct() {
106
		$this->stop();
107
	}
108
}
109