Skip to content

Commit

Permalink
replace react with amphp and revolt
Browse files Browse the repository at this point in the history
  • Loading branch information
ata-no-one committed Jul 3, 2024
1 parent 72461e7 commit fe28cf8
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 140 deletions.
76 changes: 32 additions & 44 deletions php/src/vaas/Authentication/OAuth2TokenReceiver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,68 @@

namespace VaasSdk\Authentication;

use Amp\Http\Client\Form;
use Amp\Http\Client\HttpClient;
use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Request;
use Amp\TimeoutCancellation;
use Exception;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\EventLoop\StreamSelectLoop;
use React\Http\Browser;
use React\Socket\Connector;
use React\Socket\DnsConnector;
use React\Socket\TcpConnector;
use React\Stream\ReadableStreamInterface;
use VaasSdk\Exceptions\VaasAuthenticationException;

use function React\Async\await;
use function React\Promise\Stream\buffer;

class OAuth2TokenReceiver {
private string $_tokenEndpoint;
private string $_clientId;
private string $_clientSecret;
private string $_username;
private string $_password;
private string $_grantType;
private Array $_formParams;
private Browser $_browser;
private Form $_formParams;
private HttpClient $_browser;
private int $_receiveTokenTimeout = 30;

public function __construct(
string $tokenEndpoint, string $clientId, string $clientSecret = "",
string $username = "", string $password = "", Browser $browser = new Browser())
string $username = "", string $password = "")
{
$loop = new StreamSelectLoop();
$connector = new Connector([], $loop);
$this->_browser = new Browser($connector, $loop);
$this->_browser = $browser;
$this->_browser = HttpClientBuilder::buildDefault();
$this->_tokenEndpoint = $tokenEndpoint;
$this->_clientId = $clientId;
$this->_clientSecret = $clientSecret;
$this->_username = $username;
$this->_password = $password;
$this->_grantType = $this->_clientSecret == "" ? "password" : "client_credentials";

$this->_formParams = [
'client_id' => $this->_clientId,
'grant_type' => $this->_grantType
];

$this->_formParams = match($this->_grantType) {
"password" => array_merge($this->_formParams, ['username' => $this->_username, 'password' => $this->_password]),
"client_credentials" => array_merge($this->_formParams, ['client_secret' => $this->_clientSecret]),
default => throw new VaasAuthenticationException("Invalid grant type")
};
$this->_formParams = new Form();
$this->_formParams->addField('client_id', $this->_clientId);
$this->_formParams->addField('grant_type', $this->_grantType);

switch($this->_grantType) {
case "password":
$this->_formParams->addField('username', $this->_username);
$this->_formParams->addField('password', $this->_password);
break;
case "client_credentials":
$this->_formParams->addField('client_secret', $this->_clientSecret);
break;
default:
throw new VaasAuthenticationException("Invalid grant type");
}
}

public function GetToken() {
$headers = ['Content-Type' => 'application/x-www-form-urlencoded'];

try {
$response = await($this->_browser
->withTimeout($this->_receiveTokenTimeout)
->requestStreaming(
'POST',
$this->_tokenEndpoint,
$headers,
\http_build_query($this->_formParams)
));
if ($response->getStatusCode() != 200) {
throw new VaasAuthenticationException($response->getReasonPhrase(), $response->getStatusCode());
$request = new Request($this->_tokenEndpoint, 'POST');
$request->addHeader('Content-Type', 'application/x-www-form-urlencoded');
$request->setBody($this->_formParams);
$response = $this->_browser->request($request, new TimeoutCancellation($this->_receiveTokenTimeout));
if ($response->getStatus() != 200) {
throw new VaasAuthenticationException($response->getReason(), $response->getStatus());
}
} catch (Exception $e) {
throw new VaasAuthenticationException($e->getMessage(), $e->getCode());
}
$body = $response->getBody();
assert($body instanceof ReadableStreamInterface);
$bodyString = await(buffer($body));
$response_body = json_decode($bodyString);
$body = $response->getBody()->buffer();
$response_body = json_decode($body);
return $response_body->access_token;
}
}
51 changes: 27 additions & 24 deletions php/src/vaas/Vaas.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

namespace VaasSdk;

use Amp\ByteStream\ReadableResourceStream;
use Amp\ByteStream\ReadableStream;
use Amp\Http\Client\HttpClient;
use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\HttpException;
use Amp\Http\Client\Request;
use Amp\Http\Client\StreamedContent;
use Amp\TimeoutCancellation;
use InvalidArgumentException;
use JsonMapper;
use JsonMapper_Exception;
Expand All @@ -25,19 +33,13 @@
use VaasSdk\VaasOptions;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
use React\EventLoop\Loop;
use React\Http\Browser;
use React\Http\Message\ResponseException;
use Revolt\EventLoop;
use VaasSdk\Message\BaseMessage;
use VaasSdk\Message\VaasVerdict;
use WebSocket\BadOpcodeException;
use React\Stream\ReadableResourceStream;
use React\Stream\ReadableStreamInterface;
use WebSocket\Message\Close;
use WebSocket\Message\Ping;

use function React\Async\await;

class Vaas
{
private string $_vaasUrl = "wss://gateway.production.vaas.gdatasecurity.de";
Expand All @@ -46,14 +48,14 @@ class Vaas
private int $_uploadTimeoutInSeconds = 600;
private LoggerInterface $_logger;
private VaasOptions $_options;
private Browser $_httpClient;
private HttpClient $_httpClient;

/**
*/
public function __construct(?string $vaasUrl, ?LoggerInterface $logger = new NullLogger(), VaasOptions $options = new VaasOptions())
{
$this->_options = $options;
$this->_httpClient = new Browser();
$this->_httpClient = HttpClientBuilder::buildDefault();
$this->_logger = $logger;
$this->_logger->debug("Url: " . $vaasUrl);
if ($vaasUrl)
Expand Down Expand Up @@ -168,7 +170,7 @@ public function ForFile(string $path, $upload = true, string $uuid = null): Vaas
/**
* Gets verdict by stream
*
* @param ReadableStreamInterface $stream the path to get the verdict for
* @param ReadableStream $stream the path to get the verdict for
* @param bool $upload should the file be uploaded if initial verdict is unknown
* @param string $uuid unique identifier
*
Expand All @@ -181,7 +183,7 @@ public function ForFile(string $path, $upload = true, string $uuid = null): Vaas
* @throws GuzzleException
* @throws UploadFailedException
*/
public function ForStream(ReadableStreamInterface $stream, int $size = 0, string $uuid = null): VaasVerdict
public function ForStream(ReadableStream $stream, int $size = 0, string $uuid = null): VaasVerdict
{
$this->_logger->debug("uuid: ".var_export($uuid, true));
$uuid = $uuid !== null ? $uuid : UuidV4::getFactory()->uuid4()->toString();
Expand Down Expand Up @@ -488,33 +490,34 @@ public function setUploadTimeout(int $UploadTimeoutInSeconds): self
* @throws GuzzleException
* @throws UploadFailedException
*/
private function UploadStream(ReadableStreamInterface $fileStream, string $url, string $uploadToken, int $fileSize)
private function UploadStream(ReadableStream $fileStream, string $url, string $uploadToken, int $fileSize)
{
$times = 0;
$pingTimer = Loop::addPeriodicTimer(5, function () use(&$times) {
$pingTimer = EventLoop::repeat(5, function () use(&$times) {
$this->_logger->debug("pinging " . $times++);
$websocket = $this->_vaasConnection->GetAuthenticatedWebsocket();
$websocket->ping();
});

try {
$response = await($this->_httpClient->withTimeout($this->_uploadTimeoutInSeconds)->requestStreaming('PUT', $url,
[
"Content-Length" => $fileSize,
"Authorization" => $uploadToken,
],
$fileStream
));
if ($response->getStatusCode() > 399) {
throw new UploadFailedException($response->getReasonPhrase(), $response->getStatusCode());
$request = new Request($url, 'PUT');
$request->setTransferTimeout($this->_uploadTimeoutInSeconds);
$request->setBody(StreamedContent::fromStream($fileStream, $fileSize));
$request->addHeader("Content-Length", $fileSize);
$request->addHeader("Authorization", $uploadToken);

$response = $this->_httpClient->request($request, new TimeoutCancellation($this->_uploadTimeoutInSeconds));
if ($response->getStatus() > 399) {
$reason = $response->getBody()->buffer();
throw new UploadFailedException($reason, $response->getStatus());
}
} catch (\Exception $e) {
if ($e instanceof ResponseException) {
if ($e instanceof HttpException) {
throw new UploadFailedException($e->getMessage(), $e->getCode());
}
throw new VaasClientException($e->getMessage());
} finally {
Loop::cancelTimer($pingTimer);
EventLoop::cancel($pingTimer);
}
}
}
5 changes: 1 addition & 4 deletions php/src/vaas/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@
"textalk/websocket": "^1.6 || ^1.5",
"netresearch/jsonmapper": "^4.4",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"react/event-loop": "^1.5",
"react/http": "^1.10",
"react/async": "^4.3",
"react/promise-stream": "^1.7"
"amphp/http-client": "^5.1"
},
"autoload": {
"psr-4": {
Expand Down
35 changes: 13 additions & 22 deletions php/tests/vaas/StreamsInLoopTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,30 @@

namespace VaasTesting;

use Amp\Http\Client\HttpClientBuilder;
use Amp\Http\Client\Request as ClientRequest;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use React\EventLoop\Loop;
use React\Http\Browser;
use React\Stream\ReadableResourceStream;
use React\Stream\ReadableStreamInterface;
use React\Stream\ThroughStream;
use React\Stream\Util;
use React\Stream\WritableResourceStream;

use function React\Async\await;
use function React\Promise\Stream\buffer;

final class StreamsInLoopTest extends TestCase
{
use ProphecyTrait;

public function testLoopUnexpectedConsumesStreamWithBrowser() {
$browser1 = new Browser();
$browser2 = new Browser();
public function testLoopUnexpectedConsumesStreamWithAmphp() {
$browser1 = HttpClientBuilder::buildDefault();
$browser2 = HttpClientBuilder::buildDefault();

$response1 = await($browser1->requestStreaming("GET", "https://secure.eicar.org/eicar.com.txt"));
$body1 = $response1->getBody();
$this->assertEquals(true, $body1->isReadable());
assert($body1 instanceof ReadableStreamInterface);
$body1->pause();
$response1 = $browser1->request(new ClientRequest("https://secure.eicar.org/eicar.com.txt", "GET"));
$bodyStream1 = $response1->getBody();
$this->assertTrue($bodyStream1->isReadable());

$response2 = await($browser2->requestStreaming("GET", "https://secure.eicar.org/eicar.com"));
$this->assertEquals(false, $body1->isReadable());
$body2 = $response2->getBody();
$this->assertEquals(true, $body2->isReadable());
$response2 = $browser2->request(new ClientRequest("https://secure.eicar.org/eicar.com", "GET"));
$bodyStream2 = $response2->getBody();
$this->assertTrue($bodyStream1->isReadable());
}



static function random_strings($length_of_string) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$characters_length = strlen($characters);
Expand Down
Loading

0 comments on commit fe28cf8

Please sign in to comment.