Completed
Push — stable2 ( 10fadc...4d0e89 )
by Robin
07:41
created

NotifyHandler   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 95.56%

Importance

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

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