Redis Watcher is a Redis watcher for Casbin-RS.
Add this to your Cargo.toml
:
[dependencies]
redis-watcher = "1.0.0"
casbin = { version = "2.13.0", features = ["watcher"] }
tokio = { version = "1.0", features = ["rt-multi-thread", "macros", "time"] }
redis = { version = "0.32.6", features = ["tokio-comp", "cluster-async", "aio"] }
Note: The watcher
feature is required for Casbin to enable watcher functionality. For Redis cluster support, include the cluster-async
feature.
use redis_watcher::{RedisWatcher, WatcherOptions};
use casbin::{prelude::*, Watcher, EventData};
fn main() -> redis_watcher::Result<()> {
// Configure watcher options
let options = WatcherOptions::default()
.with_channel("/casbin".to_string())
.with_ignore_self(false); // Set to true in production to ignore self-updates
// Create watcher for standalone Redis
let mut watcher = RedisWatcher::new("redis://127.0.0.1:6379", options)?;
// Set callback to handle policy updates
watcher.set_update_callback(Box::new(|msg: String| {
println!("Policy updated: {}", msg);
// Reload your enforcer policies here
}));
// The watcher automatically starts subscription when callback is set
// Now you can use it with Casbin enforcer
// Your enforcer will be notified when policies change
Ok(())
}
use redis_watcher::{RedisWatcher, WatcherOptions};
use casbin::{prelude::*, Watcher};
fn main() -> redis_watcher::Result<()> {
let options = WatcherOptions::default()
.with_channel("/casbin".to_string())
.with_ignore_self(true);
// Initialize watcher with Redis cluster
// Provide comma-separated list of cluster nodes
let mut watcher = RedisWatcher::new_cluster(
"redis://127.0.0.1:7000,redis://127.0.0.1:7001,redis://127.0.0.1:7002",
options
)?;
// Set up callback to handle policy updates
watcher.set_update_callback(Box::new(|msg: String| {
println!("Received policy update from cluster: {}", msg);
// Parse message and reload enforcer policies
}));
// Watcher is now ready to receive cluster-wide policy updates
Ok(())
}
The WatcherOptions
struct provides configuration for the Redis watcher:
use redis_watcher::WatcherOptions;
let options = WatcherOptions::default()
.with_channel("/casbin-policy-updates".to_string()) // Redis channel name
.with_ignore_self(true) // Ignore self-generated updates
.with_local_id("unique-instance-id".to_string()); // Unique identifier for this instance
Options Explained:
channel
: Redis pub/sub channel name for policy updates (default:"/casbin"
)ignore_self
: Whentrue
, the watcher ignores messages it published itself, preventing circular updates (default:false
)local_id
: Unique identifier for this watcher instance, automatically generated using UUID v4 if not specified
Best Practices:
- Set
ignore_self
totrue
in production to avoid processing your own updates - Use a descriptive
local_id
for easier debugging in multi-instance deployments - Choose a channel name that doesn't conflict with other Redis applications
The watcher supports various policy update types through the UpdateType
enum, which corresponds to different Casbin operations:
pub enum UpdateType {
Update, // Generic update notification
UpdateForAddPolicy, // Single policy addition
UpdateForRemovePolicy, // Single policy removal
UpdateForRemoveFilteredPolicy, // Filtered policy removal
UpdateForSavePolicy, // Complete policy save
UpdateForAddPolicies, // Batch policy addition
UpdateForRemovePolicies, // Batch policy removal
UpdateForUpdatePolicy, // Single policy update
UpdateForUpdatePolicies, // Batch policy update
}
Message Structure:
Each update is published as a JSON message with the following structure:
pub struct Message {
pub method: UpdateType, // Type of update
pub id: String, // Sender's local_id
pub sec: String, // Policy section (e.g., "p", "g")
pub ptype: String, // Policy type
pub old_rule: Vec<String>, // Old policy rule
pub old_rules: Vec<Vec<String>>, // Old policy rules (batch)
pub new_rule: Vec<String>, // New policy rule
pub new_rules: Vec<Vec<String>>, // New policy rules (batch)
pub field_index: i32, // Field index for filtered operations
pub field_values: Vec<String>, // Field values for filtered operations
}
Integration with Casbin:
The watcher automatically converts Casbin's EventData
to these message types when you call watcher.update(event_data)
. This ensures consistent synchronization across all instances.
- API Documentation: docs.rs/redis-watcher
- Casbin-RS Documentation: Casbin-RS GitHub
- Redis Client: redis-rs Documentation
- Async Runtime: Tokio Documentation
This project is under Apache 2.0 License. See the LICENSE file for the full license text.