Completed
Push — master ( afaf42...8ac772 )
by Raffael
20:10 queued 16:21
created

SmbListener::notify()   B

Complexity

Conditions 9
Paths 14

Size

Total Lines 43

Duplication

Lines 14
Ratio 32.56 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 14
loc 43
ccs 0
cts 35
cp 0
rs 7.6764
c 0
b 0
f 0
cc 9
nc 14
nop 4
crap 90
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\Async;
13
14
use Balloon\Filesystem\Node\Collection;
15
use Balloon\Filesystem\Node\NodeInterface;
16
use Balloon\Filesystem\Storage\Adapter\Blackhole;
17
use Balloon\Filesystem\Storage\Adapter\Smb;
18
use Balloon\Helper;
19
use Balloon\Server;
20
use Icewind\SMB\INotifyHandler;
21
use Icewind\SMB\IShare;
22
use Psr\Log\LoggerInterface;
23
use TaskScheduler\AbstractJob;
24
use TaskScheduler\Process;
25
use TaskScheduler\Scheduler;
26
27
class SmbListener extends AbstractJob
28
{
29
    /**
30
     * Server.
31
     *
32
     * @var Server
33
     */
34
    protected $server;
35
36
    /**
37
     * Scheduler.
38
     *
39
     * @var Scheduler
40
     */
41
    protected $scheduler;
42
43
    /**
44
     * Logger.
45
     *
46
     * @var LoggerInterface
47
     */
48
    protected $logger;
49
50
    /**
51
     * Constructor.
52
     */
53
    public function __construct(Server $server, Scheduler $scheduler, LoggerInterface $logger)
54
    {
55
        $this->server = $server;
56
        $this->scheduler = $scheduler;
57
        $this->logger = $logger;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function start(): bool
64
    {
65
        $dummy = new Blackhole();
66
        $fs = $this->server->getFilesystem();
67
        $collection = $fs->findNodeById($this->data['id']);
68
        $user_fs = $this->server->getUserById($collection->getOwner())->getFilesystem();
69
        $smb = $collection->getStorage();
70
        $share = $smb->getShare();
71
72
        $collection
73
            ->setFilesystem($user_fs)
74
            ->setStorage($dummy);
75
76
        $this->notify($collection, $share, $dummy, $smb);
77
78
        return true;
79
    }
80
81
    /**
82
     * Bind to smb changes.
83
     */
84
    protected function notify(Collection $mount, IShare $share, Blackhole $dummy, Smb $smb): void
85
    {
86
        $last = null;
87
        $that = $this;
0 ignored issues
show
Unused Code introduced by
$that is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
88
        $logger = $this->logger;
89
        $root = $smb->getRoot();
90
        $system = ($root === '') ? $smb->getSystemFolder() : $root.DIRECTORY_SEPARATOR.$smb->getSystemFolder();
91
92
        $notify = $share->notify('');
93
94
        while (true) {
95
            foreach ($notify->getChanges() as $change) {
96
                $logger->debug('smb mount ['.$mount->getId().'] notify event in ['.$change->getCode().'] for path ['.$change->getPath().']', [
97
                    'category' => get_class($this),
98
                ]);
99
100 View Code Duplication
                if (substr($change->getPath(), 0, strlen($root)) !== $root) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
101
                    $logger->debug('skip smb event ['.$change->getPath().'], path is not part of root ['.$root.']', [
102
                        'category' => get_class($this),
103
                    ]);
104
105
                    continue;
106
                }
107 View Code Duplication
                if (substr($change->getPath(), 0, strlen($system)) === $system) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
                    $logger->debug('skip smb event ['.$change->getPath().'], path is part of balloon system folder ['.$system.']', [
109
                        'category' => get_class($this),
110
                    ]);
111
112
                    continue;
113
                }
114
115
                if ($change->getCode() === INotifyHandler::NOTIFY_RENAMED_OLD) {
116
                    //do nothing
117
                } elseif ($change->getCode() === INotifyHandler::NOTIFY_RENAMED_NEW && $last->getCode() === INotifyHandler::NOTIFY_RENAMED_OLD) {
118
                    $this->renameNode($mount, $dummy, $last->getPath(), $change->getPath());
119
                } else {
120
                    $this->syncNode($mount, $change->getPath(), $change->getCode());
121
                }
122
123
                $last = $change;
124
            }
125
        }
126
    }
127
128
    /**
129
     * Get parent node from sub path.
130
     */
131
    protected function getNode(Collection $mount, string $path): NodeInterface
132
    {
133
        $nodes = explode(DIRECTORY_SEPARATOR, $path);
134
        foreach ($nodes as $child) {
135
            $mount = $mount->getChild($child);
136
        }
137
138
        return $mount;
139
    }
140
141
    /**
142
     * Rename node.
143
     */
144
    protected function renameNode(Collection $mount, Blackhole $dummy, string $from, string $to): bool
145
    {
146
        try {
147
            $this->logger->debug('rename smb node from ['.$from.'] to ['.$to.'] in mount ['.$mount->getId().']', [
148
                'category' => get_class($this),
149
            ]);
150
151
            $node = $this->getNode($mount, $from);
152
            $node->getParent()->setStorage($dummy);
153
154
            if (Helper::mb_basename($from) !== Helper::mb_basename($to)) {
155
                $node->setName(Helper::mb_basename($to));
156
            }
157
158
            return true;
159
        } catch (\Exception $e) {
160
            $this->logger->error('failed to handle smb rename event from ['.$from.'] to ['.$to.'] in mount ['.$mount->getId().']', [
161
                'category' => get_class($this),
162
                'exception' => $e,
163
            ]);
164
        }
165
166
        return false;
167
    }
168
169
    /**
170
     * Add sync task.
171
     */
172
    protected function syncNode(Collection $mount, string $path, int $action): Process
173
    {
174
        $this->logger->debug('add new smb sync job for path ['.$path.'] in mount ['.$mount->getId().']', [
175
            'category' => get_class($this),
176
        ]);
177
178
        return $this->scheduler->addJob(SmbScanner::class, [
179
            'id' => $mount->getId(),
180
            'path' => $path,
181
            'action' => $action,
182
            'recursive' => true,
183
        ]);
184
    }
185
}
186