diff --git a/Cargo.lock b/Cargo.lock
index 8c077769..68bd673f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1511,9 +1511,9 @@ dependencies = [
[[package]]
name = "nextcloud-config-parser"
-version = "0.13.1"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "083fbacd3a186bf4d1dde2cb80fc4b5a6656348ef7121eea202369e5f8214578"
+checksum = "e2091417dbccebb684aa4682a1448517d0fc73d4b3fbe6b072f61d306e2ac96c"
dependencies = [
"form_urlencoded",
"itertools",
diff --git a/Cargo.toml b/Cargo.toml
index 81c57d9d..b04273af 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,7 @@ rand = { version = "0.8.5", features = ["small_rng"] }
ahash = "0.8.11"
flexi_logger = { version = "0.29.8", features = ["colors"] }
tokio-stream = { version = "0.1.17", features = ["net"] }
-nextcloud-config-parser = "0.13.1"
+nextcloud-config-parser = "0.14.0"
url = "2.5.4"
clap = { version = "4.5.26", features = ["derive"] }
sd-notify = { version = "0.4.3", optional = true }
diff --git a/README.md b/README.md
index 160ec494..05958f56 100644
--- a/README.md
+++ b/README.md
@@ -146,7 +146,17 @@ Note that Nextcloud loads all files matching `*.config.php` in the config direct
file.
You can enable this same behavior by passing the `--glob-config` option.
-#####
+
+Using a separate redis instance for the push server
+
+
+You can optionally use a different redis instance for communications between the Nextcloud server and the push daemon.
+
+This allows spreading moving the load away from the normal redis usage or use a redis setup more optimized for the specific usage (`PUBSUB` traffic instead of cache storage).
+
+You can configure this by setting the `notify_push_redis` config option in the `config.php` of the Nextcloud server, this accepts the same options as the normal redis configurations.
+
+
Connecting to redis over TLS
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index f2d891b0..a389f683 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -8,12 +8,12 @@
namespace OCA\NotifyPush\AppInfo;
-use OC\RedisFactory;
use OCA\NotifyPush\Capabilities;
use OCA\NotifyPush\CSPListener;
use OCA\NotifyPush\Listener;
use OCA\NotifyPush\Queue\IQueue;
use OCA\NotifyPush\Queue\NullQueue;
+use OCA\NotifyPush\Queue\PushRedisFactory;
use OCA\NotifyPush\Queue\RedisQueue;
use OCP\Activity\IManager;
use OCP\AppFramework\App;
@@ -41,10 +41,11 @@ public function register(IRegistrationContext $context): void {
$context->registerCapability(Capabilities::class);
$context->registerService(IQueue::class, function (ContainerInterface $c) {
- /** @var RedisFactory $redisFactory */
- $redisFactory = $c->get(RedisFactory::class);
- if ($redisFactory->isAvailable()) {
- return new RedisQueue($redisFactory->getInstance());
+ /** @var PushRedisFactory $factory */
+ $factory = $c->get(PushRedisFactory::class);
+ $redis = $factory->getRedis();
+ if ($redis) {
+ return new RedisQueue($redis);
} else {
return new NullQueue();
}
diff --git a/lib/Queue/PushRedisFactory.php b/lib/Queue/PushRedisFactory.php
new file mode 100644
index 00000000..8d91ff85
--- /dev/null
+++ b/lib/Queue/PushRedisFactory.php
@@ -0,0 +1,102 @@
+
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\NotifyPush\Queue;
+
+use OC\RedisFactory;
+use OCP\IConfig;
+
+class PushRedisFactory {
+ private $instance = null;
+ private IConfig $config;
+ private RedisFactory $redisFactory;
+
+ public function __construct(
+ IConfig $config,
+ RedisFactory $redisFactory,
+ ) {
+ $this->config = $config;
+ $this->redisFactory = $redisFactory;
+ }
+
+ /**
+ * @return \Redis|\RedisCluster|null
+ * @throws \Exception
+ */
+ public function getRedis() {
+ if ($this->instance) {
+ return $this->instance;
+ }
+ if ($this->config->getSystemValue('notify_push_redis', []) !== []) {
+ return $this->getSeparateRedis();
+ } elseif ($this->redisFactory->isAvailable()) {
+ return $this->redisFactory->getInstance();
+ } else {
+ return null;
+ }
+ }
+
+ private function getSeparateRedis(): \Redis {
+ $config = $this->config->getSystemValue('notify_push_redis', []);
+ $timeout = $config['timeout'] ?? 0.0;
+ $readTimeout = $config['read_timeout'] ?? 0.0;
+
+ $auth = null;
+ if (isset($config['password']) && (string)$config['password'] !== '') {
+ if (isset($config['user']) && (string)$config['user'] !== '') {
+ $auth = [$config['user'], $config['password']];
+ } else {
+ $auth = $config['password'];
+ }
+ }
+
+ $persistent = $this->config->getSystemValue('notify_push_redis.persistent', true);
+
+ $redis = new \Redis();
+
+ $host = $config['host'] ?? '127.0.0.1';
+ $port = $config['port'] ?? ($host[0] !== '/' ? 6379 : null);
+
+ // Support for older phpredis versions not supporting connectionParameters
+ if (isset($config['ssl_context'])) {
+ // Non-clustered redis requires connection parameters to be wrapped inside `stream`
+ $connectionParameters = [
+ 'stream' => $config['ssl_context']
+ ];
+ if ($persistent) {
+ /**
+ * even though the stubs and documentation don't want you to know this,
+ * pconnect does have the same $connectionParameters argument connect has
+ *
+ * https://github.com/phpredis/phpredis/blob/0264de1824b03fb2d0ad515b4d4ec019cd2dae70/redis.c#L710-L730
+ *
+ * @psalm-suppress TooManyArguments
+ */
+ $redis->pconnect($host, $port, $timeout, null, 0, $readTimeout, $connectionParameters);
+ } else {
+ $redis->connect($host, $port, $timeout, null, 0, $readTimeout, $connectionParameters);
+ }
+ } else {
+ if ($persistent) {
+ $redis->pconnect($host, $port, $timeout, null, 0, $readTimeout);
+ } else {
+ $redis->connect($host, $port, $timeout, null, 0, $readTimeout);
+ }
+ }
+
+ if ($auth !== null) {
+ $redis->auth($auth);
+ }
+
+ if (isset($config['dbindex'])) {
+ $redis->select($config['dbindex']);
+ }
+
+ return $redis;
+ }
+}
diff --git a/src/config/nc.rs b/src/config/nc.rs
index f5db191b..ca2bf013 100644
--- a/src/config/nc.rs
+++ b/src/config/nc.rs
@@ -18,7 +18,7 @@ pub(super) fn parse_config_file(
database: Some(config.database.url().parse()?),
database_prefix: Some(config.database_prefix),
nextcloud_url: Some(config.nextcloud_url),
- redis: Some(config.redis),
+ redis: Some(config.notify_push_redis.unwrap_or(config.redis)),
..PartialConfig::default()
})
}