Merge branch 'master' into 2.1-merge

This commit is contained in:
李铭昕 2020-11-27 19:01:03 +08:00
commit c405f177a7
32 changed files with 94 additions and 659 deletions

View File

@ -3,6 +3,13 @@
## Added
- [#2857](https://github.com/hyperf/hyperf/pull/2857) Support Consul ACL Token for Service Governance.
- [#2870](https://github.com/hyperf/hyperf/pull/2870) The publish option of `ConfigProvider` allows publish directory.
- [#2875](https://github.com/hyperf/hyperf/pull/2875) Added option `no-restart` for watcher.
## Fixed
- [#2874](https://github.com/hyperf/hyperf/pull/2874) Fixed `scan.ignore_annotations` does not works when using watcher.
- [#2878](https://github.com/hyperf/hyperf/pull/2878) Fixed config of nsqd does not works.
## Changed
@ -10,6 +17,7 @@
## Optimized
- [#2785](https://github.com/hyperf/hyperf/pull/2785) Optimized code for watcher.
- [#2861](https://github.com/hyperf/hyperf/pull/2861) Optimized guzzle coroutine handler which throw exception when the status code below zero.
- [#2868](https://github.com/hyperf/hyperf/pull/2868) Optimized code for guzzle sink, which support resource not only string.

View File

@ -104,7 +104,6 @@
"hyperf/di": "self.version",
"hyperf/dispatcher": "self.version",
"hyperf/elasticsearch": "self.version",
"hyperf/encryption": "self.version",
"hyperf/etcd": "self.version",
"hyperf/event": "self.version",
"hyperf/exception-handler": "self.version",
@ -181,7 +180,6 @@
"Hyperf\\Di\\": "src/di/src/",
"Hyperf\\Dispatcher\\": "src/dispatcher/src/",
"Hyperf\\Elasticsearch\\": "src/elasticsearch/src/",
"Hyperf\\Encryption\\": "src/encryption/src/",
"Hyperf\\Etcd\\": "src/etcd/src/",
"Hyperf\\Event\\": "src/event/src/",
"Hyperf\\ExceptionHandler\\": "src/exception-handler/src/",
@ -264,7 +262,6 @@
"HyperfTest\\Di\\": "src/di/tests/",
"HyperfTest\\Dispatcher\\": "src/dispatcher/tests/",
"HyperfTest\\Elasticsearch\\": "src/elasticsearch/tests/",
"HyperfTest\\Encryption\\": "src/encryption/tests/",
"HyperfTest\\Etcd\\": "src/etcd/tests/",
"HyperfTest\\Event\\": "src/event/tests/",
"HyperfTest\\ExceptionHandler\\": "src/exception-handler/tests/",
@ -341,7 +338,6 @@
"Hyperf\\Devtool\\ConfigProvider",
"Hyperf\\Di\\ConfigProvider",
"Hyperf\\Dispatcher\\ConfigProvider",
"Hyperf\\Encryption\\ConfigProvider",
"Hyperf\\Etcd\\ConfigProvider",
"Hyperf\\Event\\ConfigProvider",
"Hyperf\\ExceptionHandler\\ConfigProvider",

View File

@ -351,6 +351,7 @@ try{
<?php
use Hyperf\DbConnection\Db;
use Hyperf\Utils\Arr;
use App\Model\Book;
// 启用 SQL 数据记录功能

View File

@ -1,37 +0,0 @@
# 加密解密
[hyperf/encryption](https://github.com/hyperf/encryption) 借鉴于 `Laravel Encryption` 组件,十分感谢 `Laravel` 开发组对 `PHP` 社区的贡献。
## 简介
`Encryption` 是基于 `OpenSSL` 实现加密解密组件。
## 配置
加密器可以根据实际情况,配置多组 `key``cipher`
```php
<?php
return [
'default' => [
'key' => 'Hyperf',
'cipher' => 'AES-128-CBC',
],
];
```
## 使用
```php
<?php
use Hyperf\Utils\ApplicationContext;
use Hyperf\Encryption\Contract\EncrypterInterface;
$input = 'Hello Word.';
$container = ApplicationContext::getContainer();
$encrypter = $container->get(EncrypterInterface::class);
$encrypt = $encrypter->encrypt($input);
$raw = $encrypter->decrypt($encrypt);
```

View File

@ -4,8 +4,10 @@
| 版本 | 状态 | 积极支持截止时间 | 安全维护截止时间 | 发布或预计发布时间 |
| ---- | -------- | ---------------- | ---------------- | ------------------ |
| 2.0 | 积极支持中 | / | / | 2020-06-22 |
| 1.1 | 安全维护中 | 2020-06-23 | 2020-12-31 | |
| 3.0 | 研发中 | / | / | 2021-06-20 |
| 2.1 | Beta版试用中 | / | / | 2020-12-31 |
| 2.0 | 积极支持中 | 2020-12-31 | 2021-06-30 | 2020-06-22 |
| 1.1 | 安全维护中 | 2020-06-23 | 2020-12-31 | 2019-10-08 |
| 1.0 | 停止维护 | 2019-10-08 | 2019-12-31 | 2019-06-20 |
* 积极支持将包含常规迭代周期的 BUG 修复、安全问题修复、功能迭代和功能新增;

View File

@ -116,7 +116,6 @@
* [Watcher](zh-cn/watcher.md)
* [开发者工具](zh-cn/devtool.md)
* [Swoole Tracker](zh-cn/swoole-tracker.md)
* [加密解密](zh-cn/encryption.md)
* 应用部署

View File

@ -25,7 +25,6 @@
<directory suffix="Test.php">./src/di/tests</directory>
<directory suffix="Test.php">./src/dispatcher/tests</directory>
<directory suffix="Test.php">./src/elasticsearch/tests</directory>
<directory suffix="Test.php">./src/encryption/tests</directory>
<directory suffix="Test.php">./src/etcd/tests</directory>
<directory suffix="Test.php">./src/event/tests</directory>
<directory suffix="Test.php">./src/exception-handler/tests</directory>
@ -39,6 +38,7 @@
<directory suffix="Test.php">./src/logger/tests</directory>
<directory suffix="Test.php">./src/metric/tests</directory>
<directory suffix="Test.php">./src/model-cache/tests</directory>
<directory suffix="Test.php">./src/nsq/tests</directory>
<directory suffix="Test.php">./src/paginator/tests</directory>
<directory suffix="Test.php">./src/pool/tests</directory>
<directory suffix="Test.php">./src/process/tests</directory>
@ -81,7 +81,6 @@
<directory suffix=".php">./src/di/src</directory>
<directory suffix=".php">./src/dispatcher/src</directory>
<directory suffix=".php">./src/elasticsearch/src</directory>
<directory suffix=".php">./src/encryption/src</directory>
<directory suffix=".php">./src/event/src</directory>
<directory suffix=".php">./src/grpc-client/src</directory>
<directory suffix=".php">./src/guzzle/src</directory>

View File

@ -14,6 +14,7 @@ namespace Hyperf\Devtool;
use Hyperf\Command\Annotation\Command;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Composer;
use Hyperf\Utils\Filesystem\Filesystem;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@ -35,9 +36,15 @@ class VendorPublishCommand extends SymfonyCommand
*/
protected $force = false;
public function __construct()
/**
* @var Filesystem
*/
protected $filesystem;
public function __construct(Filesystem $filesystem)
{
parent::__construct('vendor:publish');
$this->filesystem = $filesystem;
}
protected function configure()
@ -110,15 +117,20 @@ class VendorPublishCommand extends SymfonyCommand
$source = $item['source'];
$destination = $item['destination'];
if (! $this->force && file_exists($destination)) {
if (! $this->force && $this->filesystem->exists($destination)) {
$this->output->writeln(sprintf('<fg=red>[%s] already exists.</>', $destination));
continue;
}
if (! file_exists(dirname($destination))) {
mkdir(dirname($destination), 0755, true);
if (! $this->filesystem->exists($dirname = dirname($destination))) {
$this->filesystem->makeDirectory($dirname, 0755, true);
}
if ($this->filesystem->isDirectory($source)) {
$this->filesystem->copyDirectory($source, $destination);
} else {
$this->filesystem->copy($source, $destination);
}
copy($source, $destination);
$this->output->writeln(sprintf('<fg=green>[%s] publishes [%s] successfully.</>', $package, $id));
}

View File

@ -1,2 +0,0 @@
/tests export-ignore
/.github export-ignore

View File

@ -1,25 +0,0 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Release
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false

View File

@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) Taylor Otwell
Copyright (c) Hyperf
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,36 +0,0 @@
{
"name": "hyperf/encryption",
"type": "library",
"license": "MIT",
"keywords": [
"php",
"hyperf",
"encryption"
],
"description": "",
"autoload": {
"psr-4": {
"Hyperf\\Encryption\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"HyperfTest\\Encryption\\": "tests/"
}
},
"require": {
"php": ">=7.2",
"ext-json": "*",
"ext-openssl": "*",
"hyperf/contract": "~2.0.0",
"psr/container": "^1.0"
},
"config": {
"sort-packages": true
},
"extra": {
"hyperf": {
"config": "Hyperf\\Encryption\\ConfigProvider"
}
}
}

View File

@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'key' => 'Hyperf',
'cipher' => 'AES-128-CBC',
],
];

View File

@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption;
use Hyperf\Encryption\Contract\EncrypterInterface;
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => [
EncrypterInterface::class => EncrypterInvoker::class,
],
'publish' => [
[
'id' => 'config',
'description' => 'The config for encryption.',
'source' => __DIR__ . '/../publish/encryption.php',
'destination' => BASE_PATH . '/config/autoload/encryption.php',
],
],
];
}
}

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption\Contract;
use RuntimeException;
interface EncrypterInterface
{
/**
* Encrypt the given value.
*
* @param mixed $value
* @throws RuntimeException
*/
public function encrypt($value, bool $serialize = true): string;
/**
* Decrypt the given value.
*
* @throws RuntimeException
* @return mixed
*/
public function decrypt(string $payload, bool $unserialize = true);
}

View File

@ -1,229 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption;
use Hyperf\Encryption\Contract\EncrypterInterface;
use Hyperf\Encryption\Exception\DecryptException;
use Hyperf\Encryption\Exception\EncryptException;
use Hyperf\Encryption\Exception\InvalidArgumentException;
class Encrypter implements EncrypterInterface
{
/**
* The encryption key.
*
* @var string
*/
protected $key;
/**
* The algorithm used for encryption.
*
* @var string
*/
protected $cipher;
public function __construct(string $key, string $cipher = 'AES-128-CBC')
{
if (empty($key)) {
throw new InvalidArgumentException('Encrypter key Not Set');
}
if (! in_array(strtolower($cipher), openssl_get_cipher_methods())) {
throw new InvalidArgumentException('Encrypter ciphers Not supported');
}
$this->key = $key;
$this->cipher = $cipher;
}
/**
* Encrypt the given value.
*
* @param mixed $value
* @throws \Exception
*/
public function encrypt($value, bool $serialize = true): string
{
$iv = random_bytes(openssl_cipher_iv_length($this->cipher));
// First we will encrypt the value using OpenSSL. After this is encrypted we
// will proceed to calculating a MAC for the encrypted value so that this
// value can be verified later as not having been changed by the users.
$value = \openssl_encrypt(
$serialize ? serialize($value) : $value,
$this->cipher,
$this->key,
0,
$iv
);
if ($value === false) {
throw new EncryptException('Could not encrypt the data.');
}
// Once we get the encrypted value we'll go ahead and base64_encode the input
// vector and create the MAC for the encrypted value so we can then verify
// its authenticity. Then, we'll JSON the data into the "payload" array.
$mac = $this->hash($iv = base64_encode($iv), $value);
$json = json_encode(compact('iv', 'value', 'mac'), JSON_UNESCAPED_SLASHES);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new EncryptException('Could not encrypt the data.');
}
return base64_encode($json);
}
/**
* Encrypt a string without serialization.
*
* @param string $value
* @throws \Exception
* @return string
*/
public function encryptString($value)
{
return $this->encrypt($value, false);
}
/**
* Decrypt the given value.
*
* @return mixed
*/
public function decrypt(string $payload, bool $unserialize = true)
{
$payload = $this->getJsonPayload($payload);
$iv = base64_decode($payload['iv']);
// Here we will decrypt the value. If we are able to successfully decrypt it
// we will then unserialize it and return it out to the caller. If we are
// unable to decrypt this value we will throw out an exception message.
$decrypted = \openssl_decrypt(
$payload['value'],
$this->cipher,
$this->key,
0,
$iv
);
if ($decrypted === false) {
throw new DecryptException('Could not decrypt the data.');
}
return $unserialize ? unserialize($decrypted) : $decrypted;
}
/**
* Decrypt the given string without unserialization.
*
* @param string $payload
* @return string
*/
public function decryptString($payload)
{
return $this->decrypt($payload, false);
}
/**
* Get the encryption key.
*
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* Create a MAC for the given value.
*
* @param string $iv
* @param mixed $value
* @return string
*/
protected function hash($iv, $value)
{
return hash_hmac('sha256', $iv . $value, $this->key);
}
/**
* Get the JSON array from the given payload.
*
* @param string $payload
* @return array
*/
protected function getJsonPayload($payload)
{
$payload = json_decode(base64_decode($payload), true);
// If the payload is not valid JSON or does not have the proper keys set we will
// assume it is invalid and bail out of the routine since we will not be able
// to decrypt the given value. We'll also check the MAC for this encryption.
if (! $this->validPayload($payload)) {
throw new DecryptException('The payload is invalid.');
}
if (! $this->validMac($payload)) {
throw new DecryptException('The MAC is invalid.');
}
return $payload;
}
/**
* Verify that the encryption payload is valid.
*
* @param mixed $payload
* @return bool
*/
protected function validPayload($payload)
{
return is_array($payload) && isset($payload['iv'], $payload['value'], $payload['mac']) &&
strlen(base64_decode($payload['iv'], true)) === openssl_cipher_iv_length($this->cipher);
}
/**
* Determine if the MAC for the given payload is valid.
*
* @return bool
*/
protected function validMac(array $payload)
{
$calculated = $this->calculateMac($payload, $bytes = random_bytes(16));
return hash_equals(
hash_hmac('sha256', $payload['mac'], $bytes, true),
$calculated
);
}
/**
* Calculate the hash of the given payload.
*
* @param array $payload
* @param string $bytes
* @return string
*/
protected function calculateMac($payload, $bytes)
{
return hash_hmac(
'sha256',
$this->hash($payload['iv'], $payload['value']),
$bytes,
true
);
}
}

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Encryption\Contract\EncrypterInterface;
use Psr\Container\ContainerInterface;
class EncrypterFactory
{
/**
* @var ConfigInterface
*/
protected $config;
public function __construct(ContainerInterface $container)
{
$this->config = $container->get(ConfigInterface::class);
}
public function get(string $name): EncrypterInterface
{
$encryption = $this->config->get('encryption.' . $name, []);
$key = $encryption['key'] ?? '';
$cipher = $encryption['cipher'] ?? 'AES-128-CBC';
return new Encrypter($key, $cipher);
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption;
use Psr\Container\ContainerInterface;
class EncrypterInvoker
{
public function __invoke(ContainerInterface $container)
{
$factory = $container->get(EncrypterFactory::class);
return $factory->get('default');
}
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption\Exception;
class DecryptException extends \RuntimeException
{
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption\Exception;
class EncryptException extends \RuntimeException
{
}

View File

@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Encryption\Exception;
class InvalidArgumentException extends \InvalidArgumentException
{
}

View File

@ -1,74 +0,0 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace HyperfTest\Encryption;
use Hyperf\Config\Config;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Encryption\Contract\EncrypterInterface;
use Hyperf\Encryption\EncrypterFactory;
use Hyperf\Encryption\EncrypterInvoker;
use Hyperf\Utils\ApplicationContext;
use Mockery;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
/**
* @internal
* @coversNothing
*/
class EncrypterTest extends TestCase
{
protected function tearDown(): void
{
Mockery::close();
}
public function mockContainer(): ContainerInterface
{
$container = Mockery::mock(ContainerInterface::class);
ApplicationContext::setContainer($container);
$config = new Config([
'encryption' => [
'default' => [
'key' => '123456',
'cipher' => 'AES-256-CBC',
],
],
]);
$container->shouldReceive('get')->with(ConfigInterface::class)->andReturn($config);
$container->shouldReceive('get')->with(EncrypterFactory::class)->andReturnUsing(function () use ($container) {
return new EncrypterFactory($container);
});
$container->shouldReceive('get')->with(EncrypterInterface::class)->andReturnUsing(function () use ($container) {
return (new EncrypterInvoker())($container);
});
return $container;
}
public function testEncodeString()
{
$input = 'Hello Word.';
$container = $this->mockContainer();
$encrypter = $container->get(EncrypterInterface::class);
$encrypt = $encrypter->encryptString($input);
$this->assertSame($input, $encrypter->decryptString($encrypt));
}
public function testEncodeObject()
{
$input = range(1, 3);
$container = $this->mockContainer();
$encrypter = $container->get(EncrypterInterface::class);
$encrypt = $encrypter->encrypt($input);
$this->assertSame($input, $encrypter->decrypt($encrypt));
}
}

View File

@ -22,9 +22,9 @@ class Client implements ClientInterface
*/
protected $options = [];
public function __construct(ConfigInterface $config)
public function __construct(ConfigInterface $config, string $pool = 'default')
{
$nsq = $config->get('nsq', []);
$nsq = $config->get('nsq.' . $pool, []);
$options = $nsq['nsqd']['options'] ?? [];
if (! isset($options['base_uri'])) {
$options['base_uri'] = sprintf('http://%s:%s', $nsq['host'] ?? '127.0.0.1', $nsq['nsqd']['port'] ?? 4151);

View File

@ -61,7 +61,7 @@ class ConsumerManagerTest extends TestCase
$hasRegistered = true;
/** @var AbstractConsumer $consumer */
$consumer = $item->getConsumer();
$this->assertTrue($item->isEnable());
$this->assertTrue($item->isEnable(new \stdClass()));
$this->assertSame($name, $consumer->getName());
$this->assertSame($channel, $consumer->getChannel());
$this->assertSame($topic, $consumer->getTopic());
@ -96,7 +96,7 @@ class ConsumerManagerTest extends TestCase
foreach (ProcessManager::all() as $item) {
if (method_exists($item, 'getConsumer')) {
/* @var AbstractConsumer $consumer */
$this->assertFalse($item->isEnable());
$this->assertFalse($item->isEnable(new \stdClass()));
break;
}
}
@ -123,7 +123,7 @@ class ConsumerManagerTest extends TestCase
$manager->run();
foreach (ProcessManager::all() as $item) {
if (method_exists($item, 'getConsumer') && ($item->getConsumer() instanceof DisabledDemoConsumer)) {
$this->assertFalse($item->isEnable());
$this->assertFalse($item->isEnable(new \stdClass()));
break;
}
}

View File

@ -11,7 +11,7 @@ declare(strict_types=1);
*/
namespace HyperfTest\Nsq;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Config\Config;
use Hyperf\Guzzle\CoroutineHandler;
use Hyperf\Nsq\Nsqd\Client;
use HyperfTest\Nsq\Stub\CoroutineHandlerStub;
@ -31,9 +31,7 @@ class HttpClientTest extends TestCase
public function testHttpClientWithEmptyConfig()
{
$config = Mockery::mock(ConfigInterface::class);
$config->shouldReceive('get')->with('nsq', [])->andReturn([]);
$config = new Config([]);
$client = new Client($config);
$this->assertSame('http://127.0.0.1:4151', $client->getOptions()['base_uri']);
$this->assertInstanceOf(CoroutineHandler::class, $client->getOptions()['handler']);
@ -41,11 +39,14 @@ class HttpClientTest extends TestCase
public function testHttpClientWithHost()
{
$config = Mockery::mock(ConfigInterface::class);
$config->shouldReceive('get')->with('nsq', [])->andReturn([
'host' => '192.168.1.1',
'nsqd' => [
'port' => 14151,
$config = new Config([
'nsq' => [
'default' => [
'host' => '192.168.1.1',
'nsqd' => [
'port' => 14151,
],
],
],
]);
@ -56,12 +57,15 @@ class HttpClientTest extends TestCase
public function testHttpClientWithOptions()
{
$config = Mockery::mock(ConfigInterface::class);
$config->shouldReceive('get')->with('nsq', [])->andReturn([
'nsqd' => [
'options' => [
'base_uri' => 'https://nsq.hyperf.io',
'handler' => new CoroutineHandlerStub(),
$config = new Config([
'nsq' => [
'default' => [
'nsqd' => [
'options' => [
'base_uri' => 'https://nsq.hyperf.io',
'handler' => new CoroutineHandlerStub(),
],
],
],
],
]);

View File

@ -435,7 +435,7 @@ class Filesystem
// As we spin through items, we will check to see if the current file is actually
// a directory or a file. When it is actually a directory we will need to call
// back into this function recursively to keep copying these nested folders.
$target = $destination . '/' . $item->getBasename();
$target = $destination . DIRECTORY_SEPARATOR . $item->getBasename();
if ($item->isDir()) {
$path = $item->getPathname();

View File

@ -29,6 +29,7 @@ class WatchCommand extends Command
$this->setDescription('watch command');
$this->addOption('file', 'F', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, '', []);
$this->addOption('dir', 'D', InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, '', []);
$this->addOption('no-restart', 'N', InputOption::VALUE_NONE, 'Whether no need to restart server');
}
public function handle()
@ -36,6 +37,7 @@ class WatchCommand extends Command
$option = make(Option::class, [
'dir' => $this->input->getOption('dir'),
'file' => $this->input->getOption('file'),
'restart' => ! $this->input->getOption('no-restart'),
]);
$watcher = make(Watcher::class, [

View File

@ -92,12 +92,12 @@ class FindDriver implements DriverInterface
$dest = implode(' ', $targets);
$ret = System::exec($this->getBin() . ' ' . $dest . ' -mmin ' . $minutes . ' -type f -print');
if ($ret['code'] === 0 && strlen($ret['output'])) {
$stdout = $ret['output'];
$stdout = trim($ret['output']);
$lineArr = explode(PHP_EOL, $stdout);
foreach ($lineArr as $line) {
$pathName = $line;
$modifyTime = fileatime($pathName);
$modifyTime = filemtime($pathName);
// modifyTime less than or equal to startTime continue
if ($modifyTime <= $this->startTime) {
continue;

View File

@ -69,7 +69,9 @@ class FswatchDriver implements DriverInterface
$cmd = 'fswatch ';
if (! $this->isDarwin) {
$cmd .= '-m inotify_monitor ';
$cmd .= ' -m inotify_monitor';
$cmd .= " -E --format '%p' -r ";
$cmd .= ' --event Created --event Updated --event Removed --event Renamed ';
}
return $cmd . implode(' ', $dir) . ' ' . implode(' ', $file);

View File

@ -46,7 +46,12 @@ class Option
*/
protected $scanInterval = 2000;
public function __construct(ConfigInterface $config, array $dir, array $file)
/**
* @var bool
*/
protected $restart = true;
public function __construct(ConfigInterface $config, array $dir, array $file, bool $restart = true)
{
$options = $config->get('watcher', []);
@ -59,6 +64,7 @@ class Option
$this->watchDir = array_unique(array_merge($this->watchDir, $dir));
$this->watchFile = array_unique(array_merge($this->watchFile, $file));
$this->restart = $restart;
}
public function getDriver(): string
@ -90,4 +96,9 @@ class Option
{
return $this->scanInterval > 0 ? $this->scanInterval : 2000;
}
public function isRestart(): bool
{
return $this->restart;
}
}

View File

@ -68,8 +68,8 @@ class Process
$this->file = $file;
$this->ast = new Ast();
$this->reflection = new BetterReflection();
$this->config = $this->initScanConfig();
$this->reader = new AnnotationReader();
$this->config = ScanConfig::instance('/');
$this->filesystem = new Filesystem();
}
@ -177,4 +177,16 @@ class Process
}
return $meta;
}
protected function initScanConfig(): ScanConfig
{
$config = ScanConfig::instance(BASE_PATH . '/config/');
foreach ($config->getIgnoreAnnotations() as $annotation) {
AnnotationReader::addGlobalIgnoredName($annotation);
}
foreach ($config->getGlobalImports() as $alias => $annotation) {
AnnotationReader::addGlobalImports($alias, $annotation);
}
return $config;
}
}

View File

@ -133,6 +133,9 @@ class Watcher
$ret = System::exec($this->option->getBin() . ' vendor/hyperf/watcher/collector-reload.php ' . $file);
if ($ret['code'] === 0) {
$this->output->writeln('Class reload success.');
} else {
$this->output->writeln('Class reload failed.');
$this->output->writeln($ret['output'] ?? '');
}
$result[] = $file;
}
@ -147,6 +150,9 @@ class Watcher
public function restart($isStart = true)
{
if (! $this->option->isRestart()) {
return;
}
$file = $this->config->get('server.settings.pid_file');
if (empty($file)) {
throw new FileNotFoundException('The config of pid_file is not found.');