chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
|
|
@ -110,6 +110,185 @@ func (s *Service) CanSee(ctx context.Context, ownerUserID, viewerUserID int64, k
|
|||
return Evaluate(rules, evalCtx), nil
|
||||
}
|
||||
|
||||
// CanSeeBatch 批量评估多个 owner 对同一 viewer 在多个 key 上的可见性,结果等价于对每个
|
||||
// (owner,key) 调一次 CanSee,但只用一次 ListPrivacyRules + 一次 GetReverseContacts + 内存
|
||||
// Evaluate(消除 projectBatch / fan-out 投影里 per-user 3×CanSee×2行 的 N+1)。返回
|
||||
// map[ownerUserID]map[key]bool;owner==viewer 恒 true(与 CanSee 一致)。
|
||||
func (s *Service) CanSeeBatch(ctx context.Context, ownerUserIDs []int64, viewerUserID int64, keys []domain.PrivacyKey) (map[int64]map[domain.PrivacyKey]bool, error) {
|
||||
out := make(map[int64]map[domain.PrivacyKey]bool, len(ownerUserIDs))
|
||||
if viewerUserID == 0 || len(ownerUserIDs) == 0 || len(keys) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
for _, k := range keys {
|
||||
if !ValidKey(k) {
|
||||
return nil, domain.ErrPrivacyKeyInvalid
|
||||
}
|
||||
}
|
||||
owners := make([]int64, 0, len(ownerUserIDs))
|
||||
seen := make(map[int64]struct{}, len(ownerUserIDs))
|
||||
for _, id := range ownerUserIDs {
|
||||
if id == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
if id == viewerUserID {
|
||||
// 自己恒可见全部 key(与 CanSee 的 ownerUserID==viewerUserID 分支一致)。
|
||||
m := make(map[domain.PrivacyKey]bool, len(keys))
|
||||
for _, k := range keys {
|
||||
m[k] = true
|
||||
}
|
||||
out[id] = m
|
||||
continue
|
||||
}
|
||||
owners = append(owners, id)
|
||||
}
|
||||
if len(owners) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
// 批量取 rules:存在的行进 map,缺失的 (owner,key) 用 defaultRules(复刻 GetRules 兜底)。
|
||||
rulesByOwner := make(map[int64]map[domain.PrivacyKey]domain.PrivacyRules, len(owners))
|
||||
if s != nil && s.rules != nil {
|
||||
list, err := s.rules.ListPrivacyRules(ctx, owners, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, r := range list {
|
||||
if !ValidKey(r.Key) {
|
||||
continue
|
||||
}
|
||||
if len(r.Rules) == 0 {
|
||||
r.Rules = domain.DefaultPrivacyRules(r.Key)
|
||||
}
|
||||
if rulesByOwner[r.OwnerUserID] == nil {
|
||||
rulesByOwner[r.OwnerUserID] = make(map[domain.PrivacyKey]domain.PrivacyRules, len(keys))
|
||||
}
|
||||
rulesByOwner[r.OwnerUserID][r.Key] = cloneRules(r)
|
||||
}
|
||||
}
|
||||
// 批量取「viewer 是否在 owner 的联系人里」(owner→viewer 方向,对应 CanSee 的
|
||||
// contacts.Get(owner, viewer))。
|
||||
var reverse map[int64]domain.Contact
|
||||
if s != nil && s.contacts != nil {
|
||||
var err error
|
||||
reverse, err = s.contacts.GetReverseContacts(ctx, viewerUserID, owners)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, owner := range owners {
|
||||
_, isContact := reverse[owner]
|
||||
m := make(map[domain.PrivacyKey]bool, len(keys))
|
||||
for _, k := range keys {
|
||||
rules, ok := rulesByOwner[owner][k]
|
||||
if !ok {
|
||||
rules = defaultRules(owner, k)
|
||||
}
|
||||
m[k] = Evaluate(rules, domain.PrivacyContext{
|
||||
OwnerUserID: owner,
|
||||
ViewerUserID: viewerUserID,
|
||||
ViewerIsContact: isContact,
|
||||
})
|
||||
}
|
||||
out[owner] = m
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CanSeeMatrix 批量评估 owners × viewers × keys 的可见性矩阵,结果等价于逐 (owner,viewer,key)
|
||||
// 调 CanSee,但只用一次 ListPrivacyRules + 每 owner 一次 GetMany(owner,viewers) + 内存 Evaluate
|
||||
// (把 fan-out 投影从 O(viewer) 次 privacy 查询降到 O(owner))。返回 map[owner]map[viewer]map[key]bool。
|
||||
func (s *Service) CanSeeMatrix(ctx context.Context, ownerUserIDs, viewerUserIDs []int64, keys []domain.PrivacyKey) (map[int64]map[int64]map[domain.PrivacyKey]bool, error) {
|
||||
out := make(map[int64]map[int64]map[domain.PrivacyKey]bool, len(ownerUserIDs))
|
||||
if len(ownerUserIDs) == 0 || len(viewerUserIDs) == 0 || len(keys) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
for _, k := range keys {
|
||||
if !ValidKey(k) {
|
||||
return nil, domain.ErrPrivacyKeyInvalid
|
||||
}
|
||||
}
|
||||
owners := dedupNonZero(ownerUserIDs)
|
||||
viewers := dedupNonZero(viewerUserIDs)
|
||||
if len(owners) == 0 || len(viewers) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
rulesByOwner := make(map[int64]map[domain.PrivacyKey]domain.PrivacyRules, len(owners))
|
||||
if s != nil && s.rules != nil {
|
||||
list, err := s.rules.ListPrivacyRules(ctx, owners, keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, r := range list {
|
||||
if !ValidKey(r.Key) {
|
||||
continue
|
||||
}
|
||||
if len(r.Rules) == 0 {
|
||||
r.Rules = domain.DefaultPrivacyRules(r.Key)
|
||||
}
|
||||
if rulesByOwner[r.OwnerUserID] == nil {
|
||||
rulesByOwner[r.OwnerUserID] = make(map[domain.PrivacyKey]domain.PrivacyRules, len(keys))
|
||||
}
|
||||
rulesByOwner[r.OwnerUserID][r.Key] = cloneRules(r)
|
||||
}
|
||||
}
|
||||
for _, owner := range owners {
|
||||
// owner 的联系人中哪些是本批 viewer(= privacy 的 ViewerIsContact,对应 contacts.Get(owner,viewer))。
|
||||
var ownerContacts map[int64]domain.Contact
|
||||
if s != nil && s.contacts != nil {
|
||||
var err error
|
||||
ownerContacts, err = s.contacts.GetMany(ctx, owner, viewers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
perViewer := make(map[int64]map[domain.PrivacyKey]bool, len(viewers))
|
||||
for _, viewer := range viewers {
|
||||
m := make(map[domain.PrivacyKey]bool, len(keys))
|
||||
if owner == viewer {
|
||||
for _, k := range keys {
|
||||
m[k] = true
|
||||
}
|
||||
perViewer[viewer] = m
|
||||
continue
|
||||
}
|
||||
_, isContact := ownerContacts[viewer]
|
||||
for _, k := range keys {
|
||||
rules, ok := rulesByOwner[owner][k]
|
||||
if !ok {
|
||||
rules = defaultRules(owner, k)
|
||||
}
|
||||
m[k] = Evaluate(rules, domain.PrivacyContext{
|
||||
OwnerUserID: owner,
|
||||
ViewerUserID: viewer,
|
||||
ViewerIsContact: isContact,
|
||||
})
|
||||
}
|
||||
perViewer[viewer] = m
|
||||
}
|
||||
out[owner] = perViewer
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func dedupNonZero(ids []int64) []int64 {
|
||||
seen := make(map[int64]struct{}, len(ids))
|
||||
out := make([]int64, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
if id == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[id] = struct{}{}
|
||||
out = append(out, id)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func Evaluate(rules domain.PrivacyRules, ctx domain.PrivacyContext) bool {
|
||||
if ctx.OwnerUserID != 0 && ctx.OwnerUserID == ctx.ViewerUserID {
|
||||
return true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue