This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin.git


The following commit(s) were added to refs/heads/master by this push:
     new 7e08792  feat: add SyncedContextEnforcer
7e08792 is described below

commit 7e08792062d25fccf41d4034e14417b5a4eae3d7
Author: Yang Luo <[email protected]>
AuthorDate: Wed Oct 21 00:26:55 2026 +0800

    feat: add SyncedContextEnforcer
---
 README.md                       |   4 +
 enforcer_context_synced.go      | 485 ++++++++++++++++++++++++++++++++++++++++
 enforcer_context_synced_test.go |  70 ++++++
 3 files changed, 559 insertions(+)

diff --git a/README.md b/README.md
index 804fe0f..c9747dd 100644
--- a/README.md
+++ b/README.md
@@ -182,6 +182,8 @@ https://casbin.apache.org/docs/tutorials
 
 Note: you can also initialize an enforcer with policy in DB instead of file, 
see [Policy-persistence](#policy-persistence) section for details.
 
+Note: `Enforcer` is not safe for concurrent use. If the enforcer is shared by 
multiple goroutines (e.g., in a web server) and the policy can change at 
run-time (management API, watcher callback, periodic `LoadPolicy()`), use 
`casbin.NewSyncedEnforcer()` instead, or `casbin.NewSyncedContextEnforcer()` 
for the context-aware API. See [Production 
Deployment](https://casbin.apache.org/docs/production-deployment) for details.
+
 2. Add an enforcement hook into your code right before the access happens:
 
     ```go
@@ -225,6 +227,8 @@ https://casbin.apache.org/docs/adapters
 
 https://casbin.apache.org/docs/watchers
 
+https://casbin.apache.org/docs/production-deployment
+
 ## Role manager
 
 https://casbin.apache.org/docs/role-managers
diff --git a/enforcer_context_synced.go b/enforcer_context_synced.go
new file mode 100644
index 0000000..3192216
--- /dev/null
+++ b/enforcer_context_synced.go
@@ -0,0 +1,485 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package casbin
+
+import "context"
+
+var _ IEnforcerContext = &SyncedContextEnforcer{}
+
+// SyncedContextEnforcer wraps ContextEnforcer and provides synchronized 
access.
+type SyncedContextEnforcer struct {
+       *SyncedEnforcer
+       ctxEnforcer *ContextEnforcer
+}
+
+// NewSyncedContextEnforcer creates a synchronized context-aware enforcer via 
file or DB.
+func NewSyncedContextEnforcer(params ...interface{}) (*SyncedContextEnforcer, 
error) {
+       e, err := NewContextEnforcer(params...)
+       if err != nil {
+               return nil, err
+       }
+
+       ctxEnforcer := e.(*ContextEnforcer)
+       return &SyncedContextEnforcer{
+               SyncedEnforcer: &SyncedEnforcer{
+                       Enforcer:     ctxEnforcer.Enforcer,
+                       stopAutoLoad: make(chan struct{}, 1),
+               },
+               ctxEnforcer: ctxEnforcer,
+       }, nil
+}
+
+// LoadPolicyCtx loads all policy rules from the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) LoadPolicyCtx(ctx context.Context) error {
+       e.m.RLock()
+       newModel, err := e.ctxEnforcer.loadPolicyFromAdapterCtx(ctx, e.model)
+       e.m.RUnlock()
+       if err != nil {
+               return err
+       }
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.applyModifiedModel(newModel)
+}
+
+// LoadFilteredPolicyCtx loads all policy rules from the storage with context 
and filter with synchronization.
+func (e *SyncedContextEnforcer) LoadFilteredPolicyCtx(ctx context.Context, 
filter interface{}) error {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.LoadFilteredPolicyCtx(ctx, filter)
+}
+
+// LoadIncrementalFilteredPolicyCtx append a filtered policy from 
file/database with context and synchronization.
+func (e *SyncedContextEnforcer) LoadIncrementalFilteredPolicyCtx(ctx 
context.Context, filter interface{}) error {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.LoadIncrementalFilteredPolicyCtx(ctx, filter)
+}
+
+// IsFilteredCtx returns true if the loaded policy has been filtered with 
context and synchronization.
+func (e *SyncedContextEnforcer) IsFilteredCtx(ctx context.Context) bool {
+       e.m.RLock()
+       defer e.m.RUnlock()
+       return e.ctxEnforcer.IsFilteredCtx(ctx)
+}
+
+// SavePolicyCtx calls ContextEnforcer.SavePolicyCtx with synchronization.
+func (e *SyncedContextEnforcer) SavePolicyCtx(ctx context.Context) error {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SavePolicyCtx(ctx)
+}
+
+// AddPolicyCtx adds a policy rule to the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) AddPolicyCtx(ctx context.Context, params 
...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddPolicyCtx(ctx, params...)
+}
+
+// AddPoliciesCtx adds policy rules to the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) AddPoliciesCtx(ctx context.Context, rules 
[][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddPoliciesCtx(ctx, rules)
+}
+
+// AddNamedPolicyCtx adds a named policy rule to the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) AddNamedPolicyCtx(ctx context.Context, ptype 
string, params ...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddNamedPolicyCtx(ctx, ptype, params...)
+}
+
+// AddNamedPoliciesCtx adds named policy rules to the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) AddNamedPoliciesCtx(ctx context.Context, ptype 
string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddNamedPoliciesCtx(ctx, ptype, rules)
+}
+
+// AddPoliciesExCtx calls ContextEnforcer.AddPoliciesExCtx with 
synchronization.
+func (e *SyncedContextEnforcer) AddPoliciesExCtx(ctx context.Context, rules 
[][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddPoliciesExCtx(ctx, rules)
+}
+
+// AddNamedPoliciesExCtx calls ContextEnforcer.AddNamedPoliciesExCtx with 
synchronization.
+func (e *SyncedContextEnforcer) AddNamedPoliciesExCtx(ctx context.Context, 
ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddNamedPoliciesExCtx(ctx, ptype, rules)
+}
+
+// RemovePolicyCtx removes a policy rule from the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) RemovePolicyCtx(ctx context.Context, params 
...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemovePolicyCtx(ctx, params...)
+}
+
+// RemoveNamedPolicyCtx removes a named policy rule from the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) RemoveNamedPolicyCtx(ctx context.Context, 
ptype string, params ...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveNamedPolicyCtx(ctx, ptype, params...)
+}
+
+// RemovePoliciesCtx removes policy rules from the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) RemovePoliciesCtx(ctx context.Context, rules 
[][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemovePoliciesCtx(ctx, rules)
+}
+
+// RemoveNamedPoliciesCtx removes named policy rules from the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) RemoveNamedPoliciesCtx(ctx context.Context, 
ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveNamedPoliciesCtx(ctx, ptype, rules)
+}
+
+// RemoveFilteredPolicyCtx removes policy rules that match the filter from the 
storage with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveFilteredPolicyCtx(ctx context.Context, 
fieldIndex int, fieldValues ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveFilteredPolicyCtx(ctx, fieldIndex, 
fieldValues...)
+}
+
+// RemoveFilteredNamedPolicyCtx removes named policy rules that match the 
filter from the storage with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveFilteredNamedPolicyCtx(ctx 
context.Context, ptype string, fieldIndex int, fieldValues ...string) (bool, 
error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveFilteredNamedPolicyCtx(ctx, ptype, 
fieldIndex, fieldValues...)
+}
+
+// UpdatePolicyCtx updates a policy rule in the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) UpdatePolicyCtx(ctx context.Context, oldPolicy 
[]string, newPolicy []string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdatePolicyCtx(ctx, oldPolicy, newPolicy)
+}
+
+// UpdateNamedPolicyCtx updates a named policy rule in the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) UpdateNamedPolicyCtx(ctx context.Context, 
ptype string, p1 []string, p2 []string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateNamedPolicyCtx(ctx, ptype, p1, p2)
+}
+
+// UpdatePoliciesCtx updates policy rules in the storage with context and 
synchronization.
+func (e *SyncedContextEnforcer) UpdatePoliciesCtx(ctx context.Context, 
oldPolicies [][]string, newPolicies [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdatePoliciesCtx(ctx, oldPolicies, newPolicies)
+}
+
+// UpdateNamedPoliciesCtx updates named policy rules in the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) UpdateNamedPoliciesCtx(ctx context.Context, 
ptype string, p1 [][]string, p2 [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateNamedPoliciesCtx(ctx, ptype, p1, p2)
+}
+
+// UpdateFilteredPoliciesCtx updates policy rules that match the filter in the 
storage with context and synchronization.
+func (e *SyncedContextEnforcer) UpdateFilteredPoliciesCtx(ctx context.Context, 
newPolicies [][]string, fieldIndex int, fieldValues ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateFilteredPoliciesCtx(ctx, newPolicies, 
fieldIndex, fieldValues...)
+}
+
+// UpdateFilteredNamedPoliciesCtx updates named policy rules that match the 
filter in the storage with context and synchronization.
+func (e *SyncedContextEnforcer) UpdateFilteredNamedPoliciesCtx(ctx 
context.Context, ptype string, newPolicies [][]string, fieldIndex int, 
fieldValues ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateFilteredNamedPoliciesCtx(ctx, ptype, 
newPolicies, fieldIndex, fieldValues...)
+}
+
+// AddGroupingPolicyCtx adds a grouping policy rule to the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) AddGroupingPolicyCtx(ctx context.Context, 
params ...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddGroupingPolicyCtx(ctx, params...)
+}
+
+// AddGroupingPoliciesCtx adds grouping policy rules to the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) AddGroupingPoliciesCtx(ctx context.Context, 
rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddGroupingPoliciesCtx(ctx, rules)
+}
+
+// AddGroupingPoliciesExCtx calls ContextEnforcer.AddGroupingPoliciesExCtx 
with synchronization.
+func (e *SyncedContextEnforcer) AddGroupingPoliciesExCtx(ctx context.Context, 
rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddGroupingPoliciesExCtx(ctx, rules)
+}
+
+// AddNamedGroupingPolicyCtx adds a named grouping policy rule to the storage 
with context and synchronization.
+func (e *SyncedContextEnforcer) AddNamedGroupingPolicyCtx(ctx context.Context, 
ptype string, params ...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddNamedGroupingPolicyCtx(ctx, ptype, params...)
+}
+
+// AddNamedGroupingPoliciesCtx adds named grouping policy rules to the storage 
with context and synchronization.
+func (e *SyncedContextEnforcer) AddNamedGroupingPoliciesCtx(ctx 
context.Context, ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddNamedGroupingPoliciesCtx(ctx, ptype, rules)
+}
+
+// AddNamedGroupingPoliciesExCtx calls 
ContextEnforcer.AddNamedGroupingPoliciesExCtx with synchronization.
+func (e *SyncedContextEnforcer) AddNamedGroupingPoliciesExCtx(ctx 
context.Context, ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddNamedGroupingPoliciesExCtx(ctx, ptype, rules)
+}
+
+// RemoveGroupingPolicyCtx removes a grouping policy rule from the storage 
with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveGroupingPolicyCtx(ctx context.Context, 
params ...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveGroupingPolicyCtx(ctx, params...)
+}
+
+// RemoveNamedGroupingPolicyCtx removes a named grouping policy rule from the 
storage with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveNamedGroupingPolicyCtx(ctx 
context.Context, ptype string, params ...interface{}) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveNamedGroupingPolicyCtx(ctx, ptype, params...)
+}
+
+// RemoveGroupingPoliciesCtx removes grouping policy rules from the storage 
with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveGroupingPoliciesCtx(ctx context.Context, 
rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveGroupingPoliciesCtx(ctx, rules)
+}
+
+// RemoveNamedGroupingPoliciesCtx removes named grouping policy rules from the 
storage with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveNamedGroupingPoliciesCtx(ctx 
context.Context, ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveNamedGroupingPoliciesCtx(ctx, ptype, rules)
+}
+
+// RemoveFilteredGroupingPolicyCtx removes grouping policy rules that match 
the filter from the storage with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveFilteredGroupingPolicyCtx(ctx 
context.Context, fieldIndex int, fieldValues ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveFilteredGroupingPolicyCtx(ctx, fieldIndex, 
fieldValues...)
+}
+
+// RemoveFilteredNamedGroupingPolicyCtx removes named grouping policy rules 
that match the filter from the storage with context and synchronization.
+func (e *SyncedContextEnforcer) RemoveFilteredNamedGroupingPolicyCtx(ctx 
context.Context, ptype string, fieldIndex int, fieldValues ...string) (bool, 
error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.RemoveFilteredNamedGroupingPolicyCtx(ctx, ptype, 
fieldIndex, fieldValues...)
+}
+
+// UpdateGroupingPolicyCtx updates a grouping policy rule in the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) UpdateGroupingPolicyCtx(ctx context.Context, 
oldRule []string, newRule []string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateGroupingPolicyCtx(ctx, oldRule, newRule)
+}
+
+// UpdateNamedGroupingPolicyCtx updates a named grouping policy rule in the 
storage with context and synchronization.
+func (e *SyncedContextEnforcer) UpdateNamedGroupingPolicyCtx(ctx 
context.Context, ptype string, oldRule []string, newRule []string) (bool, 
error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateNamedGroupingPolicyCtx(ctx, ptype, oldRule, 
newRule)
+}
+
+// UpdateGroupingPoliciesCtx updates grouping policy rules in the storage with 
context and synchronization.
+func (e *SyncedContextEnforcer) UpdateGroupingPoliciesCtx(ctx context.Context, 
oldRules [][]string, newRules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateGroupingPoliciesCtx(ctx, oldRules, newRules)
+}
+
+// UpdateNamedGroupingPoliciesCtx updates named grouping policy rules in the 
storage with context and synchronization.
+func (e *SyncedContextEnforcer) UpdateNamedGroupingPoliciesCtx(ctx 
context.Context, ptype string, oldRules [][]string, newRules [][]string) (bool, 
error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.UpdateNamedGroupingPoliciesCtx(ctx, ptype, 
oldRules, newRules)
+}
+
+// SelfAddPolicyCtx adds a policy rule to the current policy with context and 
synchronization.
+func (e *SyncedContextEnforcer) SelfAddPolicyCtx(ctx context.Context, sec 
string, ptype string, rule []string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfAddPolicyCtx(ctx, sec, ptype, rule)
+}
+
+// SelfAddPoliciesCtx adds policy rules to the current policy with context and 
synchronization.
+func (e *SyncedContextEnforcer) SelfAddPoliciesCtx(ctx context.Context, sec 
string, ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfAddPoliciesCtx(ctx, sec, ptype, rules)
+}
+
+// SelfAddPoliciesExCtx calls ContextEnforcer.SelfAddPoliciesExCtx with 
synchronization.
+func (e *SyncedContextEnforcer) SelfAddPoliciesExCtx(ctx context.Context, sec 
string, ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfAddPoliciesExCtx(ctx, sec, ptype, rules)
+}
+
+// SelfRemovePolicyCtx removes a policy rule from the current policy with 
context and synchronization.
+func (e *SyncedContextEnforcer) SelfRemovePolicyCtx(ctx context.Context, sec 
string, ptype string, rule []string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfRemovePolicyCtx(ctx, sec, ptype, rule)
+}
+
+// SelfRemovePoliciesCtx removes policy rules from the current policy with 
context and synchronization.
+func (e *SyncedContextEnforcer) SelfRemovePoliciesCtx(ctx context.Context, sec 
string, ptype string, rules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfRemovePoliciesCtx(ctx, sec, ptype, rules)
+}
+
+// SelfRemoveFilteredPolicyCtx removes policy rules that match the filter from 
the current policy with context and synchronization.
+func (e *SyncedContextEnforcer) SelfRemoveFilteredPolicyCtx(ctx 
context.Context, sec string, ptype string, fieldIndex int, fieldValues 
...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfRemoveFilteredPolicyCtx(ctx, sec, ptype, 
fieldIndex, fieldValues...)
+}
+
+// SelfUpdatePolicyCtx updates a policy rule in the current policy with 
context and synchronization.
+func (e *SyncedContextEnforcer) SelfUpdatePolicyCtx(ctx context.Context, sec 
string, ptype string, oldRule, newRule []string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfUpdatePolicyCtx(ctx, sec, ptype, oldRule, 
newRule)
+}
+
+// SelfUpdatePoliciesCtx updates policy rules in the current policy with 
context and synchronization.
+func (e *SyncedContextEnforcer) SelfUpdatePoliciesCtx(ctx context.Context, sec 
string, ptype string, oldRules, newRules [][]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.SelfUpdatePoliciesCtx(ctx, sec, ptype, oldRules, 
newRules)
+}
+
+// AddRoleForUserCtx adds a role for a user with context and synchronization.
+func (e *SyncedContextEnforcer) AddRoleForUserCtx(ctx context.Context, user 
string, role string, domain ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddRoleForUserCtx(ctx, user, role, domain...)
+}
+
+// DeleteRoleForUserCtx deletes a role for a user with context and 
synchronization.
+func (e *SyncedContextEnforcer) DeleteRoleForUserCtx(ctx context.Context, user 
string, role string, domain ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteRoleForUserCtx(ctx, user, role, domain...)
+}
+
+// DeleteRolesForUserCtx deletes all roles for a user with context and 
synchronization.
+func (e *SyncedContextEnforcer) DeleteRolesForUserCtx(ctx context.Context, 
user string, domain ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteRolesForUserCtx(ctx, user, domain...)
+}
+
+// DeleteUserCtx deletes a user with context and synchronization.
+func (e *SyncedContextEnforcer) DeleteUserCtx(ctx context.Context, user 
string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteUserCtx(ctx, user)
+}
+
+// DeleteRoleCtx deletes a role with context and synchronization.
+func (e *SyncedContextEnforcer) DeleteRoleCtx(ctx context.Context, role 
string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteRoleCtx(ctx, role)
+}
+
+// DeletePermissionCtx deletes a permission with context and synchronization.
+func (e *SyncedContextEnforcer) DeletePermissionCtx(ctx context.Context, 
permission ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeletePermissionCtx(ctx, permission...)
+}
+
+// AddPermissionForUserCtx adds a permission for a user or role with context 
and synchronization.
+func (e *SyncedContextEnforcer) AddPermissionForUserCtx(ctx context.Context, 
user string, permission ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddPermissionForUserCtx(ctx, user, permission...)
+}
+
+// AddPermissionsForUserCtx adds multiple permissions for a user or role with 
context and synchronization.
+func (e *SyncedContextEnforcer) AddPermissionsForUserCtx(ctx context.Context, 
user string, permissions ...[]string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddPermissionsForUserCtx(ctx, user, permissions...)
+}
+
+// DeletePermissionForUserCtx deletes a permission for a user or role with 
context and synchronization.
+func (e *SyncedContextEnforcer) DeletePermissionForUserCtx(ctx 
context.Context, user string, permission ...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeletePermissionForUserCtx(ctx, user, 
permission...)
+}
+
+// DeletePermissionsForUserCtx deletes permissions for a user or role with 
context and synchronization.
+func (e *SyncedContextEnforcer) DeletePermissionsForUserCtx(ctx 
context.Context, user string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeletePermissionsForUserCtx(ctx, user)
+}
+
+// AddRoleForUserInDomainCtx adds a role for a user inside a domain with 
context and synchronization.
+func (e *SyncedContextEnforcer) AddRoleForUserInDomainCtx(ctx context.Context, 
user string, role string, domain string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.AddRoleForUserInDomainCtx(ctx, user, role, domain)
+}
+
+// DeleteRoleForUserInDomainCtx deletes a role for a user inside a domain with 
context and synchronization.
+func (e *SyncedContextEnforcer) DeleteRoleForUserInDomainCtx(ctx 
context.Context, user string, role string, domain string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteRoleForUserInDomainCtx(ctx, user, role, 
domain)
+}
+
+// DeleteRolesForUserInDomainCtx deletes all roles for a user inside a domain 
with context and synchronization.
+func (e *SyncedContextEnforcer) DeleteRolesForUserInDomainCtx(ctx 
context.Context, user string, domain string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteRolesForUserInDomainCtx(ctx, user, domain)
+}
+
+// DeleteAllUsersByDomainCtx deletes all users associated with the domain with 
context and synchronization.
+func (e *SyncedContextEnforcer) DeleteAllUsersByDomainCtx(ctx context.Context, 
domain string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteAllUsersByDomainCtx(ctx, domain)
+}
+
+// DeleteDomainsCtx deletes all associated policies for domains with context 
and synchronization.
+func (e *SyncedContextEnforcer) DeleteDomainsCtx(ctx context.Context, domains 
...string) (bool, error) {
+       e.m.Lock()
+       defer e.m.Unlock()
+       return e.ctxEnforcer.DeleteDomainsCtx(ctx, domains...)
+}
diff --git a/enforcer_context_synced_test.go b/enforcer_context_synced_test.go
new file mode 100644
index 0000000..ec0d15c
--- /dev/null
+++ b/enforcer_context_synced_test.go
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package casbin
+
+import (
+       "context"
+       "sync"
+       "testing"
+)
+
+func TestSyncedContextEnforcer(t *testing.T) {
+       e, err := NewSyncedContextEnforcer("examples/rbac_model.conf", 
"examples/rbac_policy.csv")
+       if err != nil {
+               t.Fatalf("NewSyncedContextEnforcer failed: %v", err)
+       }
+       e.EnableAutoSave(false)
+
+       ctx := context.Background()
+       var wg sync.WaitGroup
+       for i := 0; i < 10; i++ {
+               wg.Add(3)
+               go func() {
+                       defer wg.Done()
+                       for j := 0; j < 100; j++ {
+                               if _, err := e.AddPolicyCtx(ctx, "eve", 
"data3", "read"); err != nil {
+                                       t.Error(err)
+                               }
+                               if _, err := e.RemovePolicyCtx(ctx, "eve", 
"data3", "read"); err != nil {
+                                       t.Error(err)
+                               }
+                       }
+               }()
+               go func() {
+                       defer wg.Done()
+                       for j := 0; j < 10; j++ {
+                               if err := e.LoadPolicyCtx(ctx); err != nil {
+                                       t.Error(err)
+                               }
+                       }
+               }()
+               go func() {
+                       defer wg.Done()
+                       for j := 0; j < 100; j++ {
+                               if _, err := e.Enforce("alice", "data2", 
"read"); err != nil {
+                                       t.Error(err)
+                               }
+                       }
+               }()
+       }
+       wg.Wait()
+
+       testEnforceSync(t, e.SyncedEnforcer, "alice", "data1", "read", true)
+       testEnforceSync(t, e.SyncedEnforcer, "alice", "data2", "read", true)
+       testEnforceSync(t, e.SyncedEnforcer, "eve", "data3", "read", false)
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to