Skip to content

Commit

Permalink
Merge pull request #62 from CharlotteDunoisLabs/file-put-get-rocket
Browse files Browse the repository at this point in the history
Add Adapter::getContents & Adapter::putContents
  • Loading branch information
WyriHaximus authored Apr 10, 2019
2 parents 36f25ca + 00ed432 commit 71a6514
Show file tree
Hide file tree
Showing 11 changed files with 311 additions and 19 deletions.
42 changes: 42 additions & 0 deletions src/AdapterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,48 @@ public function write($fileDescriptor, $data, $length, $offset);
*/
public function close($fd);

/**
* Reads the entire file.
*
* This is an optimization for adapters which can optimize
* the open -> (seek ->) read -> close sequence into one call.
*
* @param string $path
* @param int $offset
* @param int|null $length
* @return PromiseInterface
*/
public function getContents($path, $offset = 0, $length = null);

/**
* Writes the given content to the specified file.
* If the file exists, the file is truncated.
* If the file does not exist, the file will be created.
*
* This is an optimization for adapters which can optimize
* the open -> write -> close sequence into one call.
*
* @param string $path
* @param string $content
* @return PromiseInterface
* @see AdapterInterface::appendContents()
*/
public function putContents($path, $content);

/**
* Appends the given content to the specified file.
* If the file does not exist, the file will be created.
*
* This is an optimization for adapters which can optimize
* the open -> write -> close sequence into one call.
*
* @param string $path
* @param string $content
* @return PromiseInterface
* @see AdapterInterface::putContents()
*/
public function appendContents($path, $content);

/**
* Rename a node.
*
Expand Down
76 changes: 75 additions & 1 deletion src/ChildProcess/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DateTime;
use Exception;
use Throwable;
use React\EventLoop\LoopInterface;
use React\Filesystem\ObjectStream;
use React\Filesystem\ObjectStreamSink;
Expand Down Expand Up @@ -181,6 +182,10 @@ public function callFilesystem($function, $args, $errorResultCode = -1)
return $this->pool->rpc(Factory::rpc($function, $args))->then(function (Payload $payload) {
return \React\Promise\resolve($payload->getPayload());
}, function ($payload) {
if ($payload instanceof Throwable) {
return \React\Promise\reject($payload);
}

return \React\Promise\reject(new Exception($payload['error']['message']));
});
}
Expand Down Expand Up @@ -280,7 +285,76 @@ public function close($fd)
return $fileDescriptor->softTerminate();
});
}


/**
* Reads the entire file.
*
* This is an optimization for adapters which can optimize
* the open -> (seek ->) read -> close sequence into one call.
*
* @param string $path
* @param int $offset
* @param int|null $length
* @return PromiseInterface
*/
public function getContents($path, $offset = 0, $length = null)
{
return $this->invoker->invokeCall('getContents', [
'path' => $path,
'offset' => $offset,
'maxlen' => $length,
])->then(function ($payload) {
return \React\Promise\resolve(base64_decode($payload['chunk']));
});
}

/**
* Writes the given content to the specified file.
* If the file exists, the file is truncated.
* If the file does not exist, the file will be created.
*
* This is an optimization for adapters which can optimize
* the open -> write -> close sequence into one call.
*
* @param string $path
* @param string $content
* @return PromiseInterface
* @see AdapterInterface::appendContents()
*/
public function putContents($path, $content)
{
return $this->invoker->invokeCall('putContents', [
'path' => $path,
'chunk' => base64_encode($content),
'flags' => 0,
])->then(function ($payload) {
return \React\Promise\resolve($payload['written']);
});
}

/**
* Appends the given content to the specified file.
* If the file does not exist, the file will be created.
*
* This is an optimization for adapters which can optimize
* the open -> write -> close sequence into one call.
*
* @param string $path
* @param string $content
* @return PromiseInterface
* @see AdapterInterface::putContents()
*/
public function appendContents($path, $content)
{
return $this->invoker->invokeCall('putContents', [
'path' => $path,
'chunk' => base64_encode($content),
'flags' => FILE_APPEND,
])->then(function ($payload) {
return \React\Promise\resolve($payload['written']);
});
}

/**
* @param string $path
* @return PromiseInterface
Expand Down
30 changes: 30 additions & 0 deletions src/ChildProcess/Process.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public function __construct(Messenger $messenger)
'read',
'write',
'close',
'getContents',
'putContents',
'rename',
'readlink',
'symlink',
Expand Down Expand Up @@ -247,6 +249,34 @@ public function close(array $payload)
]);
}

/**
* @param array $payload
* @return PromiseInterface
*/
public function getContents(array $payload)
{
if ($payload['maxlen'] > 0) {
$chunk = file_get_contents($payload['path'], false, null, $payload['offset'], $payload['maxlen']);
} else {
$chunk = file_get_contents($payload['path'], false, null, $payload['offset']);
}

return \React\Promise\resolve([
'chunk' => base64_encode($chunk),
]);
}

/**
* @param array $payload
* @return PromiseInterface
*/
public function putContents(array $payload)
{
return \React\Promise\resolve([
'written' => file_put_contents($payload['path'], base64_decode($payload['chunk']), $payload['flags']),
]);
}

/**
* @param array $payload
* @return PromiseInterface
Expand Down
69 changes: 69 additions & 0 deletions src/Eio/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,75 @@ public function close($fd)
});
}

/**
* Reads the entire file.
*
* This is an optimization for adapters which can optimize
* the open -> (seek ->) read -> close sequence into one call.
*
* @param string $path
* @param int $offset
* @param int|null $length
* @return PromiseInterface
*/
public function getContents($path, $offset = 0, $length = null)
{
if ($length === null) {
return $this->stat($path)->then(function ($stat) use ($path, $offset) {
return $this->getContents($path, $offset, $stat['size']);
});
}

return $this->open($path, 'r')->then(function ($fd) use ($offset, $length) {
return $this->read($fd, $length, $offset)->always(function () use ($fd) {
return $this->close($fd);
});
});
}

/**
* Writes the given content to the specified file.
* If the file exists, the file is truncated.
* If the file does not exist, the file will be created.
*
* This is an optimization for adapters which can optimize
* the open -> write -> close sequence into one call.
*
* @param string $path
* @param string $content
* @return PromiseInterface
* @see AdapterInterface::appendContents()
*/
public function putContents($path, $content)
{
return $this->open($path, 'cw')->then(function ($fd) use ($content) {
return $this->write($fd, $content, strlen($content), 0)->always(function () use ($fd) {
return $this->close($fd);
});
});
}

/**
* Appends the given content to the specified file.
* If the file does not exist, the file will be created.
*
* This is an optimization for adapters which can optimize
* the open -> write -> close sequence into one call.
*
* @param string $path
* @param string $content
* @return PromiseInterface
* @see AdapterInterface::putContents()
*/
public function appendContents($path, $content)
{
return $this->open($path, 'cwa')->then(function ($fd) use ($content) {
return $this->write($fd, $content, strlen($content), 0)->always(function () use ($fd) {
return $this->close($fd);
});
});
}

/**
* {@inheritDoc}
*/
Expand Down
9 changes: 0 additions & 9 deletions tests/Adapters/AbstractAdaptersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,6 @@ protected function getEioProvider(callable $loopFactory)
];
}

protected function getPthreadsProvider(callable $loopFactory)
{
$loop = $loopFactory();
return [
$loop,
new Pthreads\Adapter($loop),
];
}

protected function getFacoryProvider(callable $loopFactory)
{
$loop = $loopFactory();
Expand Down
3 changes: 0 additions & 3 deletions tests/Adapters/DirectoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
namespace React\Tests\Filesystem\Adapters;

use React\EventLoop\LoopInterface;
use React\Filesystem\ChildProcess;
use React\Filesystem\Eio;
use React\Filesystem\FilesystemInterface;
use React\Filesystem\Pthreads;

/**
* @group adapters
Expand Down
3 changes: 0 additions & 3 deletions tests/Adapters/FileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
namespace React\Tests\Filesystem\Adapters;

use React\EventLoop\LoopInterface;
use React\Filesystem\ChildProcess;
use React\Filesystem\Eio;
use React\Filesystem\FilesystemInterface;
use React\Filesystem\Pthreads;

/**
* @group adapters
Expand Down
3 changes: 0 additions & 3 deletions tests/Adapters/InterfaceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

use React\EventLoop\LoopInterface;
use React\Filesystem\AdapterInterface;
use React\Filesystem\ChildProcess;
use React\Filesystem\Eio;
use React\Filesystem\Pthreads;

class InterfaceTest extends AbstractAdaptersTest
{
Expand Down
46 changes: 46 additions & 0 deletions tests/ChildProcess/AdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,4 +416,50 @@ public function testErrorFromPool()
]);
$this->await($adapter->touch('foo.bar'), $loop, 1);
}

public function testGetContents()
{
$loop = \React\EventLoop\Factory::create();
$adapter = new Adapter($loop);

$contents = $this->await($adapter->getContents(__FILE__), $loop);
$this->assertSame(file_get_contents(__FILE__), $contents);
}

public function testGetContentsMinMax()
{
$loop = \React\EventLoop\Factory::create();
$adapter = new Adapter($loop);

$contents = $this->await($adapter->getContents(__FILE__, 5, 10), $loop);
$this->assertSame(file_get_contents(__FILE__, false, null, 5, 10), $contents);
}

public function testPutContents()
{
$loop = \React\EventLoop\Factory::create();
$adapter = new Adapter($loop);

$tempFile = $this->tmpDir . uniqid('', true);
$contents = sha1_file(__FILE__);

$this->await($adapter->putContents($tempFile, $contents), $loop);
$this->assertSame($contents, file_get_contents($tempFile));
}

public function testAppendContents()
{
$loop = \React\EventLoop\Factory::create();
$adapter = new Adapter($loop);

$tempFile = $this->tmpDir . uniqid('', true);
$contents = sha1_file(__FILE__);

file_put_contents($tempFile, $contents);
$time = sha1(time());
$contents .= $time;

$this->await($adapter->appendContents($tempFile, $time, FILE_APPEND), $loop);
$this->assertSame($contents, file_get_contents($tempFile));
}
}
Loading

0 comments on commit 71a6514

Please sign in to comment.