From d96bf416d3bdd4c3be5f5de01a9f862612dbf518 Mon Sep 17 00:00:00 2001 From: sergeytangyan Date: Fri, 8 Sep 2017 13:55:03 +0400 Subject: [PATCH 1/3] first --- composer.json | 4 +- composer.lock | 493 ++++++++++++++++++++++- src/EtherScan/Resources/ApiConnector.php | 25 +- 3 files changed, 498 insertions(+), 24 deletions(-) diff --git a/composer.json b/composer.json index 4b2d50b..67ca0ef 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,9 @@ "minimum-stability": "stable", "require": { "php": "^7.0", - "guzzlehttp/promises": "^1.3" + "react/promise": "^2.5", + "react/event-loop": "^0.4.3", + "react/http-client": "^0.5.4" }, "require-dev": { "phpunit/phpunit": "^6.3" diff --git a/composer.lock b/composer.lock index cc6a364..cb8a5f0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,27 +4,74 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "8d3e50d3cd4ff8d2cb720486b6ad61f9", + "content-hash": "7855efe9dda4163d41bb7675b0924c5e", "packages": [ { - "name": "guzzlehttp/promises", - "version": "v1.3.1", + "name": "evenement/evenement", + "version": "v3.0.1", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + "url": "https://github.com/igorw/evenement.git", + "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", - "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7", + "reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7", "shasum": "" }, "require": { - "php": ">=5.5.0" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^4.0" + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "time": "2017-07-23T21:35:13+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" }, "type": "library", "extra": { @@ -34,7 +81,7 @@ }, "autoload": { "psr-4": { - "GuzzleHttp\\Promise\\": "src/" + "GuzzleHttp\\Psr7\\": "src/" }, "files": [ "src/functions_include.php" @@ -49,13 +96,433 @@ "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "react/cache", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "558f614891341b1d817a8cdf9a358948ec49638f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/558f614891341b1d817a8cdf9a358948ec49638f", + "reference": "558f614891341b1d817a8cdf9a358948ec49638f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "~2.0|~1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src\\" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async caching.", + "keywords": [ + "cache" + ], + "time": "2016-02-25T18:17:16+00:00" + }, + { + "name": "react/dns", + "version": "v0.4.11", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "8558bba4f2784aa997670d15fc6f7461a8eb4e53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/8558bba4f2784aa997670d15fc6f7461a8eb4e53", + "reference": "8558bba4f2784aa997670d15fc6f7461a8eb4e53", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "~0.4.0|~0.3.0", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", + "react/promise": "^2.1 || ^1.2.1", + "react/promise-timer": "^1.2", + "react/socket": "^1.0 || ^0.8 || ^0.7 || ^0.6 || ^0.5 || ^0.4.4", + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.5" + }, + "require-dev": { + "clue/block-react": "^1.2", + "phpunit/phpunit": "^5.0 || ^4.8.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "time": "2017-08-25T08:22:48+00:00" + }, + { + "name": "react/event-loop", + "version": "v0.4.3", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "8bde03488ee897dc6bb3d91e4e17c353f9c5252f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/8bde03488ee897dc6bb3d91e4e17c353f9c5252f", + "reference": "8bde03488ee897dc6bb3d91e4e17c353f9c5252f", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-event": "~1.0", + "ext-libev": "*", + "ext-libevent": ">=0.1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Event loop abstraction layer that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "time": "2017-04-27T10:56:23+00:00" + }, + { + "name": "react/http-client", + "version": "v0.5.4", + "source": { + "type": "git", + "url": "https://github.com/reactphp/http-client.git", + "reference": "e11eef9c82595a42a8523252bafe4bb5cbfb306d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/http-client/zipball/e11eef9c82595a42a8523252bafe4bb5cbfb306d", + "reference": "e11eef9c82595a42a8523252bafe4bb5cbfb306d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0", + "guzzlehttp/psr7": "^1.0", + "php": ">=5.4.0", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3", + "react/promise": "~2.2", + "react/socket": "^1.0 || ^0.8.2", + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.2" + }, + "require-dev": { + "phpunit/phpunit": "^5.0 || ^4.8.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\HttpClient\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Event-driven, streaming HTTP client for ReactPHP", + "keywords": [ + "http" + ], + "time": "2017-08-25T12:20:26+00:00" + }, + { + "name": "react/promise", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "62785ae604c8d69725d693eb370e1d67e94c4053" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/62785ae604c8d69725d693eb370e1d67e94c4053", + "reference": "62785ae604c8d69725d693eb370e1d67e94c4053", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "time": "2017-03-25T12:08:31+00:00" + }, + { + "name": "react/promise-timer", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise-timer.git", + "reference": "3bc527fbd1201a193ab41c19b9a770d71a3514af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/3bc527fbd1201a193ab41c19b9a770d71a3514af", + "reference": "3bc527fbd1201a193ab41c19b9a770d71a3514af", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", + "react/promise": "~2.1|~1.2" + }, + "require-dev": { + "phpunit/phpunit": "^5.0 || ^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Promise\\Timer\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@lueck.tv" + } + ], + "description": "Trivial timeout implementation for Promises", + "homepage": "https://github.com/react/promise-timer", + "keywords": [ + "async", + "event-loop", + "promise", + "reactphp", + "timeout", + "timer" + ], + "time": "2017-08-08T16:30:19+00:00" + }, + { + "name": "react/socket", + "version": "v0.8.2", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "ee817e348abcf35c55b448a5cd3ef4eec88379e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/ee817e348abcf35c55b448a5cd3ef4eec88379e9", + "reference": "ee817e348abcf35c55b448a5cd3ef4eec88379e9", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^0.4.11", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", + "react/promise": "^2.1 || ^1.2", + "react/promise-timer": "~1.0", + "react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.5" + }, + "require-dev": { + "clue/block-react": "^1.1", + "phpunit/phpunit": "~4.8", + "react/stream": "^1.0 || ^0.7 || ^0.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src" } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "description": "Guzzle promises library", + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", "keywords": [ - "promise" + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "time": "2017-08-25T09:08:33+00:00" + }, + { + "name": "react/stream", + "version": "v0.7.3", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "5cc7bec91dc3f6ad123a81602489b82fdb180090" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/5cc7bec91dc3f6ad123a81602489b82fdb180090", + "reference": "5cc7bec91dc3f6ad123a81602489b82fdb180090", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^5.0 || ^4.8.10" + }, + "suggest": { + "react/event-loop": "^0.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], - "time": "2016-12-20T10:07:11+00:00" + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "time": "2017-08-05T09:16:09+00:00" } ], "packages-dev": [ diff --git a/src/EtherScan/Resources/ApiConnector.php b/src/EtherScan/Resources/ApiConnector.php index 200c3c8..f9ccdb1 100644 --- a/src/EtherScan/Resources/ApiConnector.php +++ b/src/EtherScan/Resources/ApiConnector.php @@ -3,7 +3,8 @@ namespace EtherScan\Resources; use Exception; -use GuzzleHttp\Promise\Promise; +use React\EventLoop\Factory; +use React\HttpClient\Client; class ApiConnector { @@ -11,6 +12,8 @@ class ApiConnector private $ch; /** @var string */ private $apiKey; + private $httpClient; + private $eventLoop; public function __construct(string $apiKey) { @@ -23,6 +26,10 @@ public function __construct(string $apiKey) CURLOPT_SSL_VERIFYPEER => 0 ]); $this->apiKey = $apiKey; + + $this->eventLoop = Factory::create(); + $this->httpClient = new Client($this->eventLoop); + } /** @@ -72,17 +79,15 @@ public function doRequest(string $prefix, string $resource, array $queryParams = public function doRequestAsync(string $prefix, string $resource, array $queryParams, callable $resolve, callable $reject) { - $promise = new Promise(); - $promise->then($resolve, $reject); + $url = $this->generateLink($prefix, $resource, $queryParams); - $result = $this->doRequest($prefix, $resource, $queryParams); - $oResult = json_decode($result); + $request = $this->httpClient->request('GET', $url); + $request->on('response', function (\React\HttpClient\Response $response) use ($resolve) { + $response->on('data', $response); + }); - if ($oResult->status == 1) { - $promise->resolve($result); - } else { - $promise->reject($result); - } + $request->end(); + $this->eventLoop->run(); } public function close() From 9d39ca9e66eb848eb5d3ec0f2be5d5132a770661 Mon Sep 17 00:00:00 2001 From: sergeytangyan Date: Fri, 8 Sep 2017 17:37:33 +0400 Subject: [PATCH 2/3] async restructure --- examples/EtherScanAsyncExample.php | 41 +++++++++++--- examples/EtherScanExample.php | 17 +++++- src/EtherScan/EtherScan.php | 12 ++++ src/EtherScan/Modules/Account.php | 72 +++++++++--------------- src/EtherScan/Modules/Stats.php | 28 +++++---- src/EtherScan/Resources/ApiConnector.php | 40 +++++++------ 6 files changed, 125 insertions(+), 85 deletions(-) diff --git a/examples/EtherScanAsyncExample.php b/examples/EtherScanAsyncExample.php index 6afd718..99499c3 100644 --- a/examples/EtherScanAsyncExample.php +++ b/examples/EtherScanAsyncExample.php @@ -1,19 +1,42 @@ getAccount(EtherScan::PREFIX_API); +$startT = microtime(1); + +$etherScan->callGroupAsync([ + [ + $account->getTransactionsLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, Account::SORT_DESC), + $a, $b + ], + [ + $account->getTransactionsLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, Account::SORT_DESC), + $a, $b + ], + [ + $account->getBalanceLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413'), + $a, $b + ], + [ + $account->getTransactionsLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, Account::SORT_DESC), + $a, $b + ], +]); +$endT = microtime(1); + +echo "DONE IN: " . ($endT - $startT); + -echo $etherScan->getStats(EtherScan::PREFIX_API)->getEthPriceAsync( - function ($responseOnResolve) { - echo 'Called on resolve: ' . $responseOnResolve . PHP_EOL; - }, - function ($responseOnReject) { - echo 'Called on resolve: ' . $responseOnReject . PHP_EOL; - } -); -echo "END OF FILE" . PHP_EOL; diff --git a/examples/EtherScanExample.php b/examples/EtherScanExample.php index d949a3f..927cf74 100644 --- a/examples/EtherScanExample.php +++ b/examples/EtherScanExample.php @@ -8,6 +8,17 @@ $esApiConnector = new ApiConnector('your_api_key'); $etherScan = new EtherScan($esApiConnector); -echo $etherScan->getAccount(EtherScan::PREFIX_API)->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1) . PHP_EOL; -echo $etherScan->getTxLink('0x14dc46124c7cc003c158eb6ba812b2f53d509753fd931607edad957504d19bd3'); -echo "END OF FILE" . PHP_EOL; + +$account = $etherScan->getAccount(EtherScan::PREFIX_API); +$startT = microtime(1); +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +$endT = microtime(1); + + +echo "DONE IN: " . ($endT - $startT); + + + diff --git a/src/EtherScan/EtherScan.php b/src/EtherScan/EtherScan.php index 117dd44..8200b21 100644 --- a/src/EtherScan/EtherScan.php +++ b/src/EtherScan/EtherScan.php @@ -57,4 +57,16 @@ public function getAddressLink(string $address): string return $this->apiConnector->generateLink('', AbstractHttpResource::RESOURCE_ADDRESS . '/' . $address); } + /** + * @param array $calls + */ + public function callGroupAsync(array $calls) + { + foreach ($calls as $call) { + $this->apiConnector->enlistRequest($call[0], $call[1], $call[2]); + } + + $this->apiConnector->getEventLoop()->run(); + } + } \ No newline at end of file diff --git a/src/EtherScan/Modules/Account.php b/src/EtherScan/Modules/Account.php index 51db3eb..dffea88 100644 --- a/src/EtherScan/Modules/Account.php +++ b/src/EtherScan/Modules/Account.php @@ -3,10 +3,13 @@ namespace EtherScan\Modules; use EtherScan\Resources\AbstractHttpResource; +use InvalidArgumentException; class Account extends AbstractHttpResource { - const PAGE_SIZE = 25; + const SORT_DESC = 'desc'; + const SORT_ASC = 'asc'; + private $queryParams = ['module' => 'account']; /** @@ -15,30 +18,22 @@ class Account extends AbstractHttpResource */ public function getBalance(string $address): string { - $finalQuery = array_merge($this->queryParams, [ - 'action' => 'balance', - 'address' => $address, - 'tag' => 'latest' - ]); - return $this->apiConnector->doRequest($this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery); + $url = $this->getBalanceLink($address); + return $this->apiConnector->doRequest($url); } /** * @param string $address - * @param callable $resolveHandler - * @param callable $rejectHandler */ - public function getBalanceAsync(string $address, - callable $resolveHandler, callable $rejectHandler) + public function getBalanceLink(string $address) { $finalQuery = array_merge($this->queryParams, [ 'action' => 'balance', 'address' => $address, 'tag' => 'latest' ]); - $this->apiConnector->doRequestAsync( - $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery, - $resolveHandler, $rejectHandler + return $this->apiConnector->generateLink( + $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery ); } @@ -48,30 +43,23 @@ public function getBalanceAsync(string $address, */ public function getBalances(array $addressList): string { - $finalQuery = array_merge($this->queryParams, [ - 'action' => 'balancemulti', - 'address' => implode(',', $addressList), - 'tag' => 'latest' - ]); - return $this->apiConnector->doRequest($this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery); + $url = $this->getBalancesLink($addressList); + return $this->apiConnector->doRequest($url); } /** * @param array $addressList - * @param callable $resolveHandler - * @param callable $rejectHandler + * @return string */ - public function getBalancesAsync(array $addressList, - callable $resolveHandler, callable $rejectHandler) + public function getBalancesLink(array $addressList) { $finalQuery = array_merge($this->queryParams, [ 'action' => 'balancemulti', 'address' => implode(',', $addressList), 'tag' => 'latest' ]); - $this->apiConnector->doRequestAsync( - $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery, - $resolveHandler, $rejectHandler + return $this->apiConnector->generateLink( + $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery ); } @@ -81,38 +69,34 @@ public function getBalancesAsync(array $addressList, * @param int $pageSize * @return string */ - public function getTransactions(string $address, int $page, int $pageSize = Account::PAGE_SIZE): string + public function getTransactions(string $address, int $page, int $pageSize, string $sort): string { - $finalQuery = array_merge($this->queryParams, [ - 'action' => 'txlist', - 'address' => $address, - 'offset' => $pageSize, - 'page' => $page, - 'sort' => 'desc' - ]); - return $this->apiConnector->doRequest($this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery); + $url = $this->getTransactionsLink($address, $page, $pageSize, $sort); + return $this->apiConnector->doRequest($url); } /** * @param string $address * @param int $page * @param int $pageSize - * @param callable $resolveHandler - * @param callable $rejectHandler + * @param string $sort + * @return string + * @throws InvalidArgumentException */ - public function getTransactionsAsync(string $address, int $page, int $pageSize, - callable $resolveHandler, callable $rejectHandler) + public function getTransactionsLink(string $address, int $page, int $pageSize, string $sort) { + if ($sort != Account::SORT_ASC && $sort != Account::SORT_DESC) { + throw new InvalidArgumentException('Argument sort is invalid'); + } $finalQuery = array_merge($this->queryParams, [ 'action' => 'txlist', 'address' => $address, 'offset' => $pageSize, 'page' => $page, - 'sort' => 'desc' + 'sort' => $sort ]); - $this->apiConnector->doRequestAsync( - $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery, - $resolveHandler, $rejectHandler + return $this->apiConnector->generateLink( + $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery ); } diff --git a/src/EtherScan/Modules/Stats.php b/src/EtherScan/Modules/Stats.php index c491fe8..63c8d4d 100644 --- a/src/EtherScan/Modules/Stats.php +++ b/src/EtherScan/Modules/Stats.php @@ -13,16 +13,18 @@ class Stats extends AbstractHttpResource */ public function getEthPrice(): string { - $finalQuery = array_merge($this->queryParams, ['action' => 'ethprice']); - return $this->apiConnector->doRequest($this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery); + $url = $this->getEthPriceLink(); + return $this->apiConnector->doRequest($url); } - public function getEthPriceAsync(callable $resolveHandler, callable $rejectHandler) + /** + * @return string + */ + public function getEthPriceLink() { $finalQuery = array_merge($this->queryParams, ['action' => 'ethprice']); - $this->apiConnector->doRequestAsync( - $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery, - $resolveHandler, $rejectHandler + return $this->apiConnector->generateLink( + $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery ); } @@ -31,16 +33,18 @@ public function getEthPriceAsync(callable $resolveHandler, callable $rejectHandl */ public function getEthSupply(): string { - $finalQuery = array_merge($this->queryParams, ['action' => 'ethsupply']); - return $this->apiConnector->doRequest($this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery); + $url = $this->getEthSupplyLink(); + return $this->apiConnector->doRequest($url); } - public function getEthSupplyAsync(callable $resolveHandler, callable $rejectHandler) + /** + * @return string + */ + public function getEthSupplyLink() { $finalQuery = array_merge($this->queryParams, ['action' => 'ethsupply']); - $this->apiConnector->doRequestAsync( - $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery, - $resolveHandler, $rejectHandler + return $this->apiConnector->generateLink( + $this->prefix, AbstractHttpResource::RESOURCE_API, $finalQuery ); } diff --git a/src/EtherScan/Resources/ApiConnector.php b/src/EtherScan/Resources/ApiConnector.php index f9ccdb1..8a93879 100644 --- a/src/EtherScan/Resources/ApiConnector.php +++ b/src/EtherScan/Resources/ApiConnector.php @@ -4,7 +4,9 @@ use Exception; use React\EventLoop\Factory; +use React\EventLoop\LoopInterface; use React\HttpClient\Client; +use React\HttpClient\Response; class ApiConnector { @@ -12,7 +14,9 @@ class ApiConnector private $ch; /** @var string */ private $apiKey; + /** @var Client */ private $httpClient; + /** @var LoopInterface */ private $eventLoop; public function __construct(string $apiKey) @@ -29,10 +33,10 @@ public function __construct(string $apiKey) $this->eventLoop = Factory::create(); $this->httpClient = new Client($this->eventLoop); - } /** + * @param string $prefix * @param string $resource * @param array|null $queryParams * @return string @@ -53,13 +57,12 @@ public function generateLink(string $prefix, string $resource, array $queryParam } /** - * @param string $resource - * @param array|null $queryParams + * @param string $url * @return string + * @throws Exception */ - public function doRequest(string $prefix, string $resource, array $queryParams = null): string + public function doRequest(string $url): string { - $url = $this->generateLink($prefix, $resource, $queryParams); curl_setopt($this->ch, CURLOPT_URL, $url); $result = curl_exec($this->ch); @@ -71,23 +74,26 @@ public function doRequest(string $prefix, string $resource, array $queryParams = } /** - * @param string $resource - * @param array $queryParams + * @param string $url * @param callable $resolve - * @param callable $reject */ - public function doRequestAsync(string $prefix, string $resource, array $queryParams, callable $resolve, - callable $reject) + public function enlistRequest(string $url, callable $onResponse, callable $onError) { - $url = $this->generateLink($prefix, $resource, $queryParams); - $request = $this->httpClient->request('GET', $url); - $request->on('response', function (\React\HttpClient\Response $response) use ($resolve) { - $response->on('data', $response); - }); - + $request->on('response', + function (Response $response) use ($onResponse) { + $response->on('data', $onResponse); + }); + $request->on('error', $onError); $request->end(); - $this->eventLoop->run(); + } + + /** + * @return \React\EventLoop\ExtEventLoop|\React\EventLoop\LibEventLoop|\React\EventLoop\LibEvLoop|\React\EventLoop\StreamSelectLoop + */ + public function getEventLoop() + { + return $this->eventLoop; } public function close() From a2e6c081af56fcc3ba64816cfb78da7693481610 Mon Sep 17 00:00:00 2001 From: sergeytangyan Date: Mon, 11 Sep 2017 11:19:31 +0400 Subject: [PATCH 3/3] cleanup before merge --- README.md | 52 +++++++++++++++++++++++------- examples/EtherScanAsyncExample.php | 4 +-- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 536e0c7..066f585 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,17 @@ $esApiConnector = new ApiConnector('your_api_key'); $etherScan = new EtherScan($esApiConnector); -echo $etherScan->getAccount(EtherScan::PREFIX_API)->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1) . PHP_EOL; -echo $etherScan->getTxLink('0x14dc46124c7cc003c158eb6ba812b2f53d509753fd931607edad957504d19bd3'); -echo "END OF FILE" . PHP_EOL; + +$account = $etherScan->getAccount(EtherScan::PREFIX_API); +$startT = microtime(1); +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +echo $account->getTransactions('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, 'desc') . PHP_EOL; +$endT = microtime(1); + + +echo "DONE IN: " . ($endT - $startT); ``` @@ -20,16 +28,36 @@ echo "END OF FILE" . PHP_EOL; ``` $esApiConnector = new ApiConnector('your_api_key'); $etherScan = new EtherScan($esApiConnector); +$a = function ($responseOnResolve) { + echo 'Called on resolve: ' . $responseOnResolve . PHP_EOL; +}; +$b = function ($responseOnResolve) { + echo 'Called on error: ' . $responseOnResolve . PHP_EOL; +}; +$account = $etherScan->getAccount(EtherScan::PREFIX_API); +$startT = microtime(1); + +$etherScan->callGroupAsync([ + [ + $account->getTransactionsLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, Account::SORT_DESC), + $a, $b + ], + [ + $account->getTransactionsLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, Account::SORT_DESC), + $a, $b + ], + [ + $account->getBalanceLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413'), + $a, $b + ], + [ + $account->getTransactionsLink('0xbb9bc244d798123fde783fcc1c72d3bb8c189413', 1, 25, Account::SORT_DESC), + $a, $b + ], +]); +$endT = microtime(1); -echo $etherScan->getStats(EtherScan::PREFIX_API)->getEthPriceAsync( - function ($responseOnResolve) { - echo 'Called on resolve: ' . $responseOnResolve . PHP_EOL; - }, - function ($responseOnReject) { - echo 'Called on reject: ' . $responseOnReject . PHP_EOL; - } -); -echo "END OF FILE" . PHP_EOL; +echo "DONE IN: " . ($endT - $startT); ``` diff --git a/examples/EtherScanAsyncExample.php b/examples/EtherScanAsyncExample.php index 99499c3..0c1d189 100644 --- a/examples/EtherScanAsyncExample.php +++ b/examples/EtherScanAsyncExample.php @@ -9,10 +9,10 @@ $esApiConnector = new ApiConnector('your_api_key'); $etherScan = new EtherScan($esApiConnector); $a = function ($responseOnResolve) { - echo 'Called on error: ' . $responseOnResolve . PHP_EOL; + echo 'Called on resolve: ' . $responseOnResolve . PHP_EOL; }; $b = function ($responseOnResolve) { - echo 'Called on resolve: ' . PHP_EOL; + echo 'Called on error: ' . $responseOnResolve . PHP_EOL; }; $account = $etherScan->getAccount(EtherScan::PREFIX_API); $startT = microtime(1);