Skip to content
Merged
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
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"hyperf/db-connection": "~3.0.0",
"hyperf/di": "~3.0.0",
"hyperf/engine": "^1.3|^2.0",
"hyperf/etcd": "~3.0.0",
"hyperf/filesystem": "~3.0.0",
"hyperf/framework": "~3.0.0",
"hyperf/grpc-server": "~3.0.0",
Expand Down Expand Up @@ -57,7 +56,9 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
"hyperf/etcd": "~3.0.0",
"hyperf/ide-helper": "~3.0.0",
"hyperf/nacos": "~3.0.0",
"mockery/mockery": "^1.0",
"phpstan/phpstan": "^1.0",
"phpunit/phpunit": "^9.5",
Expand Down
6 changes: 5 additions & 1 deletion src/confd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ The confd component for Hyperf.

```shell
composer require friendsofhyperf/confd
composer require friendsofhyperf/etcd
# or
composer require friendsofhyperf/nacos
```

## Command

Fetch configs from etcd/consul and upgrade `.env`.
Fetch configs from etcd/nacos and upgrade `.env`.

```shell
php bin/hyperf.php confd:env
Expand Down Expand Up @@ -62,6 +65,7 @@ class ConfigChangedListener implements ListenerInterface
## Support

- [x] Etcd
- [x] Nacos
- [ ] Consul

## Sponsor
Expand Down
5 changes: 4 additions & 1 deletion src/confd/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"hyperf/command": "~3.0.0",
"hyperf/config-center": "~3.0.0",
"hyperf/di": "~3.0.0",
"hyperf/etcd": "~3.0.0",
"hyperf/event": "~3.0.0",
"hyperf/framework": "~3.0.0",
"hyperf/utils": "~3.0.0"
Expand All @@ -29,5 +28,9 @@
"hyperf": {
"config": "FriendsOfHyperf\\Confd\\ConfigProvider"
}
},
"suggest": {
"hyperf/nacos": "For nacos driver.",
"hyperf/etcd": "For etcd driver."
}
}
32 changes: 32 additions & 0 deletions src/confd/publish/confd.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@
'/test/foo',
],
],
'nacos' => [
'driver' => \FriendsOfHyperf\Confd\Driver\Nacos::class,
'client' => [
'host' => '127.0.0.1',
'port' => 8848,
'username' => 'nacos',
'password' => 'nacos',
'guzzle' => [
'config' => ['timeout' => 3, 'connect_timeout' => 1],
],
],
'listener_config' => [
'mysql' => [
'tenant' => 'framework',
'data_id' => 'mysql',
'group' => 'DEFAULT_GROUP',
'type' => 'json',
],
],
'mapping' => [
'mysql' => ['charset' => 'DB_CHARSET'],
'redis' => ['port' => 'REDIS_PORT'],
],
'watches' => [
'test' => [
'tenant' => 'framework',
'data_id' => 'test',
'group' => 'DEFAULT_GROUP',
'type' => 'text',
],
],
],
],

'env_path' => BASE_PATH . '/.env',
Expand Down
2 changes: 1 addition & 1 deletion src/confd/src/Driver/Etcd.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public function getChanges(): array
->filter(fn ($kv) => in_array($kv['key'], $watches))
->mapWithKeys(fn ($kv) => [$kv['key'] => $kv['value']])
->toArray();
$changes = array_diff($values, $this->origins);
$changes = array_diff_assoc($values, $this->origins);

if (! $this->origins) { // Return [] when first run.
return tap([], fn () => $this->origins = $values);
Expand Down
143 changes: 143 additions & 0 deletions src/confd/src/Driver/Nacos.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

declare(strict_types=1);
/**
* This file is part of friendsofhyperf/components.
*
* @link https://github.com/friendsofhyperf/components
* @document https://github.com/friendsofhyperf/components/blob/3.x/README.md
* @contact huangdijia@gmail.com
*/
namespace FriendsOfHyperf\Confd\Driver;

use Hyperf\Contract\ConfigInterface;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Nacos\Application;
use Hyperf\Nacos\Config;
use Hyperf\Utils\Codec\Json;
use Hyperf\Utils\Codec\Xml;
use Psr\Container\ContainerInterface;

class Nacos implements DriverInterface
{
private Application $client;

private array $origins = [];

public function __construct(private ContainerInterface $container, private ConfigInterface $config, private StdoutLoggerInterface $logger)
{
$this->client = make(Application::class, [
'config' => $this->pendingNacosConfig(),
]);
}

/**
* get all listener config from nacos server.
*/
public function fetch(): array
{
$listener = $this->config->get('confd.drivers.nacos.listener_config', []);
$mapping = (array) $this->config->get('confd.drivers.nacos.mapping', []);

$config = [];
foreach ($listener as $key => $item) {
$config = collect($this->pullConfig($item))
->filter(fn ($item, $k) => isset($mapping[$key][$k]))
->mapWithKeys(fn ($item, $k) => [$mapping[$key][$k] => is_array($item) ? implode(',', $item) : $item])
->merge($config)
->toArray();
}
return $config;
}

/**
* check watch config is chaged.
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Hyperf\Utils\Exception\InvalidArgumentException
*/
public function getChanges(): array
{
$watches = (array) $this->config->get('confd.drivers.nacos.watches', []);

$config = [];
foreach ($watches as $item) {
$configKey = sprintf('%s.%s.%s', $item['group'], $item['tenant'] ?? 'default', $item['data_id']);
$config = collect($this->pullConfig($item))
->mapWithKeys(fn ($value) => [$configKey => is_array($value) ? implode(',', $value) : $value])
->merge($config)
->toArray();
}

if (! $this->origins) { // Return [] when first run.
return tap([], fn () => $this->origins = $config);
}

$changes = array_diff_assoc($config, $this->origins);

return tap($changes, function ($changes) use ($config) {
if ($changes) {
$this->logger->debug('[confd#nacos] Config changed.');
}

$this->origins = $config;
});
}

protected function decode(string $body, ?string $type = null): mixed
{
$type = strtolower((string) $type);
switch ($type) {
case 'json':
return Json::decode($body);
case 'yml':
case 'yaml':
return yaml_parse($body);
case 'xml':
return Xml::toArray($body);
default:
return $body;
}
}

/**
* get nacos client config from confd setting.
*/
protected function pendingNacosConfig(): Config
{
$clientConfig = $this->config->get('confd.drivers.nacos.client', []);

if (! empty($clientConfig['uri'])) {
$baseUri = $clientConfig['uri'];
} else {
$baseUri = sprintf('http://%s:%d', $clientConfig['host'] ?? '127.0.0.1', $clientConfig['port'] ?? 8848);
}

return new Config([
'base_uri' => $baseUri,
'username' => $clientConfig['username'] ?? null,
'password' => $clientConfig['password'] ?? null,
'guzzle_config' => $clientConfig['guzzle']['config'] ?? null,
]);
}

/**
* pull fresh config from nacos server.
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Hyperf\Utils\Exception\InvalidArgumentException
*/
protected function pullConfig(array $listenerConfig): array|string
{
$dataId = $listenerConfig['data_id'];
$group = $listenerConfig['group'];
$tenant = $listenerConfig['tenant'] ?? null;
$type = $listenerConfig['type'] ?? null;
$response = $this->client->config->get($dataId, $group, $tenant);

if ($response->getStatusCode() !== 200) {
$this->logger->error(sprintf('The config of %s.%s.%s read failed from Nacos.', $group, $tenant, $dataId));
return [];
}

return $this->decode((string) $response->getBody(), $type);
}
}