mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-07 21:47:02 +09:00
143 lines
3.2 KiB
Go
143 lines
3.2 KiB
Go
package aclwaiter
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/anyproto/any-sync/accountservice"
|
|
"github.com/anyproto/any-sync/app"
|
|
"github.com/anyproto/any-sync/app/logger"
|
|
"github.com/anyproto/any-sync/commonspace/acl/aclclient"
|
|
"github.com/anyproto/any-sync/commonspace/object/accountdata"
|
|
"github.com/anyproto/any-sync/commonspace/object/acl/list"
|
|
"github.com/anyproto/any-sync/commonspace/object/acl/recordverifier"
|
|
"github.com/anyproto/any-sync/util/periodicsync"
|
|
)
|
|
|
|
const CName = "common.acl.aclwaiter"
|
|
|
|
var log = logger.NewNamed(CName)
|
|
|
|
const (
|
|
checkIntervalSecs = 5
|
|
timeout = 20 * time.Second
|
|
)
|
|
|
|
type AclWaiter interface {
|
|
app.ComponentRunnable
|
|
}
|
|
|
|
type aclWaiter struct {
|
|
client aclclient.AclJoiningClient
|
|
keys *accountdata.AccountKeys
|
|
|
|
periodicCall periodicsync.PeriodicSync
|
|
|
|
acl list.AclList
|
|
spaceId string
|
|
aclHeadId string
|
|
prevHeadId string
|
|
|
|
onFinish func(acl list.AclList) error
|
|
onReject func(acl list.AclList) error
|
|
finished bool
|
|
}
|
|
|
|
func New(spaceId string, aclHeadId string, onFinish, onReject func(acl list.AclList) error) AclWaiter {
|
|
return &aclWaiter{
|
|
spaceId: spaceId,
|
|
aclHeadId: aclHeadId,
|
|
onFinish: onFinish,
|
|
onReject: onReject,
|
|
}
|
|
}
|
|
|
|
func (a *aclWaiter) Init(app *app.App) (err error) {
|
|
a.client = app.MustComponent(aclclient.CName).(aclclient.AclJoiningClient)
|
|
a.keys = app.MustComponent(accountservice.CName).(accountservice.Service).Account()
|
|
a.periodicCall = periodicsync.NewPeriodicSync(checkIntervalSecs, timeout, a.loop, log.With(zap.String("spaceId", a.spaceId)))
|
|
return nil
|
|
}
|
|
|
|
func (a *aclWaiter) Name() (name string) {
|
|
return CName
|
|
}
|
|
|
|
func (a *aclWaiter) loop(ctx context.Context) error {
|
|
if a.finished {
|
|
return nil
|
|
}
|
|
if a.acl == nil {
|
|
res, err := a.client.AclGetRecords(ctx, a.spaceId, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(res) == 0 {
|
|
return fmt.Errorf("acl not found")
|
|
}
|
|
storage, err := list.NewInMemoryStorage(res[0].Id, res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
acl, err := list.BuildAclListWithIdentity(a.keys, storage, recordverifier.NewValidateFull())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
a.acl = acl
|
|
a.prevHeadId = acl.Head().Id
|
|
} else {
|
|
prevId := a.prevHeadId
|
|
res, err := a.client.AclGetRecords(ctx, a.spaceId, prevId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(res) == 0 {
|
|
return nil
|
|
}
|
|
for _, rec := range res {
|
|
err := a.acl.AddRawRecord(rec)
|
|
if err != nil && !errors.Is(err, list.ErrRecordAlreadyExists) {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
// if the user was added
|
|
if !a.acl.AclState().Permissions(a.keys.SignKey.GetPublic()).NoPermissions() {
|
|
err := a.onFinish(a.acl)
|
|
if err == nil {
|
|
a.finished = true
|
|
return nil
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
// check the join record, if it exists
|
|
_, err := a.acl.AclState().JoinRecord(a.acl.AclState().Identity(), false)
|
|
if err != nil {
|
|
_, err = a.acl.Get(a.aclHeadId)
|
|
// that means the request was declined
|
|
if err == nil {
|
|
err := a.onReject(a.acl)
|
|
if err == nil {
|
|
a.finished = true
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (a *aclWaiter) Run(ctx context.Context) (err error) {
|
|
a.periodicCall.Run()
|
|
return nil
|
|
}
|
|
|
|
func (a *aclWaiter) Close(ctx context.Context) error {
|
|
a.periodicCall.Close()
|
|
return nil
|
|
}
|