Completed
Push — master ( da5b20...773556 )
by Kamil
03:06
created

DriverEio::unlink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Dazzle\Filesystem\Driver;
4
5
use Dazzle\Filesystem\Driver\Flag\FlagResolverInterface;
6
use Dazzle\Filesystem\Invoker\InvokerInterface;
7
use Dazzle\Filesystem\Invoker\InvokerStandard;
8
use Dazzle\Loop\LoopInterface;
9
use Dazzle\Promise\Promise;
10
use Dazzle\Promise\PromiseInterface;
11
use Dazzle\Throwable\Exception\Runtime\ExecutionException;
12
use DateTimeImmutable;
13
14
class DriverEio extends DriverAbstract implements DriverInterface
15
{
16
    /**
17
     * @var array
18
     */
19
    protected $options;
20
21
    /**
22
     * @var InvokerInterface
23
     */
24
    protected $invoker;
25
26
    /**
27
     * @var resource
28
     */
29
    protected $stream;
30
31
    /**
32
     * @var bool
33
     */
34
    protected $active = false;
35
36
    /**
37
     * @var FlagResolverInterface
38
     */
39
    protected $flagPermission;
40
41
    /**
42
     * @var FlagResolverInterface
43
     */
44
    protected $flagOpen;
45
46
    /**
47
     * @param LoopInterface $loop
48
     * @param array $options
49
     */
50
    public function __construct(LoopInterface $loop, $options = [])
51
    {
52
        eio_init();
53
        $this->loop = $loop;
54
        $this->options = $this->createConfiguration($options);
55
        $this->invoker = $this->createInvoker();
56
        $this->stream = eio_get_event_stream();
57
        $this->flagPermission = $this->createFlagPermissionResolver();
58
        $this->flagOpen = $this->createFlagOpenResolver();
59
    }
60
61
    /**
62
     * @override
63
     * @inheritDoc
64
     */
65
    public function access($path, $mode = 0755)
66
    {
67
        // TODO
68
    }
69
70
    /**
71
     * @override
72
     * @inheritDoc
73
     */
74
    public function append($path, $data = '')
75
    {
76
        // TODO
77
    }
78
79
    /**
80
     * @override
81
     * @inheritDoc
82
     */
83
    public function chmod($path, $mode)
84
    {
85
        return $this->invoker->call('eio_chmod', [ $this->getPath($path), decoct($mode) ])
86
            ->then([ $this, 'handleChmod' ]);
87
    }
88
89
    /**
90
     * @override
91
     * @inheritDoc
92
     */
93
    public function chown($path, $uid = -1, $gid = -1)
94
    {
95
        return $this->invoker->call('eio_chown', [ $this->getPath($path), $uid, $gid ])
96
            ->then([ $this, 'handleChown' ]);
97
    }
98
99
    /**
100
     * @override
101
     * @inheritDoc
102
     */
103
    public function exists($path)
104
    {
105
        return $this->stat($path)
106
            ->then(
107
                function() { return true; },
108
                function() { return false; }
109
            );
110
    }
111
112
    /**
113
     * @override
114
     * @inheritDoc
115
     */
116
    public function link($srcPath, $dstPath)
117
    {
118
        return $this->invoker->call('eio_link', [ $this->getPath($srcPath), $this->getPath($dstPath) ]);
119
    }
120
121
    /**
122
     * @override
123
     * @inheritDoc
124
     */
125
    public function ls($path)
126
    {
127
        // TODO
128
    }
129
130
    /**
131
     * @override
132
     * @inheritDoc
133
     */
134
    public function mkdir($path, $mode = 0755)
135
    {
136
        return $this->invoker->call('eio_mkdir', [ $this->getPath($path), $this->flagPermission->resolve($mode) ]);
137
    }
138
139
    /**
140
     * @override
141
     * @inheritDoc
142
     */
143
    public function prepend($path, $data = '')
144
    {
145
        // TODO
146
    }
147
148
    /**
149
     * @override
150
     * @inheritDoc
151
     */
152
    public function readlink($path)
153
    {
154
        return $this->invoker->call('eio_readlink', [ $this->getPath($path) ]);
155
    }
156
157
    /**
158
     * @override
159
     * @inheritDoc
160
     */
161
    public function realpath($path)
162
    {
163
        return $this->invoker->call('eio_realpath', [ $this->getPath($path) ]);
164
    }
165
166
    /**
167
     * @override
168
     * @inheritDoc
169
     */
170
    public function rename($srcPath, $dstPath)
171
    {
172
        return $this->invoker->call('eio_rename', [ $this->getPath($srcPath), $this->getPath($dstPath) ]);
173
    }
174
175
    /**
176
     * @override
177
     * @inheritDoc
178
     */
179
    public function rmdir($path)
180
    {
181
        return $this->invoker->call('eio_rmdir', [ $this->getPath($path) ]);
182
    }
183
184
    /**
185
     * @override
186
     * @inheritDoc
187
     */
188
    public function stat($path)
189
    {
190
        return $this->invoker->call('eio_lstat', [ $this->getPath($path) ])
191 View Code Duplication
            ->then(function($info) {
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...
192
                if ($info)
193
                {
194
                    $info['atime'] && $info['atime'] = new DateTimeImmutable('@' . $info['atime']);
195
                    $info['mtime'] && $info['mtime'] = new DateTimeImmutable('@' . $info['mtime']);
196
                    $info['ctime'] && $info['ctime'] = new DateTimeImmutable('@' . $info['ctime']);
197
                }
198
                return $info;
199
            });
200
    }
201
202
    /**
203
     * @override
204
     * @inheritDoc
205
     */
206
    public function symlink($srcPath, $dstPath)
207
    {
208
        return $this->invoker->call('eio_symlink', [ $this->getPath($srcPath), $this->getPath($dstPath) ]);
209
    }
210
211
    /**
212
     * @override
213
     * @inheritDoc
214
     */
215
    public function truncate($path, $len = 0)
216
    {
217
        return $this->invoker->call('eio_truncate', [ $this->getPath($path), $len ]);
218
    }
219
220
    /**
221
     * @override
222
     * @inheritDoc
223
     */
224
    public function unlink($path)
225
    {
226
        return $this->invoker->call('eio_unlink', [ $this->getPath($path) ]);
227
    }
228
229
    /**
230
     * @internal
231
     * @override
232
     * @inheritDoc
233
     */
234
    public function call($func, $args = [])
235
    {
236
        $loop = $this->loop;
237
238
        if ($loop->isRunning())
239
        {
240
            return $this->callDelayed($func, $args);
241
        }
242
243
        $promise = new Promise();
244
        $loop->onTick(function() use($func, $args, $promise) {
245
            $this
246
                ->callDelayed($func, $args)
247
                ->then(function($result) use($promise) {
248
                    return $promise->resolve($result);
249
                })
250
                ->failure(function($ex) use($promise) {
251
                    return $promise->reject($ex);
252
                });
253
        });
254
255
        return $promise;
256
    }
257
258
    /**
259
     * @param string $func
260
     * @param array $args
261
     * @return PromiseInterface
0 ignored issues
show
Documentation introduced by
Should the return type not be PromiseInterface|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
262
     */
263
    protected function callDelayed($func, $args = [])
264
    {
265
        $this->register();
266
267
        $promise = new Promise();
268
269
        $args[] = EIO_PRI_DEFAULT;
270
        $args[] = function($data, $result, $req) use($func, $args, $promise) {
271
272
            if ($result == -1)
273
            {
274
                $ex = new ExecutionException(@eio_get_last_error($req));
275
                $ex->setContext($args);
276
                return $promise->reject($ex);
277
            }
278
279
            return $promise->resolve($result);
280
        };
281
282
        if (!$func(...$args))
283
        {
284
            $name = is_string($func) ? $func : get_class($func);
285
            $ex = new ExecutionException('Unknown error in response for "' . $name . '"');
286
            $ex->setContext($args);
287
            return $promise->reject($ex);
288
        };
289
290
        return $promise;
291
    }
292
293
    protected function register()
294
    {
295
        if ($this->active) {
296
            return;
297
        }
298
299
        $this->active = true;
300
        $this->loop->addReadStream($this->stream, [ $this, 'handleEvent' ]);
301
    }
302
303
    protected function unregister()
304
    {
305
        if (!$this->active) {
306
            return;
307
        }
308
309
        $this->active = false;
310
        $this->loop->removeReadStream($this->stream);
311
    }
312
313
    public function handleEvent()
314
    {
315
        if ($this->workPendingCount() == 0)
316
        {
317
            return;
318
        }
319
320
        while (eio_npending())
321
        {
322
            eio_poll();
323
        }
324
325
        if ($this->workPendingCount() == 0)
326
        {
327
            $this->unregister();
328
        }
329
    }
330
331
    public function workPendingCount()
332
    {
333
        return eio_nreqs() + eio_npending() + eio_nready();
334
    }
335
336
    /**
337
     * Get path.
338
     *
339
     * @param string $path
340
     * @return string
341
     */
342
    protected function getPath($path)
343
    {
344
        return $this->options['root'] . '/' . ltrim($path, '/');
345
    }
346
347
    /**
348
     * Create valid configuration for the driver.
349
     *
350
     * @param array $options
351
     * @return array
352
     */
353
    protected function createConfiguration($options = [])
354
    {
355
        return array_merge([
356
            'root' => '',
357
            'invoker.class' => InvokerStandard::class,
358
        ], $options);
359
    }
360
361
    /**
362
     * Create invoker for the driver.
363
     *
364
     * @return InvokerInterface
365
     */
366 View Code Duplication
    protected function createInvoker()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
367
    {
368
        $invoker = class_exists($this->options['invoker.class'])
369
            ? $this->options['invoker.class']
370
            : InvokerStandard::class
371
        ;
372
        return new $invoker($this);
373
    }
374
}
375