<?php
namespace Yesf\Config\Adapter;
use SplQueue;
use CIDRmatch\CIDRmatch;
use Swoole\Coroutine\Http\Client;
use Yesf\Yesf;
use Yesf\DI\Container;
use Yesf\Exception\Exception;
use Yesf\Config\ConfigTrait;
use Yesf\Config\ConfigInterface;
class Apollo implements ConfigInterface {
protected $conf;
protected $cache;
protected $last_fetch = 0;
protected $last_key = [];
public function __construct($conf) {
$this->environment = Yesf::app()->getEnvironment();
if (is_string($conf)) {
$conf = Yesf::app()->getConfig($conf, Yesf::CONF_PROJECT);
}
$this->conf = $conf;
if (!isset($this->conf['cluster'])) {
$this->conf['cluster'] = 'default';
}
if (is_string($this->conf['namespace'])) {
$this->conf['namespace'] = explode(',', $this->conf['namespace']);
}
}
protected function getClient($namespace) {
$path = sprintf('%s/configs/%s/%s/%s?releaseKey=%s',
$this->conf['path'],
$this->conf['appid'],
$this->conf['cluster'],
$this->conf['namespace'],
$this->last_key);
if ($this->conf['with_ip']) {
$cidr = Container::getInstance()->get(CIDRmatch::class);
foreach (swoole_get_local_ip() as $k => $v) {
if ($cidr->match($v, $this->conf['with_ip'])) {
$url .= '&ip=' . $v;
break;
}
}
}
$cli = new Client($this->conf['host'], $this->conf['port']);
$cli->set([
'timeout' => 1
]);
$cli->setDefer();
$cli->get($path);
return $cli;
}
protected function update($namespace, $config) {
foreach ($config as $k => $v) {
if (strpos($k, '.') === false) {
$this->cache[$namespace][$k] = $v;
continue;
}
$keys = explode('.', $k);
$total = count($keys) - 1;
$parent = &$this->cache[$namespace];
foreach ($keys as $kk => $vv) {
if ($total === $kk) {
$parent[$vv] = $v;
} else {
if (!isset($parent[$vv])) {
$parent[$vv] = [];
}
$parent = &$parent[$vv];
}
}
}
}
public function refresh($force = false) {
if (!$force && time() - $this->last_fetch < $this->config['refresh_interval']) {
return;
}
$clis = [];
foreach ($this->conf['namespace'] as $v) {
$clis[] = $this->getClient($v);
}
foreach ($clis as $cli) {
$cli->recv();
if ($cli->statusCode === 304) {
continue;
}
$res = json_decode($cli->body, true);
$ns = $res['namespaceName'];
$this->last_key[$ns] = $res['releaseKey'];
$this->update($ns, $res['configurations']);
}
$this->last_fetch = time();
}
public function get($key, $default = null) {
$this->refresh();
$keys = explode('.', $key);
$conf = $this->cache;
foreach ($keys as $v) {
if (isset($conf[$v])) {
$conf = $conf[$v];
} else {
return $default;
}
}
return $conf;
}
public function has($key) {
$this->refresh();
$keys = explode('.', $key);
$conf = $this->cache;
foreach ($keys as $v) {
if (isset($conf[$v])) {
$conf = $conf[$v];
} else {
return false;
}
}
return true;
}
}