-
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
During the initial rewrite this adapter was removed to make the rewrite easier. Since that is now in adding the ext-eio adapter will provide several high performance adapters.
- Loading branch information
1 parent
57d8f3a
commit 913b2fa
Showing
13 changed files
with
540 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?php | ||
|
||
namespace React\Filesystem\Eio; | ||
|
||
use React\EventLoop\Loop; | ||
use React\EventLoop\LoopInterface; | ||
use React\Filesystem\AdapterInterface; | ||
use React\Filesystem\ModeTypeDetector; | ||
use React\Filesystem\Node; | ||
use React\Filesystem\PollInterface; | ||
use React\Filesystem\Stat; | ||
use React\Promise\PromiseInterface; | ||
|
||
final class Adapter implements AdapterInterface | ||
{ | ||
use StatTrait; | ||
|
||
private LoopInterface $loop; | ||
private PollInterface $poll; | ||
|
||
public function __construct() | ||
{ | ||
$this->loop = Loop::get(); | ||
$this->poll = new Poll($this->loop); | ||
} | ||
|
||
public function detect(string $path): PromiseInterface | ||
{ | ||
return $this->internalStat($path)->then(function (?Stat $stat) use ($path) { | ||
if ($stat === null) { | ||
return new NotExist($this->poll, $this, $this->loop, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); | ||
} | ||
|
||
switch (ModeTypeDetector::detect($stat->mode())) { | ||
case Node\FileInterface::class: | ||
return $this->file($stat->path()); | ||
break; | ||
case Node\DirectoryInterface::class: | ||
return $this->directory($stat->path()); | ||
break; | ||
default: | ||
return new Node\Unknown($stat->path(), $stat->path()); | ||
break; | ||
} | ||
}); | ||
} | ||
|
||
public function directory(string $path): Node\DirectoryInterface | ||
{ | ||
return new Directory($this->poll, $this, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); | ||
} | ||
|
||
public function file(string $path): Node\FileInterface | ||
{ | ||
return new File($this->poll, dirname($path) . DIRECTORY_SEPARATOR, basename($path)); | ||
} | ||
|
||
protected function activate(): void | ||
{ | ||
$this->poll->activate(); | ||
} | ||
|
||
protected function deactivate(): void | ||
{ | ||
$this->poll->deactivate(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?php | ||
|
||
namespace React\Filesystem\Eio; | ||
|
||
use React\Filesystem\AdapterInterface; | ||
use React\Filesystem\Node; | ||
use React\Filesystem\PollInterface; | ||
use React\Promise\Promise; | ||
use React\Promise\PromiseInterface; | ||
use function React\Promise\all; | ||
|
||
final class Directory implements Node\DirectoryInterface | ||
{ | ||
use StatTrait; | ||
|
||
private PollInterface $poll; | ||
private AdapterInterface $filesystem; | ||
private string $path; | ||
private string $name; | ||
private int $workInProgress = 0; | ||
|
||
public function __construct(PollInterface $poll, AdapterInterface $filesystem, string $path, string $name) | ||
{ | ||
$this->poll = $poll; | ||
$this->filesystem = $filesystem; | ||
$this->path = $path; | ||
$this->name = $name; | ||
} | ||
|
||
public function stat(): PromiseInterface | ||
{ | ||
return $this->internalStat($this->path . $this->name); | ||
} | ||
|
||
public function ls(): PromiseInterface | ||
{ | ||
$this->activate(); | ||
return new Promise(function (callable $resolve): void { | ||
\eio_readdir($this->path . $this->name . DIRECTORY_SEPARATOR, \EIO_READDIR_STAT_ORDER | \EIO_READDIR_DIRS_FIRST, \EIO_PRI_DEFAULT, function ($_, $contents) use ($resolve): void { | ||
$this->deactivate(); | ||
$list = []; | ||
foreach ($contents['dents'] as $node) { | ||
$fullPath = $this->path . $this->name . DIRECTORY_SEPARATOR . $node['name']; | ||
switch ($node['type'] ?? null) { | ||
case EIO_DT_DIR: | ||
$list[] = $this->filesystem->directory($fullPath); | ||
break; | ||
case EIO_DT_REG : | ||
$list[] = $this->filesystem->file($fullPath); | ||
break; | ||
default: | ||
$list[] = $this->filesystem->detect($this->path . $this->name . DIRECTORY_SEPARATOR . $node['name']); | ||
break; | ||
} | ||
} | ||
|
||
$resolve(all($list)); | ||
}); | ||
}); | ||
} | ||
|
||
public function unlink(): PromiseInterface | ||
{ | ||
$this->activate(); | ||
return new Promise(function (callable $resolve): void { | ||
\eio_readdir($this->path . $this->name . DIRECTORY_SEPARATOR, \EIO_READDIR_STAT_ORDER | \EIO_READDIR_DIRS_FIRST, \EIO_PRI_DEFAULT, function ($_, $contents) use ($resolve): void { | ||
$this->deactivate(); | ||
if (count($contents['dents']) > 0) { | ||
$resolve(false); | ||
|
||
return; | ||
} | ||
|
||
$this->activate(); | ||
\eio_rmdir($this->path . $this->name, function () use ($resolve): void { | ||
$this->deactivate(); | ||
$resolve(true); | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
public function path(): string | ||
{ | ||
return $this->path; | ||
} | ||
|
||
public function name(): string | ||
{ | ||
return $this->name; | ||
} | ||
|
||
protected function activate(): void | ||
{ | ||
$this->poll->activate(); | ||
} | ||
|
||
protected function deactivate(): void | ||
{ | ||
$this->poll->deactivate(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
namespace React\Filesystem\Eio; | ||
|
||
/** | ||
* Singleton to make sure we always only have one file descriptor for the ext-eio event stream. | ||
* Creating more than one will invalidate the previous ones and make anything still using those fail. | ||
* | ||
* @internal | ||
*/ | ||
final class EventStream | ||
{ | ||
private static $fd = null; | ||
|
||
public static function get() | ||
{ | ||
if (self::$fd !== null) { | ||
return self::$fd; | ||
} | ||
|
||
self::$fd = eio_get_event_stream(); | ||
|
||
return self::$fd; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<?php | ||
|
||
namespace React\Filesystem\Eio; | ||
|
||
use React\Filesystem\Node\FileInterface; | ||
use React\Filesystem\PollInterface; | ||
use React\Promise\Promise; | ||
use React\Promise\PromiseInterface; | ||
|
||
final class File implements FileInterface | ||
{ | ||
use StatTrait; | ||
|
||
private PollInterface $poll; | ||
private string $path; | ||
private string $name; | ||
|
||
public function __construct(PollInterface $poll, string $path, string $name) | ||
{ | ||
$this->poll = $poll; | ||
$this->path = $path; | ||
$this->name = $name; | ||
} | ||
|
||
public function stat(): PromiseInterface | ||
{ | ||
return $this->internalStat($this->path . $this->name); | ||
} | ||
|
||
public function getContents(int $offset = 0 , ?int $maxlen = null): PromiseInterface | ||
{ | ||
$this->activate(); | ||
return new Promise(function (callable $resolve, callable $reject) use ($offset, $maxlen): void { | ||
\eio_open( | ||
$this->path . DIRECTORY_SEPARATOR . $this->name, | ||
\EIO_O_RDONLY, | ||
0, | ||
\EIO_PRI_DEFAULT, | ||
function ($_, $fileDescriptor) use ($resolve, $reject, $offset, $maxlen): void { | ||
try { | ||
\eio_fstat($fileDescriptor, \EIO_PRI_DEFAULT, function ($fileDescriptor, $stat) use ($resolve, $reject, $offset, $maxlen): void { | ||
try { | ||
\eio_read($fileDescriptor, $maxlen ?? (int)$stat['size'], $offset, \EIO_PRI_DEFAULT, function ($fileDescriptor, string $buffer) use ($resolve): void { | ||
\eio_close($fileDescriptor, \EIO_PRI_DEFAULT, function () use ($resolve, $buffer) { | ||
$this->deactivate(); | ||
$resolve($buffer); | ||
}); | ||
}, $fileDescriptor); | ||
} catch (\Throwable $error) { | ||
$this->deactivate(); | ||
$reject($error); | ||
} | ||
}, $fileDescriptor); | ||
} catch (\Throwable $error) { | ||
$this->deactivate(); | ||
$reject($error); | ||
} | ||
} | ||
); | ||
}); | ||
} | ||
|
||
public function putContents(string $contents, int $flags = 0) | ||
{ | ||
$this->activate(); | ||
return new Promise(function (callable $resolve, callable $reject) use ($contents, $flags): void { | ||
\eio_open( | ||
$this->path . DIRECTORY_SEPARATOR . $this->name, | ||
(($flags & \FILE_APPEND) == \FILE_APPEND) ? \EIO_O_RDWR | \EIO_O_APPEND : \EIO_O_RDWR | \EIO_O_CREAT, | ||
0644, | ||
\EIO_PRI_DEFAULT, | ||
function ($_, $fileDescriptor) use ($resolve, $reject, $contents, $flags): void { | ||
try { | ||
\eio_write($fileDescriptor, $contents, strlen($contents), 0, \EIO_PRI_DEFAULT, function ($fileDescriptor, int $bytesWritten) use ($resolve, $reject): void { | ||
try { | ||
\eio_close($fileDescriptor, \EIO_PRI_DEFAULT, function () use ($resolve, $bytesWritten): void { | ||
$this->deactivate(); | ||
$resolve($bytesWritten); | ||
}); | ||
} catch (\Throwable $error) { | ||
$this->deactivate(); | ||
$reject($error); | ||
} | ||
}, $fileDescriptor); | ||
} catch (\Throwable $error) { | ||
$this->deactivate(); | ||
$reject($error); | ||
} | ||
} | ||
); | ||
}); | ||
} | ||
|
||
public function unlink(): PromiseInterface | ||
{ | ||
$this->activate(); | ||
return new Promise(function (callable $resolve): void { | ||
\eio_unlink($this->path . DIRECTORY_SEPARATOR . $this->name, \EIO_PRI_DEFAULT, function () use ($resolve): void { | ||
$this->deactivate(); | ||
$resolve(true); | ||
}); | ||
}); | ||
} | ||
|
||
public function path(): string | ||
{ | ||
return $this->path; | ||
} | ||
|
||
public function name(): string | ||
{ | ||
return $this->name; | ||
} | ||
|
||
protected function activate(): void | ||
{ | ||
$this->poll->activate(); | ||
} | ||
|
||
protected function deactivate(): void | ||
{ | ||
$this->poll->deactivate(); | ||
} | ||
} |
Oops, something went wrong.