From ace56e7aa15421d829fbdafdb3a045d0daeaa8d5 Mon Sep 17 00:00:00 2001 From: YuetChn Date: Fri, 26 Jan 2024 22:00:24 +0800 Subject: [PATCH] feat: add NewWatcherWithConfig() (#25) * feat: Added configuration-based constructors * fix: keyName is not specified. * test: new test for NewWatcherWithConfig() * doc: NewWatcherWithConfig() usage --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++++ watcher.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ watcher_test.go | 12 ++++++++++++ 3 files changed, 100 insertions(+) diff --git a/README.md b/README.md index 5786e9f..38d8fb2 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,49 @@ func main() { } ``` +## Simple Example(Configuration Mode) + +```go +package main + +import ( + "log" + + casbin "github.com/casbin/casbin/v2" + etcdwatcher "github.com/casbin/etcd-watcher/v2" +) + +func updateCallback(rev string) { + log.Println("New revision detected:", rev) +} + +func main() { + // Initialize the watcher. + // Use the configuration file as the parameter + w, _ := etcdwatcher.NewWatcherWithConfig(etcdwatcher.WatcherConfig{ + Hosts: []string{"http://127.0.0.1:2379"}, + Key: "/casbin", + User: "root", + Pass: "123", + }) + + // Initialize the enforcer. + e, _ := casbin.NewEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv") + + // Set the watcher for the enforcer. + e.SetWatcher(w) + + // By default, the watcher's callback is automatically set to the + // enforcer's LoadPolicy() in the SetWatcher() call. + // We can change it by explicitly setting a callback. + w.SetUpdateCallback(updateCallback) + + // Update the policy to test the effect. + // You should see "[New revision detected: X]" in the log. + e.SavePolicy() +} +``` + ## Getting Help - [Casbin](https://github.com/casbin/casbin) diff --git a/watcher.go b/watcher.go index af538d0..9abd559 100644 --- a/watcher.go +++ b/watcher.go @@ -35,6 +35,16 @@ type Watcher struct { keyName string password string lastSentRev int64 + conf *WatcherConfig +} + +type WatcherConfig struct { + Hosts []string + Key string `json:",default=casbin_watcher"` + User string + Pass string + DialKeepAliveTimeout time.Duration `json:",default=10"` + DialTimeout time.Duration `json:",default=30"` } // finalizer is the destructor for Watcher. @@ -70,6 +80,30 @@ func NewWatcher(endpoints []string, keyName string, password ...string) (persist return w, nil } +// NewWatcherWithConfig is a configurable Watcher constructor +func NewWatcherWithConfig(config WatcherConfig) (persist.Watcher, error) { + w := &Watcher{} + w.running = true + w.callback = nil + w.keyName = config.Key + w.conf = &config + + // Create the client. + err := w.createClient() + if err != nil { + return nil, err + } + + // Call the destructor when the object is released. + runtime.SetFinalizer(w, finalizer) + + go func() { + _ = w.startWatch() + }() + + return w, nil +} + // Close closes the Watcher. func (w *Watcher) Close() { finalizer(w) @@ -84,6 +118,17 @@ func (w *Watcher) createClient() error { Password: w.password, } + if w.conf != nil { + cfg = client.Config{ + Endpoints: w.conf.Hosts, + // set timeout per request to fail fast when the target endpoints is unavailable + DialTimeout: time.Second * w.conf.DialTimeout, + DialKeepAliveTimeout: time.Second * w.conf.DialKeepAliveTimeout, + Username: w.conf.User, + Password: w.conf.Pass, + } + } + c, err := client.New(cfg) if err != nil { return err diff --git a/watcher_test.go b/watcher_test.go index bac56ff..ed9d6de 100644 --- a/watcher_test.go +++ b/watcher_test.go @@ -30,6 +30,13 @@ func TestWatcher(t *testing.T) { // Use the endpoints of etcd cluster as parameter. updater, _ := NewWatcher([]string{"http://127.0.0.1:2379"}, "/casbin") + withConfigUpdater, _ := NewWatcherWithConfig(WatcherConfig{ + Hosts: []string{"http://127.0.0.1:2379"}, + Key: "/casbin", + User: "", + Pass: "", + }) + // listener represents any other Casbin enforcer instance that watches the change of policy in DB. listener, _ := NewWatcher([]string{"http://127.0.0.1:2379"}, "/casbin") // listener should set a callback that gets called when policy changes. @@ -41,6 +48,11 @@ func TestWatcher(t *testing.T) { panic(err) } + err = withConfigUpdater.Update() + if err != nil { + panic(err) + } + // Now the listener's callback updateCallback() should be called, // because it receives the notification of policy update. // You should see "[New revision detected: X]" in the log.