Skip to content

Commit eb2744c

Browse files
committed
Merge branch 'master' of github.com:php-casbin/swoole-redis-watcher into main
2 parents 3b6944d + cef3e01 commit eb2744c

File tree

5 files changed

+260
-0
lines changed

5 files changed

+260
-0
lines changed

.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/vendor/
2+
3+
composer.lock
4+
5+
.idea/
6+
*.iml
7+
*.cache
8+
9+
# coverage report
10+
/build
11+
12+
./phpunit.xml

README.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Redis watcher for PHP-Casbin in Swoole
2+
3+
[![Latest Stable Version](https://poser.pugx.org/casbin/swoole-redis-watcher/v/stable)](https://packagist.org/packages/casbin/swoole-redis-watcher)
4+
[![Total Downloads](https://poser.pugx.org/casbin/swoole-redis-watcher/downloads)](https://packagist.org/packages/casbin/swoole-redis-watcher)
5+
[![License](https://poser.pugx.org/casbin/swoole-redis-watcher/license)](https://packagist.org/packages/casbin/swoole-redis-watcher)
6+
7+
Redis watcher for [PHP-Casbin](https://github.com/php-casbin/php-casbin) in [Swoole](https://www.swoole.com/) , [Casbin](https://casbin.org/) is a powerful and efficient open-source access control library.
8+
9+
### Installation
10+
11+
Via [Composer](https://getcomposer.org/).
12+
13+
```
14+
composer require casbin/swoole-redis-watcher
15+
```
16+
17+
### Usage
18+
19+
```php
20+
21+
require dirname(__FILE__) . '/../vendor/autoload.php';
22+
23+
use Casbin\Enforcer;
24+
use CasbinWatcher\SwooleRedis\Watcher;
25+
26+
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
27+
28+
$http = new Swoole\Http\Server('0.0.0.0', 9501);
29+
30+
$http->on('WorkerStart', function ($server, $worker_id) {
31+
global $enforcer;
32+
33+
// Initialize the Watcher.
34+
$watcher = new Watcher([
35+
'host' => '127.0.0.1',
36+
'password' => '',
37+
'port' => 6379,
38+
'database' => 0,
39+
]);
40+
41+
// Initialize the Enforcer.
42+
$enforcer = new Enforcer("path/to/model.conf", "path/to/policy.csv");
43+
44+
// Set the watcher for the enforcer.
45+
$enforcer->setWatcher($watcher);
46+
47+
// By default, the watcher's callback is automatically set to the
48+
// $enforcer->loadPolicy() in the setWatcher() call.
49+
// We can change it by explicitly setting a callback.
50+
$watcher->setUpdateCallback(function () use ($enforcer) {
51+
// Now should reload all policies.
52+
// $enforcer->loadPolicy();
53+
});
54+
55+
};
56+
57+
$http->on('Request', function ($request, $response) {
58+
// ...
59+
});
60+
61+
$http->start();
62+
63+
```
64+
65+
### Getting Help
66+
67+
- [php-casbin](https://github.com/php-casbin/php-casbin)
68+
69+
### License
70+
71+
This project is licensed under the [Apache 2.0 license](LICENSE).

composer.json

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "casbin/swoole-redis-watcher",
3+
"keywords": [
4+
"casbin",
5+
"watcher",
6+
"swoole",
7+
"rbac",
8+
"permission",
9+
"acl"
10+
],
11+
"description": "Redis watcher for PHP-Casbin in swoole.",
12+
"authors": [
13+
{
14+
"name": "TechLee",
15+
"email": "[email protected]"
16+
}
17+
],
18+
"license": "Apache-2.0",
19+
"require": {
20+
"casbin/casbin": "^3.0",
21+
"ext-swoole": "^4.0",
22+
"ext-redis": "*"
23+
},
24+
"autoload": {
25+
"psr-4": {
26+
"CasbinWatcher\\SwooleRedis\\": "src/"
27+
}
28+
},
29+
"autoload-dev": {
30+
"psr-4": {
31+
"CasbinWatcher\\SwooleRedis\\Tests\\": "tests/"
32+
}
33+
}
34+
}

src/Watcher.php

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
namespace CasbinWatcher\SwooleRedis;
4+
5+
use Casbin\Persist\Watcher as WatcherContract;
6+
use Redis;
7+
use Closure;
8+
9+
class Watcher implements WatcherContract
10+
{
11+
public ?Closure $callback = null;
12+
13+
private $pubClient;
14+
15+
private $subClient;
16+
17+
private $channel;
18+
19+
/**
20+
* The config of Watcher.
21+
*
22+
* @param array $config
23+
* [
24+
* 'host' => '127.0.0.1',
25+
* 'password' => '',
26+
* 'port' => 6379,
27+
* 'database' => 0,
28+
* 'channel' => '/casbin',
29+
* ]
30+
*/
31+
public function __construct(array $config)
32+
{
33+
$this->pubClient = $this->createRedisClient($config);
34+
$this->subClient = $this->createRedisClient($config);
35+
$this->channel = $config['channel'] ?? '/casbin';
36+
37+
go(function () {
38+
$this->subClient->subscribe([$this->channel], function ($redis, $channel, $message) {
39+
if ($this->callback) {
40+
go($this->callback);
41+
}
42+
});
43+
});
44+
}
45+
46+
/**
47+
* Sets the callback function that the watcher will call when the policy in DB has been changed by other instances.
48+
* A classic callback is loadPolicy() method of Enforcer class.
49+
*
50+
* @param Closure $func
51+
*/
52+
public function setUpdateCallback(Closure $func): void
53+
{
54+
$this->callback = $func;
55+
}
56+
57+
/**
58+
* Update calls the update callback of other instances to synchronize their policy.
59+
* It is usually called after changing the policy in DB, like savePolicy() method of Enforcer class,
60+
* addPolicy(), removePolicy(), etc.
61+
*/
62+
public function update(): void
63+
{
64+
$this->pubClient->publish($this->channel, 'casbin rules updated');
65+
}
66+
67+
/**
68+
* Close stops and releases the watcher, the callback function will not be called any more.
69+
*/
70+
public function close(): void
71+
{
72+
$this->pubClient->close();
73+
$this->subClient->close();
74+
}
75+
76+
/**
77+
* Create redis client
78+
*
79+
* @param array $config
80+
* @return Redis
81+
*/
82+
private function createRedisClient(array $config): Redis
83+
{
84+
$config['host'] = $config['host'] ?? '127.0.0.1';
85+
$config['port'] = $config['port'] ?? 6379;
86+
$config['password'] = $config['password'] ?? '';
87+
$config['database'] = $config['database'] ?? 0;
88+
89+
$client = new Redis();
90+
$client->pconnect($config['host'], $config['port']);
91+
if (!empty($config['password'])) {
92+
$client->auth($config['password']);
93+
}
94+
95+
if (isset($config['database'])) {
96+
$client->select((int) $config['database']);
97+
}
98+
99+
$client->setOption(Redis::OPT_READ_TIMEOUT, -1);
100+
101+
return $client;
102+
}
103+
}

tests/test.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
require dirname(__FILE__) . '/../vendor/autoload.php';
4+
5+
use Casbin\Enforcer;
6+
use CasbinWatcher\SwooleRedis\Watcher;
7+
8+
Co::set(['hook_flags' => SWOOLE_HOOK_ALL]);
9+
10+
$http = new Swoole\Http\Server('0.0.0.0', 9501);
11+
12+
$http->on('WorkerStart', function ($server, $worker_id) {
13+
global $enforcer;
14+
15+
$watcher = new Watcher([
16+
'host' => getenv('REDIS_HOST') ? getenv('REDIS_HOST') : '127.0.0.1',
17+
'password' => getenv('REDIS_PASSWORD') ? getenv('REDIS_PASSWORD') : '',
18+
'port' => getenv('REDIS_PORT') ? getenv('REDIS_PORT') : 6379,
19+
'database' => getenv('REDIS_DB') ? getenv('REDIS_DB') : 0,
20+
]);
21+
22+
$enforcer = new Enforcer(dirname(__FILE__) . '/../vendor/casbin/casbin/examples/basic_model.conf', dirname(__FILE__) . '/../vendor/casbin/casbin/examples/basic_policy.csv');
23+
24+
$enforcer->setWatcher($watcher);
25+
26+
$watcher->setUpdateCallback(function () {
27+
echo "Now should reload all policies." . PHP_EOL;
28+
});
29+
});
30+
31+
$http->on('Request', function ($request, $response) {
32+
global $enforcer;
33+
34+
$enforcer->savePolicy();
35+
36+
$response->header('Content-Type', 'text/html; charset=utf-8');
37+
$response->end('<h1>Hello Swoole. #' . rand(1000, 9999) . '</h1>');
38+
});
39+
40+
$http->start();

0 commit comments

Comments
 (0)