Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions bin/blocktrail
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env php
<?php

(@include_once __DIR__ . '/../vendor/autoload.php') || @include_once __DIR__ . '/../../../autoload.php';
(new \Blocktrail\SDK\Console\Application())->run();
21 changes: 21 additions & 0 deletions bin/compile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env php
<?php

(@include_once __DIR__ . '/../vendor/autoload.php') || @include_once __DIR__ . '/../../../autoload.php';

use Blocktrail\SDK\Compiler;

error_reporting(-1);
ini_set('display_errors', 1);

try {
$phar = "blocktrail.phar";

$compiler = new Compiler();
$compiler->compile($phar);

chmod($phar, 0755);
} catch (\Exception $e) {
echo 'Failed to compile phar: ['.get_class($e).'] '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine();
exit(1);
}
8 changes: 6 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@
"rych/hash_pbkdf2-compat": "~1.0",
"ramsey/array_column": "~1.1",
"dompdf/dompdf" : "0.6.*",
"endroid/qrcode": "1.5.*"
"endroid/qrcode": "1.5.*",
"symfony/console": "~2.6",
"monolog/monolog": "~1.13"
},
"require-dev": {
"phpunit/phpunit": "4.3.*",
"squizlabs/php_codesniffer": "1.*"
"squizlabs/php_codesniffer": "1.*",
"symfony/process": "~2.6",
"symfony/finder": "~2.6"
}
}
25 changes: 25 additions & 0 deletions src/BlocktrailSDK.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use BitWasp\BitcoinLib\BitcoinLib;
use BitWasp\BitcoinLib\RawTransaction;
use Blocktrail\SDK\Connection\RestClient;
use Blocktrail\SDK\Exceptions\WalletChecksumException;
use Monolog\Logger;

/**
* Class BlocktrailSDK
Expand All @@ -17,6 +19,11 @@ class BlocktrailSDK implements BlocktrailSDKInterface {
*/
protected $client;

/**
* @var Logger
*/
private $logger = null;

/**
* @var string currently only supporting; bitcoin
*/
Expand Down Expand Up @@ -135,6 +142,24 @@ public function getRestClient() {
return $this->client;
}

/**
* @return Logger
*/
public function getLogger() {
return $this->logger;
}

/**
* @param Logger $logger
* @param bool $setOnRestClient
*/
public function setLogger(Logger $logger, $setOnRestClient = true) {
$this->logger = $logger;
if ($setOnRestClient) {
$this->client->setLogger($logger);
}
}

/**
* get a single address
* @param string $address address hash
Expand Down
183 changes: 183 additions & 0 deletions src/Compiler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php

namespace Blocktrail\SDK;

use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Process;

/**
* The Compiler class compiles the `bin/blocktrail` CLI tool into a phar file
*
* based on composer compiler
*/
class Compiler {
private $version;
private $versionDate;

/**
* Compiles composer into a single phar file
*
* @throws \RuntimeException
* @param string $pharFile The full path to the file to create
*/
public function compile($pharFile = 'blocktrail.phar') {
if (file_exists($pharFile)) {
unlink($pharFile);
}

$process = new Process('git log --pretty="%H" -n1 HEAD', __DIR__);
if ($process->run() != 0) {
throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from blocktrail git repository clone and that git binary is available.');
}
$this->version = trim($process->getOutput());

$process = new Process('git log -n1 --pretty=%ci HEAD', __DIR__);
if ($process->run() != 0) {
throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from blocktrail git repository clone and that git binary is available.');
}

$date = new \DateTime(trim($process->getOutput()));
$date->setTimezone(new \DateTimeZone('UTC'));
$this->versionDate = $date->format('Y-m-d H:i:s');

$process = new Process('git describe --tags --exact-match HEAD');
if ($process->run() == 0) {
$this->version = trim($process->getOutput());
} else {
$this->version = "dev";
}

$phar = new \Phar($pharFile, 0, 'blocktrail.phar');
$phar->setSignatureAlgorithm(\Phar::SHA1);

$phar->startBuffering();

$finder = new Finder();
$finder->files()
->ignoreVCS(true)
->name('*.php')
->notName('Compiler.php')
->in(__DIR__);

foreach ($finder as $file) {
$this->addFile($phar, $file);
}

$finder = new Finder();
$finder->files()
->ignoreVCS(true)
->name('*.php')
->exclude('Test')
->exclude('Tests')
->exclude('test')
->exclude('tests')
->exclude('phpunit')
->exclude('php_codesniffer')
->in(__DIR__ . '/../vendor/');

foreach ($finder as $file) {
$this->addFile($phar, $file);
}

$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/autoload.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_namespaces.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_psr4.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_classmap.php'));
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/autoload_real.php'));
if (file_exists(__DIR__ . '/../vendor/composer/include_paths.php')) {
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/include_paths.php'));
}
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../vendor/composer/ClassLoader.php'));
$this->addBin($phar);

// Stubs
$phar->setStub($this->getStub());

$phar->stopBuffering();

// can be disabled for interoperability with systems without gzip ext
$phar->compressFiles(\Phar::GZ);

$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../LICENSE.md'), false);

unset($phar);
}

private function addFile($phar, $file, $strip = true) {
$path = strtr(str_replace(dirname(__DIR__) . DIRECTORY_SEPARATOR, '', $file->getRealPath()), '\\', '/');

$content = file_get_contents($file);
if ($strip) {
$content = $this->stripWhitespace($content);
} elseif ('LICENSE.md' === basename($file)) {
$content = "\n" . $content . "\n";
}

$phar->addFromString($path, $content);
}

private function addBin($phar) {
$content = file_get_contents(__DIR__ . '/../bin/blocktrail');
$content = preg_replace('{^#!/usr/bin/env php\s*}', '', $content);
$phar->addFromString('bin/blocktrail', $content);
}

/**
* Removes whitespace from a PHP source string while preserving line numbers.
*
* @param string $source A PHP string
* @return string The PHP string with the whitespace removed
*/
private function stripWhitespace($source) {
if (!function_exists('token_get_all')) {
return $source;
}

$output = '';
foreach (token_get_all($source) as $token) {
if (is_string($token)) {
$output .= $token;
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
$output .= str_repeat("\n", substr_count($token[1], "\n"));
} elseif (T_WHITESPACE === $token[0]) {
// reduce wide spaces
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
// normalize newlines to \n
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
// trim leading spaces
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
$output .= $whitespace;
} else {
$output .= $token[1];
}
}

return $output;
}

private function getStub() {
$stub = <<<'EOF'
#!/usr/bin/env php
<?php

// Avoid APC causing random fatal errors per https://github.com/composer/composer/issues/264
if (extension_loaded('apc') && ini_get('apc.enable_cli') && ini_get('apc.cache_by_default')) {
if (version_compare(phpversion('apc'), '3.0.12', '>=')) {
ini_set('apc.cache_by_default', 0);
} else {
fwrite(STDERR, 'Warning: APC <= 3.0.12 may cause fatal errors when running blocktrail commands.'.PHP_EOL);
fwrite(STDERR, 'Update APC, or set apc.enable_cli or apc.cache_by_default to 0 in your php.ini.'.PHP_EOL);
}
}

Phar::mapPhar('blocktrail.phar');

EOF;

return $stub . <<<'EOF'
require 'phar://blocktrail.phar/bin/blocktrail';

__HALT_COMPILER();
EOF;
}
}
32 changes: 32 additions & 0 deletions src/Connection/RestClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Event\BeforeEvent;
use GuzzleHttp\Event\CompleteEvent;
use GuzzleHttp\Message\ResponseInterface;
use GuzzleHttp\Post\PostBodyInterface;
use GuzzleHttp\Query;
Expand All @@ -19,6 +21,7 @@
use Blocktrail\SDK\Connection\Exceptions\InvalidCredentials;
use Blocktrail\SDK\Connection\Exceptions\MissingEndpoint;
use Blocktrail\SDK\Connection\Exceptions\GenericHTTPError;
use Monolog\Logger;
use Symfony\Component\HttpFoundation\Request;

/**
Expand All @@ -44,6 +47,13 @@ class RestClient {
*/
protected $verboseErrors = false;

private $timeIt = null;

/**
* @var Logger|null
*/
private $logger = null;

public function __construct($apiEndpoint, $apiVersion, $apiKey, $apiSecret) {
$this->guzzle = new Guzzle(array(
'base_url' => $apiEndpoint,
Expand All @@ -64,6 +74,19 @@ public function __construct($apiEndpoint, $apiVersion, $apiKey, $apiSecret) {

$this->apiKey = $apiKey;

$this->guzzle->getEmitter()->on('before', function (BeforeEvent $e) {
$this->timeIt = microtime(true);
if ($this->logger) {
$this->logger->debug("BEFORE {$e->getRequest()->getUrl()}");
}
});

$this->guzzle->getEmitter()->on('complete', function (CompleteEvent $e) {
if ($this->logger) {
$this->logger->debug("COMPLETE {$e->getRequest()->getUrl()} " . (microtime(true) - $this->timeIt));
}
});

$this->guzzle->getEmitter()->attach(new RequestSubscriber(
new Context([
'keys' => [$apiKey => $apiSecret],
Expand All @@ -89,6 +112,15 @@ public function setCurlDebugging($debug = true) {
$this->guzzle->setDefaultOption('debug', $debug);
}

/**
* set a logger to handle debug info
*
* @param Logger $logger
*/
public function setLogger(Logger $logger) {
$this->logger = $logger;
}

/**
* enable verbose errors
*
Expand Down
Loading