Skip to content

Commit 2d49eef

Browse files
committed
multi client configuration
1 parent d300887 commit 2d49eef

File tree

5 files changed

+210
-13
lines changed

5 files changed

+210
-13
lines changed

GenericStatsStorageFactory.php

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,62 @@
88

99
class GenericStatsStorageFactory implements StatsStorageFactory
1010
{
11-
public function create(string $dsn): StatsStorage
11+
public function create($config): StatsStorage
1212
{
13-
$schema = (new Dsn($dsn))->getScheme();
14-
15-
switch ($schema) {
16-
case 'influxdb':
17-
return new InfluxDbStorage($dsn);
18-
case 'wamp':
19-
case 'ws':
20-
return new WampStorage($dsn);
21-
default:
22-
throw new \LogicException(sprintf('Unsupported stats storage: "%s"', $dsn));
13+
if (is_string($config)) {
14+
$config = ['dsn' => $config];
2315
}
16+
17+
if (false == is_array($config)) {
18+
throw new \InvalidArgumentException('The config must be either array or DSN string.');
19+
}
20+
21+
if (false == array_key_exists('dsn', $config)) {
22+
throw new \InvalidArgumentException('The config must have dsn key set.');
23+
}
24+
25+
$dsn = new Dsn($config['dsn']);
26+
27+
if ($storageClass = $this->findStorageClass($dsn, Resources::getKnownStorages())) {
28+
return new $storageClass(1 === count($config) ? $config['dsn'] : $config);
29+
}
30+
31+
throw new \LogicException(sprintf(
32+
'A given scheme "%s" is not supported.',
33+
$dsn->getScheme(),
34+
Resources::class
35+
));
36+
}
37+
38+
private function findStorageClass(Dsn $dsn, array $factories): ?string
39+
{
40+
$protocol = $dsn->getSchemeProtocol();
41+
42+
if ($dsn->getSchemeExtensions()) {
43+
foreach ($factories as $storageClass => $info) {
44+
if (empty($info['supportedSchemeExtensions'])) {
45+
continue;
46+
}
47+
48+
if (false == in_array($protocol, $info['schemes'], true)) {
49+
continue;
50+
}
51+
52+
$diff = array_diff($info['supportedSchemeExtensions'], $dsn->getSchemeExtensions());
53+
if (empty($diff)) {
54+
return $storageClass;
55+
}
56+
}
57+
}
58+
59+
foreach ($factories as $storageClass => $info) {
60+
if (false == in_array($protocol, $info['schemes'], true)) {
61+
continue;
62+
}
63+
64+
return $storageClass;
65+
}
66+
67+
return null;
2468
}
2569
}

Resources.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
namespace Enqueue\Monitoring;
4+
5+
6+
final class Resources
7+
{
8+
/**
9+
* @var array
10+
*/
11+
private static $knownStorages = null;
12+
13+
private function __construct()
14+
{
15+
}
16+
17+
public static function getKnownSchemes(): array
18+
{
19+
$map = self::getKnownStorages();
20+
21+
$schemes = [];
22+
foreach ($map as $storageClass => $item) {
23+
foreach ($item['schemes'] as $scheme) {
24+
$schemes[$scheme] = $storageClass;
25+
}
26+
}
27+
28+
return $schemes;
29+
}
30+
31+
public static function getKnownStorages(): array
32+
{
33+
if (null === self::$knownStorages) {
34+
$map = [];
35+
36+
$map[WampStorage::class] = [
37+
'schemes' => ['wamp', 'ws'],
38+
'supportedSchemeExtensions' => [],
39+
];
40+
41+
$map[InfluxDbStorage::class] = [
42+
'schemes' => ['influxdb'],
43+
'supportedSchemeExtensions' => [],
44+
];
45+
46+
self::$knownStorages = $map;
47+
}
48+
49+
return self::$knownStorages;
50+
}
51+
}

StatsStorageFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66

77
interface StatsStorageFactory
88
{
9-
public function create(string $dsn): StatsStorage;
9+
public function create($config): StatsStorage;
1010
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace Enqueue\Monitoring\Symfony\DependencyInjection;
4+
5+
use Enqueue\Monitoring\GenericStatsStorageFactory;
6+
use Enqueue\Monitoring\Resources;
7+
use Enqueue\Monitoring\StatsStorage;
8+
use Enqueue\Monitoring\StatsStorageFactory;
9+
use Enqueue\Symfony\DependencyInjection\FormatTransportNameTrait;
10+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
11+
use Symfony\Component\DependencyInjection\ContainerBuilder;
12+
use Symfony\Component\DependencyInjection\Reference;
13+
14+
/**
15+
* @internal
16+
*/
17+
final class MonitoringFactory
18+
{
19+
use FormatTransportNameTrait;
20+
21+
/**
22+
* @var string
23+
*/
24+
private $name;
25+
26+
public function __construct(string $name)
27+
{
28+
if (empty($name)) {
29+
throw new \InvalidArgumentException('The name could not be empty.');
30+
}
31+
32+
$this->name = $name;
33+
}
34+
35+
public function getConfiguration(string $name): ArrayNodeDefinition
36+
{
37+
$builder = new ArrayNodeDefinition($name);
38+
39+
$builder
40+
->info(sprintf('The "%s" option could accept a string DSN, an array with DSN key, or null. It accept extra options. To find out what option you can set, look at stats storage constructor doc block.', $name))
41+
->beforeNormalization()
42+
->always(function ($v) {
43+
if (is_array($v)) {
44+
if (isset($v['storage_factory_class']) && isset($v['storage_factory_service'])) {
45+
throw new \LogicException('Both options storage_factory_class and storage_factory_service are set. Please choose one.');
46+
}
47+
48+
return $v;
49+
}
50+
51+
if (is_string($v)) {
52+
return ['dsn' => $v];
53+
}
54+
55+
return $v;
56+
})
57+
->end()
58+
->ignoreExtraKeys(false)
59+
->children()
60+
->scalarNode('dsn')
61+
->cannotBeEmpty()
62+
->isRequired()
63+
->info(sprintf('The stats storage DSN. These schemes are supported: "%s".', implode('", "', array_keys(Resources::getKnownSchemes()))))
64+
->end()
65+
->scalarNode('storage_factory_service')
66+
->info(sprintf('The factory class should implement "%s" interface', StatsStorageFactory::class))
67+
->end()
68+
->scalarNode('storage_factory_class')
69+
->info(sprintf('The factory service should be a class that implements "%s" interface', StatsStorageFactory::class))
70+
->end()
71+
->end()
72+
;
73+
74+
return $builder;
75+
}
76+
77+
public function getName(): string
78+
{
79+
return $this->name;
80+
}
81+
82+
public function buildStorage(ContainerBuilder $container, array $config): void
83+
{
84+
$storageId = $this->format('storage');
85+
$storageFactoryId = $this->format('storage.factory');
86+
87+
if (isset($config['storage_factory_service'])) {
88+
$container->setAlias($storageFactoryId, $config['storage_factory_service']);
89+
} elseif (isset($config['storage_factory_class'])) {
90+
$container->register($storageFactoryId, $config['storage_factory_class']);
91+
} else {
92+
$container->register($storageFactoryId, GenericStatsStorageFactory::class);
93+
}
94+
95+
unset($config['storage_factory_service'], $config['storage_factory_class']);
96+
97+
$container->register($storageId, StatsStorage::class)
98+
->setFactory([new Reference($storageFactoryId), 'create'])
99+
->addArgument($config)
100+
;
101+
}
102+
}

Tests/GenericStatsStorageFactoryTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function testShouldCreateWampStorage()
3535
public function testShouldThrowIfStorageIsNotSupported()
3636
{
3737
$this->expectException(\LogicException::class);
38-
$this->expectExceptionMessage('Unsupported stats storage: "unsupported:"');
38+
$this->expectExceptionMessage('A given scheme "unsupported" is not supported.');
3939

4040
(new GenericStatsStorageFactory())->create('unsupported:');
4141
}

0 commit comments

Comments
 (0)