Remove responsibility of objecttree to notify and move to synctree
This commit is contained in:
parent
4754c9704b
commit
212553d63d
2
common/commonspace/cache/treecache.go
vendored
2
common/commonspace/cache/treecache.go
vendored
@ -3,7 +3,6 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,5 +20,4 @@ type TreeResult struct {
|
|||||||
type TreeCache interface {
|
type TreeCache interface {
|
||||||
app.ComponentRunnable
|
app.ComponentRunnable
|
||||||
GetTree(ctx context.Context, id string) (TreeResult, error)
|
GetTree(ctx context.Context, id string) (TreeResult, error)
|
||||||
AddTree(ctx context.Context, payload storage.TreeStorageCreatePayload) error
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,8 @@ type Space interface {
|
|||||||
SyncService() syncservice.SyncService
|
SyncService() syncservice.SyncService
|
||||||
DiffService() diffservice.DiffService
|
DiffService() diffservice.DiffService
|
||||||
|
|
||||||
CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener tree.ObjectTreeUpdateListener) (tree.ObjectTree, error)
|
CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener synctree.UpdateListener) (tree.ObjectTree, error)
|
||||||
BuildTree(ctx context.Context, id string, listener tree.ObjectTreeUpdateListener) (tree.ObjectTree, error)
|
BuildTree(ctx context.Context, id string, listener synctree.UpdateListener) (tree.ObjectTree, error)
|
||||||
|
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
@ -65,11 +65,11 @@ func (s *space) DiffService() diffservice.DiffService {
|
|||||||
return s.diffService
|
return s.diffService
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener tree.ObjectTreeUpdateListener) (tree.ObjectTree, error) {
|
func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener synctree.UpdateListener) (tree.ObjectTree, error) {
|
||||||
return synctree.CreateSyncTree(payload, s.syncService, listener, nil, s.storage.CreateTreeStorage)
|
return synctree.CreateSyncTree(ctx, payload, s.syncService, listener, nil, s.storage.CreateTreeStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *space) BuildTree(ctx context.Context, id string, listener tree.ObjectTreeUpdateListener) (t tree.ObjectTree, err error) {
|
func (s *space) BuildTree(ctx context.Context, id string, listener synctree.UpdateListener) (t tree.ObjectTree, err error) {
|
||||||
getTreeRemote := func() (*spacesyncproto.ObjectSyncMessage, error) {
|
getTreeRemote := func() (*spacesyncproto.ObjectSyncMessage, error) {
|
||||||
// TODO: add empty context handling (when this is not happening due to head update)
|
// TODO: add empty context handling (when this is not happening due to head update)
|
||||||
peerId, err := syncservice.GetPeerIdFromStreamContext(ctx)
|
peerId, err := syncservice.GetPeerIdFromStreamContext(ctx)
|
||||||
@ -115,7 +115,7 @@ func (s *space) BuildTree(ctx context.Context, id string, listener tree.ObjectTr
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return synctree.BuildSyncTree(s.syncService, store.(treestorage.TreeStorage), listener, s.aclList)
|
return synctree.BuildSyncTree(ctx, s.syncService, store.(treestorage.TreeStorage), listener, s.aclList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *space) getObjectIds() []string {
|
func (s *space) getObjectIds() []string {
|
||||||
|
|||||||
@ -120,6 +120,7 @@ Loop:
|
|||||||
delete(s.peerStreams, id)
|
delete(s.peerStreams, id)
|
||||||
continue Loop
|
continue Loop
|
||||||
default:
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
streams = append(streams, stream)
|
streams = append(streams, stream)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,24 +10,35 @@ import (
|
|||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UpdateListener interface {
|
||||||
|
Update(tree tree.ObjectTree)
|
||||||
|
Rebuild(tree tree.ObjectTree)
|
||||||
|
}
|
||||||
|
|
||||||
type SyncTree struct {
|
type SyncTree struct {
|
||||||
tree.ObjectTree
|
tree.ObjectTree
|
||||||
syncService syncservice.SyncService
|
syncService syncservice.SyncService
|
||||||
|
listener UpdateListener
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSyncTree(
|
func CreateSyncTree(
|
||||||
|
ctx context.Context,
|
||||||
payload tree.ObjectTreeCreatePayload,
|
payload tree.ObjectTreeCreatePayload,
|
||||||
syncService syncservice.SyncService,
|
syncService syncservice.SyncService,
|
||||||
listener tree.ObjectTreeUpdateListener,
|
listener UpdateListener,
|
||||||
aclList list.ACLList,
|
aclList list.ACLList,
|
||||||
createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) {
|
createStorage storage.TreeStorageCreatorFunc) (t tree.ObjectTree, err error) {
|
||||||
t, err = tree.CreateObjectTree(payload, listener, aclList, createStorage)
|
t, err = tree.CreateObjectTree(payload, aclList, createStorage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
t = &SyncTree{
|
||||||
|
ObjectTree: t,
|
||||||
|
syncService: syncService,
|
||||||
|
listener: listener,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use context where it is needed
|
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||||
err = syncService.NotifyHeadUpdate(context.Background(), t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
|
||||||
Heads: t.Heads(),
|
Heads: t.Heads(),
|
||||||
SnapshotPath: t.SnapshotPath(),
|
SnapshotPath: t.SnapshotPath(),
|
||||||
})
|
})
|
||||||
@ -35,25 +46,31 @@ func CreateSyncTree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BuildSyncTree(
|
func BuildSyncTree(
|
||||||
|
ctx context.Context,
|
||||||
syncService syncservice.SyncService,
|
syncService syncservice.SyncService,
|
||||||
treeStorage storage.TreeStorage,
|
treeStorage storage.TreeStorage,
|
||||||
listener tree.ObjectTreeUpdateListener,
|
listener UpdateListener,
|
||||||
aclList list.ACLList) (t tree.ObjectTree, err error) {
|
aclList list.ACLList) (t tree.ObjectTree, err error) {
|
||||||
return buildSyncTree(syncService, treeStorage, listener, aclList)
|
return buildSyncTree(ctx, syncService, treeStorage, listener, aclList)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSyncTree(
|
func buildSyncTree(
|
||||||
|
ctx context.Context,
|
||||||
syncService syncservice.SyncService,
|
syncService syncservice.SyncService,
|
||||||
treeStorage storage.TreeStorage,
|
treeStorage storage.TreeStorage,
|
||||||
listener tree.ObjectTreeUpdateListener,
|
listener UpdateListener,
|
||||||
aclList list.ACLList) (t tree.ObjectTree, err error) {
|
aclList list.ACLList) (t tree.ObjectTree, err error) {
|
||||||
t, err = tree.BuildObjectTree(treeStorage, listener, aclList)
|
t, err = tree.BuildObjectTree(treeStorage, aclList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
t = &SyncTree{
|
||||||
|
ObjectTree: t,
|
||||||
|
syncService: syncService,
|
||||||
|
listener: listener,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: use context where it is needed
|
err = syncService.NotifyHeadUpdate(ctx, t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||||
err = syncService.NotifyHeadUpdate(context.Background(), t.ID(), t.Header(), &spacesyncproto.ObjectHeadUpdate{
|
|
||||||
Heads: t.Heads(),
|
Heads: t.Heads(),
|
||||||
SnapshotPath: t.SnapshotPath(),
|
SnapshotPath: t.SnapshotPath(),
|
||||||
})
|
})
|
||||||
@ -75,9 +92,18 @@ func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeCo
|
|||||||
|
|
||||||
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*aclpb.RawTreeChangeWithId) (res tree.AddResult, err error) {
|
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*aclpb.RawTreeChangeWithId) (res tree.AddResult, err error) {
|
||||||
res, err = s.AddRawChanges(ctx, changes...)
|
res, err = s.AddRawChanges(ctx, changes...)
|
||||||
if err != nil || res.Mode == tree.Nothing {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
switch res.Mode {
|
||||||
|
case tree.Nothing:
|
||||||
|
return
|
||||||
|
case tree.Append:
|
||||||
|
s.listener.Update(s)
|
||||||
|
case tree.Rebuild:
|
||||||
|
s.listener.Rebuild(s)
|
||||||
|
}
|
||||||
|
|
||||||
err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{
|
err = s.syncService.NotifyHeadUpdate(ctx, s.ID(), s.Header(), &spacesyncproto.ObjectHeadUpdate{
|
||||||
Heads: res.Heads,
|
Heads: res.Heads,
|
||||||
Changes: res.Added,
|
Changes: res.Added,
|
||||||
@ -85,3 +111,7 @@ func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*aclpb.RawTreeC
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SyncTree) Tree() tree.ObjectTree {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|||||||
@ -11,11 +11,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ObjectTreeUpdateListener interface {
|
|
||||||
Update(tree ObjectTree)
|
|
||||||
Rebuild(tree ObjectTree)
|
|
||||||
}
|
|
||||||
|
|
||||||
type RWLocker interface {
|
type RWLocker interface {
|
||||||
sync.Locker
|
sync.Locker
|
||||||
RLock()
|
RLock()
|
||||||
@ -71,7 +66,6 @@ type objectTree struct {
|
|||||||
rawChangeLoader *rawChangeLoader
|
rawChangeLoader *rawChangeLoader
|
||||||
treeBuilder *treeBuilder
|
treeBuilder *treeBuilder
|
||||||
aclList list.ACLList
|
aclList list.ACLList
|
||||||
updateListener ObjectTreeUpdateListener
|
|
||||||
|
|
||||||
id string
|
id string
|
||||||
header *aclpb.TreeHeader
|
header *aclpb.TreeHeader
|
||||||
@ -94,7 +88,6 @@ type objectTreeDeps struct {
|
|||||||
changeBuilder ChangeBuilder
|
changeBuilder ChangeBuilder
|
||||||
treeBuilder *treeBuilder
|
treeBuilder *treeBuilder
|
||||||
treeStorage storage.TreeStorage
|
treeStorage storage.TreeStorage
|
||||||
updateListener ObjectTreeUpdateListener
|
|
||||||
validator ObjectTreeValidator
|
validator ObjectTreeValidator
|
||||||
rawChangeLoader *rawChangeLoader
|
rawChangeLoader *rawChangeLoader
|
||||||
aclList list.ACLList
|
aclList list.ACLList
|
||||||
@ -102,7 +95,6 @@ type objectTreeDeps struct {
|
|||||||
|
|
||||||
func defaultObjectTreeDeps(
|
func defaultObjectTreeDeps(
|
||||||
treeStorage storage.TreeStorage,
|
treeStorage storage.TreeStorage,
|
||||||
listener ObjectTreeUpdateListener,
|
|
||||||
aclList list.ACLList) objectTreeDeps {
|
aclList list.ACLList) objectTreeDeps {
|
||||||
|
|
||||||
keychain := common.NewKeychain()
|
keychain := common.NewKeychain()
|
||||||
@ -112,7 +104,6 @@ func defaultObjectTreeDeps(
|
|||||||
changeBuilder: changeBuilder,
|
changeBuilder: changeBuilder,
|
||||||
treeBuilder: treeBuilder,
|
treeBuilder: treeBuilder,
|
||||||
treeStorage: treeStorage,
|
treeStorage: treeStorage,
|
||||||
updateListener: listener,
|
|
||||||
validator: newTreeValidator(),
|
validator: newTreeValidator(),
|
||||||
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
|
rawChangeLoader: newRawChangeLoader(treeStorage, changeBuilder),
|
||||||
aclList: aclList,
|
aclList: aclList,
|
||||||
@ -211,8 +202,7 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawTreeChangeWithId) (addResult AddResult, err error) {
|
func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.RawTreeChangeWithId) (addResult AddResult, err error) {
|
||||||
var mode Mode
|
addResult, err = ot.addRawChanges(ctx, rawChanges...)
|
||||||
mode, addResult, err = ot.addRawChanges(ctx, rawChanges...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -230,26 +220,10 @@ func (ot *objectTree) AddRawChanges(ctx context.Context, rawChanges ...*aclpb.Ra
|
|||||||
|
|
||||||
// setting heads
|
// setting heads
|
||||||
err = ot.treeStorage.SetHeads(ot.tree.Heads())
|
err = ot.treeStorage.SetHeads(ot.tree.Heads())
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ot.updateListener == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch mode {
|
|
||||||
case Append:
|
|
||||||
ot.updateListener.Update(ot)
|
|
||||||
case Rebuild:
|
|
||||||
ot.updateListener.Rebuild(ot)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.RawTreeChangeWithId) (mode Mode, addResult AddResult, err error) {
|
func (ot *objectTree) addRawChanges(ctx context.Context, rawChanges ...*aclpb.RawTreeChangeWithId) (addResult AddResult, err error) {
|
||||||
// resetting buffers
|
// resetting buffers
|
||||||
ot.tmpChangesBuf = ot.tmpChangesBuf[:0]
|
ot.tmpChangesBuf = ot.tmpChangesBuf[:0]
|
||||||
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
|
ot.notSeenIdxBuf = ot.notSeenIdxBuf[:0]
|
||||||
|
|||||||
@ -19,19 +19,18 @@ type ObjectTreeCreatePayload struct {
|
|||||||
TreeType aclpb.TreeHeaderType
|
TreeType aclpb.TreeHeaderType
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildObjectTree(treeStorage storage.TreeStorage, listener ObjectTreeUpdateListener, aclList list.ACLList) (ObjectTree, error) {
|
func BuildObjectTree(treeStorage storage.TreeStorage, aclList list.ACLList) (ObjectTree, error) {
|
||||||
deps := defaultObjectTreeDeps(treeStorage, listener, aclList)
|
deps := defaultObjectTreeDeps(treeStorage, aclList)
|
||||||
return buildObjectTree(deps)
|
return buildObjectTree(deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateObjectTree(
|
func CreateObjectTree(
|
||||||
payload ObjectTreeCreatePayload,
|
payload ObjectTreeCreatePayload,
|
||||||
listener ObjectTreeUpdateListener,
|
|
||||||
aclList list.ACLList,
|
aclList list.ACLList,
|
||||||
createStorage storage.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
createStorage storage.TreeStorageCreatorFunc) (objTree ObjectTree, err error) {
|
||||||
aclList.RLock()
|
aclList.RLock()
|
||||||
var (
|
var (
|
||||||
deps = defaultObjectTreeDeps(nil, listener, aclList)
|
deps = defaultObjectTreeDeps(nil, aclList)
|
||||||
state = aclList.ACLState()
|
state = aclList.ACLState()
|
||||||
aclId = aclList.ID()
|
aclId = aclList.ID()
|
||||||
aclHeadId = aclList.Head().Id
|
aclHeadId = aclList.Head().Id
|
||||||
@ -91,7 +90,6 @@ func CreateObjectTree(
|
|||||||
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
||||||
objTree := &objectTree{
|
objTree := &objectTree{
|
||||||
treeStorage: deps.treeStorage,
|
treeStorage: deps.treeStorage,
|
||||||
updateListener: deps.updateListener,
|
|
||||||
treeBuilder: deps.treeBuilder,
|
treeBuilder: deps.treeBuilder,
|
||||||
validator: deps.validator,
|
validator: deps.validator,
|
||||||
aclList: deps.aclList,
|
aclList: deps.aclList,
|
||||||
|
|||||||
@ -1,125 +0,0 @@
|
|||||||
package message
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
|
||||||
pool2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/net/pool"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/node"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/sync/requesthandler"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/syncproto"
|
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = logger.NewNamed("messageservice")
|
|
||||||
|
|
||||||
const CName = "MessageService"
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
nodes []*node.Node
|
|
||||||
requestHandler requesthandler.RequestHandler
|
|
||||||
pool pool2.Pool
|
|
||||||
sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func New() app.Component {
|
|
||||||
return &service{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service interface {
|
|
||||||
SendMessageAsync(peerId string, msg *syncproto.Sync) error
|
|
||||||
SendToSpaceAsync(spaceId string, msg *syncproto.Sync) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Init(a *app.App) (err error) {
|
|
||||||
s.requestHandler = a.MustComponent(requesthandler.CName).(requesthandler.RequestHandler)
|
|
||||||
s.nodes = a.MustComponent(node.CName).(node.Service).Nodes()
|
|
||||||
s.pool = a.MustComponent(pool2.CName).(pool2.Pool)
|
|
||||||
s.pool.AddHandler(syncproto.MessageType_MessageTypeSync, s.HandleMessage)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Name() (name string) {
|
|
||||||
return CName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Run(ctx context.Context) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Close(ctx context.Context) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) HandleMessage(ctx context.Context, msg *pool.Message) (err error) {
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
msg.AckError(syncproto.System_Error_UNKNOWN, err.Error())
|
|
||||||
} else {
|
|
||||||
msg.Ack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
syncMsg := &syncproto.Sync{}
|
|
||||||
err = proto.Unmarshal(msg.Data, syncMsg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
timeoutCtx, cancel := context.WithTimeout(ctx, time.Second*30)
|
|
||||||
defer cancel()
|
|
||||||
err = s.requestHandler.HandleSyncMessage(timeoutCtx, msg.Peer().Id(), syncMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) SendMessageAsync(peerId string, msg *syncproto.Sync) (err error) {
|
|
||||||
_, err = s.pool.DialAndAddPeer(context.Background(), peerId)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
marshalled, err := proto.Marshal(msg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
go s.sendAsync(peerId, msgInfo(msg), marshalled)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) SendToSpaceAsync(spaceId string, msg *syncproto.Sync) error {
|
|
||||||
for _, rp := range s.nodes {
|
|
||||||
s.SendMessageAsync(rp.PeerId, msg)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) sendAsync(peerId string, msgTypeStr string, marshalled []byte) error {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
|
|
||||||
defer cancel()
|
|
||||||
return s.pool.SendAndWait(ctx, peerId, &syncproto.Message{
|
|
||||||
Header: &syncproto.Header{
|
|
||||||
Type: syncproto.MessageType_MessageTypeSync,
|
|
||||||
DebugInfo: msgTypeStr,
|
|
||||||
},
|
|
||||||
Data: marshalled,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func msgInfo(content *syncproto.Sync) (syncMethod string) {
|
|
||||||
msg := content.GetMessage()
|
|
||||||
switch {
|
|
||||||
case msg.GetFullSyncRequest() != nil:
|
|
||||||
syncMethod = "FullSyncRequest"
|
|
||||||
case msg.GetFullSyncResponse() != nil:
|
|
||||||
syncMethod = "FullSyncResponse"
|
|
||||||
case msg.GetHeadUpdate() != nil:
|
|
||||||
syncMethod = "HeadUpdate"
|
|
||||||
}
|
|
||||||
syncMethod = fmt.Sprintf("method: %s, treeType: %s", syncMethod, content.TreeHeader.DocType.String())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@ -1,291 +0,0 @@
|
|||||||
package requesthandler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/aclchanges/aclpb"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/storage"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/pkg/acl/tree"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/service/treecache"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/syncproto"
|
|
||||||
"github.com/anytypeio/go-anytype-infrastructure-experiments/util/slice"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type requestHandler struct {
|
|
||||||
treeCache treecache.Service
|
|
||||||
account account.Service
|
|
||||||
messageService MessageSender
|
|
||||||
}
|
|
||||||
|
|
||||||
var log = logger.NewNamed("requesthandler")
|
|
||||||
|
|
||||||
func New() app.Component {
|
|
||||||
return &requestHandler{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestHandler interface {
|
|
||||||
HandleSyncMessage(ctx context.Context, senderId string, request *syncproto.Sync) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageSender interface {
|
|
||||||
SendMessageAsync(peerId string, msg *syncproto.Sync) error
|
|
||||||
SendToSpaceAsync(spaceId string, msg *syncproto.Sync) error
|
|
||||||
}
|
|
||||||
|
|
||||||
const CName = "SyncRequestHandler"
|
|
||||||
|
|
||||||
func (r *requestHandler) Init(a *app.App) (err error) {
|
|
||||||
r.treeCache = a.MustComponent(treecache.CName).(treecache.Service)
|
|
||||||
r.account = a.MustComponent(account.CName).(account.Service)
|
|
||||||
r.messageService = a.MustComponent("MessageService").(MessageSender)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) Name() (name string) {
|
|
||||||
return CName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) Run(ctx context.Context) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) Close(ctx context.Context) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) HandleSyncMessage(ctx context.Context, senderId string, content *syncproto.Sync) error {
|
|
||||||
msg := content.GetMessage()
|
|
||||||
switch {
|
|
||||||
case msg.GetFullSyncRequest() != nil:
|
|
||||||
return r.HandleFullSyncRequest(ctx, senderId, msg.GetFullSyncRequest(), content.GetTreeHeader(), content.GetTreeId())
|
|
||||||
case msg.GetFullSyncResponse() != nil:
|
|
||||||
return r.HandleFullSyncResponse(ctx, senderId, msg.GetFullSyncResponse(), content.GetTreeHeader(), content.GetTreeId())
|
|
||||||
case msg.GetHeadUpdate() != nil:
|
|
||||||
return r.HandleHeadUpdate(ctx, senderId, msg.GetHeadUpdate(), content.GetTreeHeader(), content.GetTreeId())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) HandleHeadUpdate(
|
|
||||||
ctx context.Context,
|
|
||||||
senderId string,
|
|
||||||
update *syncproto.SyncHeadUpdate,
|
|
||||||
header *aclpb.Header,
|
|
||||||
treeId string) (err error) {
|
|
||||||
|
|
||||||
var (
|
|
||||||
fullRequest *syncproto.SyncFullRequest
|
|
||||||
snapshotPath []string
|
|
||||||
result tree.AddResult
|
|
||||||
)
|
|
||||||
log.With(zap.String("peerId", senderId), zap.String("treeId", treeId)).
|
|
||||||
Debug("processing head update")
|
|
||||||
|
|
||||||
err = r.treeCache.Do(ctx, treeId, func(obj any) error {
|
|
||||||
objTree := obj.(tree.ObjectTree)
|
|
||||||
objTree.Lock()
|
|
||||||
defer objTree.Unlock()
|
|
||||||
|
|
||||||
if slice.UnsortedEquals(update.Heads, objTree.Heads()) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err = objTree.AddRawChanges(ctx, update.Changes...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we couldn't add all the changes
|
|
||||||
shouldFullSync := len(update.Changes) != len(result.Added)
|
|
||||||
snapshotPath = objTree.SnapshotPath()
|
|
||||||
if shouldFullSync {
|
|
||||||
fullRequest, err = r.prepareFullSyncRequest(objTree)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// if there are no such tree
|
|
||||||
if err == storage.ErrUnknownTreeId {
|
|
||||||
fullRequest = &syncproto.SyncFullRequest{}
|
|
||||||
}
|
|
||||||
// if we have incompatible heads, or we haven't seen the tree at all
|
|
||||||
if fullRequest != nil {
|
|
||||||
return r.messageService.SendMessageAsync(senderId, syncproto.WrapFullRequest(fullRequest, header, treeId))
|
|
||||||
}
|
|
||||||
// if error or nothing has changed
|
|
||||||
if err != nil || len(result.Added) == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise sending heads update message
|
|
||||||
newUpdate := &syncproto.SyncHeadUpdate{
|
|
||||||
Heads: result.Heads,
|
|
||||||
Changes: result.Added,
|
|
||||||
SnapshotPath: snapshotPath,
|
|
||||||
}
|
|
||||||
return r.messageService.SendToSpaceAsync("", syncproto.WrapHeadUpdate(newUpdate, header, treeId))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) HandleFullSyncRequest(
|
|
||||||
ctx context.Context,
|
|
||||||
senderId string,
|
|
||||||
request *syncproto.SyncFullRequest,
|
|
||||||
header *aclpb.Header,
|
|
||||||
treeId string) (err error) {
|
|
||||||
|
|
||||||
var fullResponse *syncproto.SyncFullResponse
|
|
||||||
err = r.treeCache.Do(ctx, treeId, func(obj any) error {
|
|
||||||
objTree := obj.(tree.ObjectTree)
|
|
||||||
objTree.Lock()
|
|
||||||
defer objTree.Unlock()
|
|
||||||
|
|
||||||
fullResponse, err = r.prepareFullSyncResponse(treeId, request.SnapshotPath, request.Heads, objTree)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return r.messageService.SendMessageAsync(senderId, syncproto.WrapFullResponse(fullResponse, header, treeId))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) HandleFullSyncResponse(
|
|
||||||
ctx context.Context,
|
|
||||||
senderId string,
|
|
||||||
response *syncproto.SyncFullResponse,
|
|
||||||
header *aclpb.Header,
|
|
||||||
treeId string) (err error) {
|
|
||||||
|
|
||||||
var (
|
|
||||||
snapshotPath []string
|
|
||||||
result tree.AddResult
|
|
||||||
)
|
|
||||||
|
|
||||||
err = r.treeCache.Do(ctx, treeId, func(obj interface{}) error {
|
|
||||||
objTree := obj.(tree.ObjectTree)
|
|
||||||
objTree.Lock()
|
|
||||||
defer objTree.Unlock()
|
|
||||||
|
|
||||||
// if we already have the heads for whatever reason
|
|
||||||
if slice.UnsortedEquals(response.Heads, objTree.Heads()) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err = objTree.AddRawChanges(ctx, response.Changes...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
snapshotPath = objTree.SnapshotPath()
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// if error or nothing has changed
|
|
||||||
if (err != nil || len(result.Added) == 0) && err != storage.ErrUnknownTreeId {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// if we have a new tree
|
|
||||||
if err == storage.ErrUnknownTreeId {
|
|
||||||
err = r.createTree(ctx, response, header, treeId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
result = tree.AddResult{
|
|
||||||
OldHeads: []string{},
|
|
||||||
Heads: response.Heads,
|
|
||||||
Added: response.Changes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// sending heads update message
|
|
||||||
newUpdate := &syncproto.SyncHeadUpdate{
|
|
||||||
Heads: result.Heads,
|
|
||||||
Changes: result.Added,
|
|
||||||
SnapshotPath: snapshotPath,
|
|
||||||
}
|
|
||||||
return r.messageService.SendToSpaceAsync("", syncproto.WrapHeadUpdate(newUpdate, header, treeId))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) HandleACLList(
|
|
||||||
ctx context.Context,
|
|
||||||
senderId string,
|
|
||||||
req *syncproto.SyncACLList,
|
|
||||||
header *aclpb.Header,
|
|
||||||
id string) (err error) {
|
|
||||||
|
|
||||||
err = r.treeCache.Do(ctx, id, func(obj interface{}) error {
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
// do nothing if already added
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// if not found then add to storage
|
|
||||||
if err == storage.ErrUnknownTreeId {
|
|
||||||
return r.createACLList(ctx, req, header, id)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) prepareFullSyncRequest(t tree.ObjectTree) (*syncproto.SyncFullRequest, error) {
|
|
||||||
return &syncproto.SyncFullRequest{
|
|
||||||
Heads: t.Heads(),
|
|
||||||
SnapshotPath: t.SnapshotPath(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) prepareFullSyncResponse(
|
|
||||||
treeId string,
|
|
||||||
theirPath, theirHeads []string,
|
|
||||||
t tree.ObjectTree) (*syncproto.SyncFullResponse, error) {
|
|
||||||
ourChanges, err := t.ChangesAfterCommonSnapshot(theirPath, theirHeads)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &syncproto.SyncFullResponse{
|
|
||||||
Heads: t.Heads(),
|
|
||||||
Changes: ourChanges,
|
|
||||||
SnapshotPath: t.SnapshotPath(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) createTree(
|
|
||||||
ctx context.Context,
|
|
||||||
response *syncproto.SyncFullResponse,
|
|
||||||
header *aclpb.Header,
|
|
||||||
treeId string) error {
|
|
||||||
|
|
||||||
return r.treeCache.Add(
|
|
||||||
ctx,
|
|
||||||
treeId,
|
|
||||||
storage.TreeStorageCreatePayload{
|
|
||||||
TreeId: treeId,
|
|
||||||
Header: header,
|
|
||||||
Changes: response.Changes,
|
|
||||||
Heads: response.Heads,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *requestHandler) createACLList(
|
|
||||||
ctx context.Context,
|
|
||||||
req *syncproto.SyncACLList,
|
|
||||||
header *aclpb.Header,
|
|
||||||
treeId string) error {
|
|
||||||
|
|
||||||
return r.treeCache.Add(
|
|
||||||
ctx,
|
|
||||||
treeId,
|
|
||||||
storage.ACLListStorageCreatePayload{
|
|
||||||
ListId: treeId,
|
|
||||||
Header: header,
|
|
||||||
Records: req.Records,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user