[IMPROVED] jsonRPC Error Handling with CURL
* [ADDED] Use curl instead of fopen * [ADDED] Error handling for various connection issues * [MOVED] jsonRPC library into lib folder * [UPDATED] Pools page for proper RPC errors with caching enabled It's using the base RPC class but modified to support CURL. Simplified some code since we won't need those features. Should make maintaining that code a whole lot easier. Fixes #1343 once merged.
This commit is contained in:
parent
290ac36729
commit
aa27e8dfde
@ -229,24 +229,7 @@ class Bitcoin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception class for BitcoinClient
|
||||
*
|
||||
* @author Mike Gogulski
|
||||
* http://www.gogulski.com/ http://www.nostate.com/
|
||||
*/
|
||||
class BitcoinClientException extends ErrorException {
|
||||
// Redefine the exception so message isn't optional
|
||||
public function __construct($message, $code = 0, $severity = E_USER_NOTICE, Exception $previous = null) {
|
||||
parent::__construct($message, $code, $severity, $previous);
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
|
||||
}
|
||||
}
|
||||
|
||||
require_once(INCLUDE_DIR . "/jsonRPCClient.php");
|
||||
require_once(INCLUDE_DIR . "/lib/jsonRPCClient.php");
|
||||
|
||||
/**
|
||||
* Bitcoin client class for access to a Bitcoin server via JSON-RPC-HTTP[S]
|
||||
@ -283,21 +266,21 @@ class BitcoinClient extends jsonRPCClient {
|
||||
* @access public
|
||||
* @throws BitcoinClientException
|
||||
*/
|
||||
public function __construct($scheme, $username, $password, $address = "localhost", $port = 8332, $certificate_path = '', $debug_level = 0) {
|
||||
public function __construct($scheme, $username, $password, $address = "localhost", $port = 8332, $certificate_path = '', $debug = true) {
|
||||
$scheme = strtolower($scheme);
|
||||
if ($scheme != "http" && $scheme != "https")
|
||||
throw new BitcoinClientException("Scheme must be http or https");
|
||||
throw new Exception("Scheme must be http or https");
|
||||
if (empty($username))
|
||||
throw new BitcoinClientException("Username must be non-blank");
|
||||
throw new Exception("Username must be non-blank");
|
||||
if (empty($password))
|
||||
throw new BitcoinClientException("Password must be non-blank");
|
||||
throw new Exception("Password must be non-blank");
|
||||
$port = (string) $port;
|
||||
if (!$port || empty($port) || !is_numeric($port) || $port < 1 || $port > 65535 || floatval($port) != intval($port))
|
||||
throw new BitcoinClientException("Port must be an integer and between 1 and 65535");
|
||||
throw new Exception("Port must be an integer and between 1 and 65535");
|
||||
if (!empty($certificate_path) && !is_readable($certificate_path))
|
||||
throw new BitcoinClientException("Certificate file " . $certificate_path . " is not readable");
|
||||
throw new Exception("Certificate file " . $certificate_path . " is not readable");
|
||||
$uri = $scheme . "://" . $username . ":" . $password . "@" . $address . "/";
|
||||
parent::__construct($uri);
|
||||
parent::__construct($uri, $debug);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,167 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
COPYRIGHT
|
||||
|
||||
Copyright 2007 Sergio Vaccaro <sergio@inservibile.org>
|
||||
|
||||
This file is part of JSON-RPC PHP.
|
||||
|
||||
JSON-RPC PHP is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
JSON-RPC PHP is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JSON-RPC PHP; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* The object of this class are generic jsonRPC 1.0 clients
|
||||
* http://json-rpc.org/wiki/specification
|
||||
*
|
||||
* @author sergio <jsonrpcphp@inservibile.org>
|
||||
*/
|
||||
class jsonRPCClient {
|
||||
|
||||
/**
|
||||
* Debug state
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $debug;
|
||||
|
||||
/**
|
||||
* The server URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
/**
|
||||
* The request id
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private $id;
|
||||
/**
|
||||
* If true, notifications are performed instead of requests
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $notification = false;
|
||||
|
||||
/**
|
||||
* Takes the connection parameters
|
||||
*
|
||||
* @param string $url
|
||||
* @param boolean $debug
|
||||
*/
|
||||
public function __construct($url,$debug = false) {
|
||||
// server URL
|
||||
$this->url = $url;
|
||||
// proxy
|
||||
empty($proxy) ? $this->proxy = '' : $this->proxy = $proxy;
|
||||
// debug state
|
||||
empty($debug) ? $this->debug = false : $this->debug = true;
|
||||
// message id
|
||||
$this->id = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the notification state of the object. In this state, notifications are performed, instead of requests.
|
||||
*
|
||||
* @param boolean $notification
|
||||
*/
|
||||
public function setRPCNotification($notification) {
|
||||
empty($notification) ?
|
||||
$this->notification = false
|
||||
:
|
||||
$this->notification = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a jsonRCP request and gets the results as an array
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function __call($method,$params) {
|
||||
|
||||
// check
|
||||
if (!is_scalar($method)) {
|
||||
throw new Exception('Method name has no scalar value');
|
||||
}
|
||||
|
||||
// check
|
||||
if (is_array($params)) {
|
||||
// no keys
|
||||
$params = array_values($params);
|
||||
} else {
|
||||
throw new Exception('Params must be given as array');
|
||||
}
|
||||
|
||||
// sets notification or request task
|
||||
if ($this->notification) {
|
||||
$currentId = NULL;
|
||||
} else {
|
||||
$currentId = $this->id;
|
||||
}
|
||||
|
||||
// prepares the request
|
||||
$request = array(
|
||||
'method' => $method,
|
||||
'params' => $params,
|
||||
'id' => $currentId
|
||||
);
|
||||
$request = json_encode($request);
|
||||
$this->debug && $this->debug.='***** Request *****'."\n".$request."\n".'***** End Of request *****'."\n\n";
|
||||
|
||||
// performs the HTTP POST
|
||||
$opts = array ('http' => array (
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-type: application/json',
|
||||
'content' => $request
|
||||
));
|
||||
$context = stream_context_create($opts);
|
||||
if ($fp = @fopen($this->url, 'r', false, $context)) {
|
||||
$response = '';
|
||||
while($row = fgets($fp)) {
|
||||
$response.= trim($row)."\n";
|
||||
}
|
||||
$this->debug && $this->debug.='***** Server response *****'."\n".$response.'***** End of server response *****'."\n";
|
||||
$response = json_decode($response,true);
|
||||
} else {
|
||||
$error = error_get_last();
|
||||
$error = explode(']: ', $error['message']);
|
||||
throw new Exception('Unable to connect: ' . $error[1]);
|
||||
}
|
||||
|
||||
// debug output
|
||||
if ($this->debug) {
|
||||
echo nl2br($debug);
|
||||
}
|
||||
|
||||
// final checks and return
|
||||
if (!$this->notification) {
|
||||
// check
|
||||
if ($response['id'] != $currentId) {
|
||||
throw new Exception('Incorrect response id (request id: '.$currentId.', response id: '.$response['id'].')');
|
||||
}
|
||||
if (!is_null($response['error'])) {
|
||||
throw new Exception('Request error: '.$response['error']);
|
||||
}
|
||||
|
||||
return $response['result'];
|
||||
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
125
public/include/lib/jsonRPCClient.php
Normal file
125
public/include/lib/jsonRPCClient.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/*
|
||||
COPYRIGHT
|
||||
|
||||
Copyright 2007 Sergio Vaccaro <sergio@inservibile.org>
|
||||
|
||||
This file is part of JSON-RPC PHP.
|
||||
|
||||
JSON-RPC PHP is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
JSON-RPC PHP is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with JSON-RPC PHP; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* The object of this class are generic jsonRPC 1.0 clients
|
||||
* http://json-rpc.org/wiki/specification
|
||||
*
|
||||
* @author sergio <jsonrpcphp@inservibile.org>
|
||||
*/
|
||||
class jsonRPCClient {
|
||||
|
||||
/**
|
||||
* Debug state
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $debug;
|
||||
private $debug_output;
|
||||
|
||||
/**
|
||||
* The server URL
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
/**
|
||||
* The request id
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* Takes the connection parameters
|
||||
*
|
||||
* @param string $url
|
||||
* @param boolean $debug
|
||||
*/
|
||||
public function __construct($url, $debug = false) {
|
||||
$this->url = $url;
|
||||
$this->debug = $debug;
|
||||
$this->debug_output = '';
|
||||
$this->id = rand(1, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch debug information
|
||||
* @param none
|
||||
* @return array Debug data
|
||||
**/
|
||||
public function getDebugData() {
|
||||
return $this->debug_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a jsonRCP request and gets the results as an array
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function __call($method, $params) {
|
||||
if (!is_scalar($method)) throw new Exception('Method name has no scalar value');
|
||||
|
||||
if (is_array($params)) {
|
||||
// no keys
|
||||
$params = array_values($params);
|
||||
} else {
|
||||
throw new Exception('Params must be given as array');
|
||||
}
|
||||
|
||||
// prepares the request
|
||||
$request = array(
|
||||
'method' => $method,
|
||||
'params' => $params,
|
||||
'id' => $this->id
|
||||
);
|
||||
$request = json_encode($request);
|
||||
if ($this->debug) $this->debug_output[] = 'Request: '.$request;
|
||||
|
||||
// performs the HTTP POST
|
||||
// extract information from URL for proper authentication
|
||||
$url = parse_url($this->url);
|
||||
$ch = curl_init($url['scheme'].'://'.$url['host'].':'.$url['port'].$url['path']);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/json'));
|
||||
curl_setopt($ch, CURLOPT_USERPWD, $url['user'] . ":" . $url['pass']);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
|
||||
$response = json_decode(curl_exec($ch), true);
|
||||
$resultStatus = curl_getinfo($ch);
|
||||
if ($resultStatus['http_code'] != '200') {
|
||||
if ($resultStatus['http_code'] == '401') throw new Exception('RPC call did not return 200: Authentication failed');
|
||||
throw new Exception('RPC call did not return 200: HTTP error: ' . $resultStatus['http_code']);
|
||||
}
|
||||
if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch));
|
||||
if ($this->debug) $this->debug_output[] = 'Response: ' . $response;
|
||||
curl_close($ch);
|
||||
|
||||
// final checks and return
|
||||
if (!is_null($response['error']) || is_null($response)) throw new Exception('Response error or empty: ' . @$response['error']);
|
||||
if ($response['id'] != $this->id) throw new Exception('Incorrect response id (request id: ' . $this->id . ', response id: ' . $response['id'] . ')');
|
||||
return $response['result'];
|
||||
}
|
||||
}
|
||||
@ -3,20 +3,21 @@
|
||||
// Make sure we are called from index.php
|
||||
if (!defined('SECURITY')) die('Hacking attempt');
|
||||
|
||||
// Fetch data from wallet, always run this check
|
||||
if ($bitcoin->can_connect() === true){
|
||||
$dDifficulty = $bitcoin->getdifficulty();
|
||||
$dNetworkHashrate = $bitcoin->getnetworkhashps();
|
||||
$iBlock = $bitcoin->getblockcount();
|
||||
is_int($iBlock) && $iBlock > 0 ? $sBlockHash = $bitcoin->getblockhash($iBlock) : $sBlockHash = '';
|
||||
} else {
|
||||
$dDifficulty = 1;
|
||||
$dNetworkHashrate = 1;
|
||||
$iBlock = 0;
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
|
||||
}
|
||||
|
||||
if (!$smarty->isCached('master.tpl', $smarty_cache_key)) {
|
||||
$debug->append('No cached version available, fetching from backend', 3);
|
||||
// Fetch data from wallet
|
||||
if ($bitcoin->can_connect() === true){
|
||||
$dDifficulty = $bitcoin->getdifficulty();
|
||||
$dNetworkHashrate = $bitcoin->getnetworkhashps();
|
||||
$iBlock = $bitcoin->getblockcount();
|
||||
is_int($iBlock) && $iBlock > 0 ? $sBlockHash = $bitcoin->getblockhash($iBlock) : $sBlockHash = '';
|
||||
} else {
|
||||
$dDifficulty = 1;
|
||||
$dNetworkHashrate = 1;
|
||||
$iBlock = 0;
|
||||
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
|
||||
}
|
||||
|
||||
// Top share contributors
|
||||
$aContributorsShares = $statistics->getTopContributors('shares', 15);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user