PHP: php server commit 2/n, add Server Call (#25397)

* php server commit 2, server call

* re-run generate_projects.sh

* temp solution to avoid using autoload

* remove type-hint of
pull/25531/merge
Hannah Shi 4 years ago committed by GitHub
parent fbc5194df6
commit 061fcbb214
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      src/php/lib/Grpc/ServerCallReader.php
  2. 101
      src/php/lib/Grpc/ServerCallWriter.php
  3. 268
      src/php/tests/unit_tests/ServerCallTest.php
  4. 2
      tools/doxygen/Doxyfile.php

@ -0,0 +1,52 @@
<?php
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace Grpc;
/**
* This is an experimental and incomplete implementation of gRPC server
* for PHP. APIs are _definitely_ going to be changed.
*
* DO NOT USE in production.
*/
class ServerCallReader
{
public function __construct($call, string $request_type)
{
$this->call_ = $call;
$this->request_type_ = $request_type;
}
public function read()
{
$event = $this->call_->startBatch([
OP_RECV_MESSAGE => true,
]);
if ($event->message === null) {
return null;
}
$data = new $this->request_type_;
$data->mergeFromString($event->message);
return $data;
}
private $call_;
private $request_type_;
}

@ -0,0 +1,101 @@
<?php
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
namespace Grpc;
/**
* This is an experimental and incomplete implementation of gRPC server
* for PHP. APIs are _definitely_ going to be changed.
*
* DO NOT USE in production.
*/
class ServerCallWriter
{
public function __construct($call)
{
$this->call_ = $call;
}
public function start(
array $initialMetadata,
$data = null,
array $options = []
) {
$batch = [];
$this->addSendInitialMetadataOpIfNotSent($batch, $initialMetadata);
$this->addSendMessageOpIfHasData($batch, $data, $options);
$this->call_->startBatch($batch);
}
public function write(
$data,
array $options = [],
array $initialMetadata = null
) {
$batch = [];
$this->addSendInitialMetadataOpIfNotSent($batch, $initialMetadata);
$this->addSendMessageOpIfHasData($batch, $data, $options);
$this->call_->startBatch($batch);
}
public function finish(
array $status = null,
array $initialMetadata = null,
$data = null,
array $options = []
) {
$batch = [
OP_SEND_STATUS_FROM_SERVER => $status ?? Status::ok(),
OP_RECV_CLOSE_ON_SERVER => true,
];
$this->addSendInitialMetadataOpIfNotSent($batch, $initialMetadata);
$this->addSendMessageOpIfHasData($batch, $data, $options);
$this->call_->startBatch($batch);
}
////////////////////////////
private function addSendInitialMetadataOpIfNotSent(
array &$batch,
array $initialMetadata = null
) {
if (!$this->initialMetadataSent_) {
$batch[OP_SEND_INITIAL_METADATA] = $initialMetadata ?? [];
$this->initialMetadataSent_ = true;
}
}
private function addSendMessageOpIfHasData(
array &$batch,
$data = null,
array $options = []
) {
if ($data) {
$message_array = ['message' => $data->serializeToString()];
if (array_key_exists('flags', $options)) {
$message_array['flags'] = $options['flags'];
}
$batch[OP_SEND_MESSAGE] = $message_array;
}
}
private $call_;
private $initialMetadataSent_ = false;
}

@ -0,0 +1,268 @@
<?php
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerCallReader.php');
require_once(dirname(__FILE__) . '/../../lib/Grpc/ServerCallWriter.php');
require_once(dirname(__FILE__) . '/../../lib/Grpc/Status.php');
// load protobuf from third_party
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/../../../../third_party/protobuf/php/src/');
spl_autoload_register(function ($className) {
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, $className);
if (strpos($classPath, 'Google/Protobuf') === 0 || strpos($classPath, 'GPBMetadata/Google/Protobuf') === 0) {
require_once($classPath . '.php');
}
});
class StartBatchEvent
{
public function __construct(string $message)
{
$this->message = $message;
}
public $message;
}
class ServerCallTest extends \PHPUnit\Framework\TestCase
{
public function setUp(): void
{
$this->mockCall = $this->getMockBuilder(stdClass::class)
->setMethods(['startBatch'])
->getMock();
}
public function newStringMessage(string $value = 'a string')
{
$message = new \Google\Protobuf\StringValue();
$message->setValue($value);
return $message;
}
public function testRead()
{
$message = $this->newStringMessage();
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_RECV_MESSAGE => true,
]))->willReturn(new StartBatchEvent($message->serializeToString()));
$serverCallReader = new \Grpc\ServerCallReader(
$this->mockCall,
'\Google\Protobuf\StringValue'
);
$return = $serverCallReader->read();
$this->assertEquals($message, $return);
}
public function testStartEmptyMetadata()
{
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => [],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->start([]);
}
public function testStartWithMetadata()
{
$metadata = ['a' => 1];
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => $metadata,
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->start($metadata);
return $serverCallWriter;
}
public function testStartWithMessage()
{
$metadata = ['a' => 1];
$message = $this->newStringMessage();
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => $metadata,
\Grpc\OP_SEND_MESSAGE => ['message' => $message->serializeToString()],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->start($metadata, $message);
}
public function testWriteStartWithMessageAndOptions()
{
$metadata = ['a' => 1];
$message = $this->newStringMessage();
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => $metadata,
\Grpc\OP_SEND_MESSAGE => [
'message' => $message->serializeToString(),
'flags' => 0x02,
],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->start($metadata, $message, ['flags' => 0x02]);
}
public function testWriteDataOnly()
{
$message = $this->newStringMessage();
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => [],
\Grpc\OP_SEND_MESSAGE => ['message' => $message->serializeToString()],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->write($message);
}
public function testWriteDataWithOptions()
{
$message = $this->newStringMessage();
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => [],
\Grpc\OP_SEND_MESSAGE => [
'message' => $message->serializeToString(),
'flags' => 0x02
],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->write($message, ['flags' => 0x02]);
}
public function testWriteDataWithMetadata()
{
$metadata = ['a' => 1];
$message = $this->newStringMessage();
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => $metadata,
\Grpc\OP_SEND_MESSAGE => ['message' => $message->serializeToString()],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->write($message, [], $metadata);
}
public function testFinish()
{
$status = \Grpc\Status::status(
\Grpc\STATUS_INVALID_ARGUMENT,
"invalid argument",
['trailiingMeta' => 100]
);
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_STATUS_FROM_SERVER => $status,
\Grpc\OP_RECV_CLOSE_ON_SERVER => true,
\Grpc\OP_SEND_INITIAL_METADATA => [],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->finish($status);
}
public function testFinishWithMetadataAndMessage()
{
$metadata = ['a' => 1];
$message = $this->newStringMessage();
$status = \Grpc\Status::ok(['trailiingMeta' => 100]);
$this->mockCall->expects($this->once())
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_STATUS_FROM_SERVER => $status,
\Grpc\OP_RECV_CLOSE_ON_SERVER => true,
\Grpc\OP_SEND_INITIAL_METADATA => $metadata,
\Grpc\OP_SEND_MESSAGE => [
'message' => $message->serializeToString(),
'flags' => 0x02,
],
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->finish($status, $metadata, $message, ['flags' => 0x02]);
}
public function testStartWriteFinish()
{
$metadata = ['a' => 1];
$metadata2 = ['a' => 2];
$message1 = $this->newStringMessage();
$message2 = $this->newStringMessage('another string');
$this->mockCall->expects($this->at(0))
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_INITIAL_METADATA => $metadata,
]));
$this->mockCall->expects($this->at(1))
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_MESSAGE => ['message' => $message1->serializeToString()],
]));
$this->mockCall->expects($this->at(2))
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_MESSAGE => [
'message' => $message2->serializeToString(),
'flags' => 0x02,
]
]));
$this->mockCall->expects($this->at(3))
->method('startBatch')
->with($this->identicalTo([
\Grpc\OP_SEND_STATUS_FROM_SERVER => \Grpc\Status::ok(),
\Grpc\OP_RECV_CLOSE_ON_SERVER => true,
]));
$serverCallWriter = new \Grpc\ServerCallWriter($this->mockCall);
$serverCallWriter->start($metadata);
$serverCallWriter->write($message1, [], $metadata2 /* should not send */);
$serverCallWriter->write($message2, ['flags' => 0x02]);
$serverCallWriter->finish();
}
}

@ -814,6 +814,8 @@ src/php/lib/Grpc/DefaultCallInvoker.php \
src/php/lib/Grpc/Interceptor.php \
src/php/lib/Grpc/RpcServer.php \
src/php/lib/Grpc/Server.php \
src/php/lib/Grpc/ServerCallReader.php \
src/php/lib/Grpc/ServerCallWriter.php \
src/php/lib/Grpc/ServerCredentials.php \
src/php/lib/Grpc/ServerStreamingCall.php \
src/php/lib/Grpc/Status.php \

Loading…
Cancel
Save