1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-09 17:44:59 +09:00

GO-2046 Merge feature/spaces 4

This commit is contained in:
kirillston 2023-10-05 10:41:35 +02:00
commit b73ff52e74
No known key found for this signature in database
GPG key ID: 88218A7F1109754B
208 changed files with 7661 additions and 11484 deletions

View file

@ -1,10 +1,10 @@
dir: "{{.InterfaceDir}}/mock_{{.PackageName}}"
testonly: True
#testonly: True
with-expecter: True
all: False
outpkg: "mock_{{.PackageName}}"
packages:
github.com/anyproto/anytype-heart/space/typeprovider:
github.com/anyproto/anytype-heart/space/spacecore/typeprovider:
interfaces:
SmartBlockTypeProvider:
github.com/anyproto/anytype-heart/core/wallet:
@ -15,7 +15,7 @@ packages:
Sender:
github.com/anyproto/anytype-heart/core/block/getblock:
interfaces:
Picker:
ObjectGetter:
github.com/anyproto/anytype-heart/pkg/lib/core:
interfaces:
Service:
@ -38,12 +38,26 @@ packages:
github.com/anyproto/anytype-heart/core/system_object:
interfaces:
Service:
deriver:
github.com/anyproto/anytype-heart/core/filestorage/filesync:
interfaces:
FileSync:
github.com/anyproto/anytype-heart/space:
interfaces:
Service:
github.com/anyproto/anytype-heart/core/subscription:
interfaces:
CollectionService:
github.com/anyproto/anytype-heart/core/block/object/objectcache:
interfaces:
Cache:
github.com/anyproto/anytype-heart/core/indexer:
interfaces:
Indexer:
github.com/anyproto/anytype-heart/space/spacecore:
interfaces:
SpaceCoreService:
github.com/anyproto/anytype-heart/space/techspace:
interfaces:
TechSpace:
github.com/anyproto/anytype-heart/space:
interfaces:
bundledObjectsInstaller:
isNewAccount:

View file

@ -3,7 +3,7 @@ package service
import (
"fmt"
"github.com/anyproto/anytype-heart/space/localdiscovery"
"github.com/anyproto/anytype-heart/space/spacecore/localdiscovery"
)
type AndroidDiscoveryProxy interface {

View file

@ -4,19 +4,22 @@ import (
"context"
"fmt"
"path/filepath"
"sync"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/wallet"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/gateway"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/pkg/lib/threads"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/spacecore"
)
const CName = "account"
@ -26,15 +29,22 @@ var log = logging.Logger(CName)
type Service interface {
app.Component
GetInfo(ctx context.Context, spaceID string) (*model.AccountInfo, error)
Delete(ctx context.Context) (spacecore.NetworkStatus, error)
RevertDeletion(ctx context.Context) error
AccountID() string
PersonalSpaceID() string
}
type service struct {
spaceService space.Service
coreService core.Service
spaceCore spacecore.SpaceCoreService
spaceService space.SpaceService
wallet wallet.Wallet
gateway gateway.Gateway
config *config.Config
blockService *block.Service
objectCache objectcache.Cache
once sync.Once
personalSpaceID string
}
func New() Service {
@ -42,13 +52,30 @@ func New() Service {
}
func (s *service) Init(a *app.App) (err error) {
s.spaceService = app.MustComponent[space.Service](a)
s.coreService = app.MustComponent[core.Service](a)
s.spaceService = app.MustComponent[space.SpaceService](a)
s.spaceCore = app.MustComponent[spacecore.SpaceCoreService](a)
s.wallet = app.MustComponent[wallet.Wallet](a)
s.gateway = app.MustComponent[gateway.Gateway](a)
s.config = app.MustComponent[*config.Config](a)
s.blockService = app.MustComponent[*block.Service](a)
return nil
s.objectCache = app.MustComponent[objectcache.Cache](a)
s.personalSpaceID, err = s.spaceCore.DeriveID(context.Background(), spacecore.SpaceType)
return
}
func (s *service) Delete(ctx context.Context) (spacecore.NetworkStatus, error) {
return spacecore.NetworkStatus{}, fmt.Errorf("not implemented")
}
func (s *service) RevertDeletion(ctx context.Context) error {
return fmt.Errorf("not implemented")
}
func (s *service) AccountID() string {
return s.wallet.Account().SignKey.GetPublic().Account()
}
func (s *service) PersonalSpaceID() string {
return s.personalSpaceID
}
func (s *service) Name() (name string) {
@ -59,7 +86,7 @@ func (s *service) GetInfo(ctx context.Context, spaceID string) (*model.AccountIn
deviceKey := s.wallet.GetDevicePrivkey()
deviceId := deviceKey.GetPublic().Account()
analyticsId, err := s.getAnalyticsID()
analyticsId, err := s.getAnalyticsID(ctx)
if err != nil {
log.Errorf("failed to get analytics id: %s", err)
}
@ -75,14 +102,20 @@ func (s *service) GetInfo(ctx context.Context, spaceID string) (*model.AccountIn
cfg.CustomFileStorePath = s.wallet.RepoPath()
}
ids, err := s.coreService.DerivePredefinedObjects(ctx, spaceID, false)
// TODO Temporary
personalIds, err := s.getIds(ctx, s.PersonalSpaceID())
if err != nil {
return nil, fmt.Errorf("derive predefined objects: %w", err)
return nil, fmt.Errorf("failed to get derived ids: %w", err)
}
ids, err := s.getIds(ctx, spaceID)
if err != nil {
return nil, fmt.Errorf("failed to get derived ids: %w", err)
}
return &model.AccountInfo{
HomeObjectId: ids.Home,
ArchiveObjectId: ids.Archive,
ProfileObjectId: ids.Profile,
ProfileObjectId: personalIds.Profile,
MarketplaceWorkspaceId: addr.AnytypeMarketplaceWorkspace,
AccountSpaceId: spaceID,
WorkspaceObjectId: ids.Workspace,
@ -96,12 +129,26 @@ func (s *service) GetInfo(ctx context.Context, spaceID string) (*model.AccountIn
}, nil
}
func (s *service) getAnalyticsID() (string, error) {
func (s *service) getIds(ctx context.Context, spaceID string) (ids threads.DerivedSmartblockIds, err error) {
sp, err := s.spaceService.Get(ctx, spaceID)
if err != nil {
return
}
return sp.DerivedIDs(), nil
}
func (s *service) getAnalyticsID(ctx context.Context) (string, error) {
if s.config.AnalyticsId != "" {
return s.config.AnalyticsId, nil
}
accountObjectID := s.coreService.AccountObjects().Workspace
sb, err := s.blockService.PickBlock(context.Background(), accountObjectID)
ids, err := s.getIds(ctx, s.personalSpaceID)
if err != nil {
return "", fmt.Errorf("failed to get derived ids: %w", err)
}
sb, err := s.objectCache.GetObject(ctx, domain.FullID{
ObjectID: ids.Workspace,
SpaceID: s.personalSpaceID,
})
if err != nil {
return "", err
}

View file

@ -35,6 +35,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/converter"
"github.com/anyproto/anytype-heart/core/block/export"
importer "github.com/anyproto/anytype-heart/core/block/import"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/block/object/objectcreator"
"github.com/anyproto/anytype-heart/core/block/object/objectgraph"
@ -66,14 +67,16 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/clientserver"
"github.com/anyproto/anytype-heart/space/credentialprovider"
"github.com/anyproto/anytype-heart/space/localdiscovery"
"github.com/anyproto/anytype-heart/space/peermanager"
"github.com/anyproto/anytype-heart/space/peerstore"
"github.com/anyproto/anytype-heart/space/storage"
"github.com/anyproto/anytype-heart/space/syncstatusprovider"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/clientserver"
"github.com/anyproto/anytype-heart/space/spacecore/credentialprovider"
"github.com/anyproto/anytype-heart/space/spacecore/localdiscovery"
"github.com/anyproto/anytype-heart/space/spacecore/peermanager"
"github.com/anyproto/anytype-heart/space/spacecore/peerstore"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/syncstatusprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/space/techspace"
"github.com/anyproto/anytype-heart/util/builtinobjects"
"github.com/anyproto/anytype-heart/util/builtintemplate"
"github.com/anyproto/anytype-heart/util/linkpreview"
@ -199,11 +202,12 @@ func Bootstrap(a *app.App, components ...app.Component) {
Register(credentialprovider.New()).
Register(commonspace.New()).
Register(rpcstore.New()).
Register(space.New()).
Register(filestore.New()).
Register(fileservice.New()).
Register(filestorage.New()).
Register(filesync.New()).
Register(spacecore.New()).
Register(idresolver.New()).
Register(localdiscovery.New()).
Register(peermanager.New()).
Register(typeprovider.New()).
@ -239,6 +243,8 @@ func Bootstrap(a *app.App, components ...app.Component) {
Register(objectcreator.NewCreator()).
Register(kanban.New()).
Register(editor.NewObjectFactory()).
Register(techspace.New()).
Register(space.New()).
Register(objectgraph.NewBuilder()).
Register(account.New())
}

View file

@ -236,6 +236,10 @@ func (c *Config) GetConfigPath() string {
return filepath.Join(c.RepoPath, ConfigFileName)
}
func (c *Config) IsNewAccount() bool {
return c.NewAccount
}
func getRandomPort() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:0")
if err != nil {

View file

@ -16,7 +16,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
@ -87,7 +86,7 @@ func (s *Service) handleCustomStorageLocation(req *pb.RpcAccountCreateRequest, a
func (s *Service) setAccountAndProfileDetails(ctx context.Context, req *pb.RpcAccountCreateRequest, newAcc *model.Account) error {
newAcc.Name = req.Name
spaceID := app.MustComponent[space.Service](s.app).AccountId()
spaceID := app.MustComponent[account.Service](s.app).PersonalSpaceID()
var err error
newAcc.Info, err = app.MustComponent[account.Service](s.app).GetInfo(ctx, spaceID)
if err != nil {

View file

@ -14,13 +14,13 @@ import (
"github.com/anyproto/any-sync/util/crypto"
"github.com/anyproto/anytype-heart/core/anytype"
"github.com/anyproto/anytype-heart/core/anytype/account"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/metrics"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/builtinobjects"
"github.com/anyproto/anytype-heart/util/constant"
oserror "github.com/anyproto/anytype-heart/util/os"
@ -110,7 +110,7 @@ func (s *Service) CreateAccountFromExport(req *pb.RpcAccountRecoverFromLegacyExp
return "", err
}
spaceID := app.MustComponent[space.Service](s.app).AccountId()
spaceID := app.MustComponent[account.Service](s.app).PersonalSpaceID()
if err = s.app.MustComponent(builtinobjects.CName).(builtinobjects.BuiltinObjects).InjectMigrationDashboard(spaceID); err != nil {
return "", errors.Join(ErrBadInput, err)
}

View file

@ -4,10 +4,11 @@ import (
"context"
"errors"
"github.com/anyproto/anytype-heart/core/anytype/account"
"github.com/anyproto/anytype-heart/core/configfetcher"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/spacecore"
)
var (
@ -18,26 +19,44 @@ var (
func (s *Service) AccountDelete(ctx context.Context, req *pb.RpcAccountDeleteRequest) (*model.AccountStatus, error) {
s.lock.RLock()
defer s.lock.RUnlock()
spaceService := s.app.MustComponent(space.CName).(space.Service)
resp, err := spaceService.DeleteAccount(ctx, req.Revert)
status := &model.AccountStatus{
StatusType: model.AccountStatusType(resp.Status),
DeletionDate: resp.DeletionDate.Unix(),
convErr := func(err error) error {
switch err {
case spacecore.ErrSpaceIsDeleted:
return ErrAccountIsAlreadyDeleted
case spacecore.ErrSpaceDeletionPending:
return ErrAccountIsAlreadyDeleted
case spacecore.ErrSpaceIsCreated:
return ErrAccountIsActive
default:
return err
}
}
var (
accountService = s.app.MustComponent(account.CName).(account.Service)
status *model.AccountStatus
)
if !req.Revert {
networkStatus, err := accountService.Delete(ctx)
if err != nil {
return nil, convErr(err)
}
status = &model.AccountStatus{
StatusType: model.AccountStatusType(networkStatus.Status),
DeletionDate: networkStatus.DeletionDate.Unix(),
}
} else {
err := accountService.RevertDeletion(ctx)
if err != nil {
return nil, convErr(err)
}
status = &model.AccountStatus{
StatusType: model.AccountStatusType(spacecore.SpaceStatusCreated),
}
}
// so we will receive updated account status
s.refreshRemoteAccountState()
switch err {
case space.ErrSpaceIsDeleted:
return nil, ErrAccountIsAlreadyDeleted
case space.ErrSpaceDeletionPending:
return nil, ErrAccountIsAlreadyDeleted
case space.ErrSpaceIsCreated:
return nil, ErrAccountIsActive
}
return status, err
return status, nil
}
func (s *Service) refreshRemoteAccountState() {

View file

@ -3,7 +3,7 @@ package application
import (
"github.com/anyproto/any-sync/app"
"github.com/anyproto/anytype-heart/space/localdiscovery"
"github.com/anyproto/anytype-heart/space/spacecore/localdiscovery"
)
func (s *Service) EnableLocalNetworkSync() error {

View file

@ -19,7 +19,6 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
)
// we cannot check the constant error from badger because they hardcoded it there
@ -50,7 +49,7 @@ func (s *Service) AccountSelect(ctx context.Context, req *pb.RpcAccountSelectReq
objectCache := app.MustComponent[objectcache.Cache](s.app)
objectCache.CloseBlocks()
spaceID := app.MustComponent[space.Service](s.app).AccountId()
spaceID := app.MustComponent[account.Service](s.app).PersonalSpaceID()
acc := &model.Account{Id: req.Id}
var err error
acc.Info, err = app.MustComponent[account.Service](s.app).GetInfo(ctx, spaceID)
@ -122,7 +121,7 @@ func (s *Service) AccountSelect(ctx context.Context, req *pb.RpcAccountSelectReq
}
acc := &model.Account{Id: req.Id}
spaceID := app.MustComponent[space.Service](s.app).AccountId()
spaceID := app.MustComponent[account.Service](s.app).PersonalSpaceID()
acc.Info, err = app.MustComponent[account.Service](s.app).GetInfo(ctx, spaceID)
return acc, nil
}

View file

@ -6,16 +6,18 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/session"
)
type Picker interface {
PickBlock(ctx context.Context, objectID string) (sb smartblock.SmartBlock, err error)
type ObjectGetter interface {
GetObject(ctx context.Context, objectID string) (sb smartblock.SmartBlock, err error)
GetObjectByFullID(ctx context.Context, id domain.FullID) (sb smartblock.SmartBlock, err error)
}
func Do[t any](p Picker, objectID string, apply func(sb t) error) error {
func Do[t any](p ObjectGetter, objectID string, apply func(sb t) error) error {
ctx := context.Background()
sb, err := p.PickBlock(ctx, objectID)
sb, err := p.GetObject(ctx, objectID)
if err != nil {
return err
}
@ -31,8 +33,25 @@ func Do[t any](p Picker, objectID string, apply func(sb t) error) error {
return apply(bb)
}
func DoContext[t any](p Picker, ctx context.Context, objectID string, apply func(sb t) error) error {
sb, err := p.PickBlock(ctx, objectID)
func DoContext[t any](p ObjectGetter, ctx context.Context, objectID string, apply func(sb t) error) error {
sb, err := p.GetObject(ctx, objectID)
if err != nil {
return err
}
bb, ok := sb.(t)
if !ok {
var dummy = new(t)
return fmt.Errorf("the interface %T is not implemented in %T", dummy, sb)
}
sb.Lock()
defer sb.Unlock()
return apply(bb)
}
func DoContextFullID[t any](p ObjectGetter, ctx context.Context, id domain.FullID, apply func(sb t) error) error {
sb, err := p.GetObjectByFullID(ctx, id)
if err != nil {
return err
}
@ -50,7 +69,7 @@ func DoContext[t any](p Picker, ctx context.Context, objectID string, apply func
// DoState2 picks two blocks and perform an action on them. The order of locks is always the same for two ids.
// It correctly handles the case when two ids are the same.
func DoState2[t1, t2 any](s Picker, firstID, secondID string, f func(*state.State, *state.State, t1, t2) error) error {
func DoState2[t1, t2 any](s ObjectGetter, firstID, secondID string, f func(*state.State, *state.State, t1, t2) error) error {
if firstID == secondID {
return DoStateAsync(s, firstID, func(st *state.State, b t1) error {
// Check that b satisfies t2
@ -76,9 +95,9 @@ func DoState2[t1, t2 any](s Picker, firstID, secondID string, f func(*state.Stat
})
}
func DoStateAsync[t any](p Picker, id string, apply func(s *state.State, sb t) error, flags ...smartblock.ApplyFlag) error {
func DoStateAsync[t any](p ObjectGetter, id string, apply func(s *state.State, sb t) error, flags ...smartblock.ApplyFlag) error {
ctx := context.Background()
sb, err := p.PickBlock(ctx, id)
sb, err := p.GetObject(ctx, id)
if err != nil {
return err
}
@ -102,8 +121,8 @@ func DoStateAsync[t any](p Picker, id string, apply func(s *state.State, sb t) e
}
// TODO rename to something more meaningful
func DoStateCtx[t any](p Picker, ctx session.Context, id string, apply func(s *state.State, sb t) error, flags ...smartblock.ApplyFlag) error {
sb, err := p.PickBlock(context.Background(), id)
func DoStateCtx[t any](p ObjectGetter, ctx session.Context, id string, apply func(s *state.State, sb t) error, flags ...smartblock.ApplyFlag) error {
sb, err := p.GetObject(context.Background(), id)
if err != nil {
return err
}

View file

@ -35,7 +35,7 @@ type Service struct {
lock *sync.RWMutex
collections map[string]map[string]chan []string
systemObjectService system_object.Service
picker block.Picker
picker block.ObjectGetter
objectStore objectstore.ObjectStore
}
@ -47,7 +47,7 @@ func New() *Service {
}
func (s *Service) Init(a *app.App) (err error) {
s.picker = app.MustComponent[block.Picker](a)
s.picker = app.MustComponent[block.ObjectGetter](a)
s.objectStore = app.MustComponent[objectstore.ObjectStore](a)
s.systemObjectService = app.MustComponent[system_object.Service](a)
return nil

View file

@ -26,7 +26,11 @@ type testPicker struct {
sb smartblock.SmartBlock
}
func (t *testPicker) PickBlock(ctx context.Context, id string) (sb smartblock.SmartBlock, err error) {
func (t *testPicker) GetObject(ctx context.Context, id string) (sb smartblock.SmartBlock, err error) {
return t.sb, nil
}
func (t *testPicker) GetObjectByFullID(ctx context.Context, id domain.FullID) (sb smartblock.SmartBlock, err error) {
return t.sb, nil
}

View file

@ -6,7 +6,6 @@ import (
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -31,13 +30,13 @@ func (s *Service) TemplateCreateFromObject(ctx context.Context, id string) (temp
return fmt.Errorf("can't make template from this obect type")
}
objectTypeKeys = b.ObjectTypeKeys()
st, err = b.TemplateCreateFromObjectState()
st, err = s.templateCreateFromObjectState(b)
return err
}); err != nil {
return
}
spaceID, err := s.ResolveSpaceID(id)
spaceID, err := s.resolver.ResolveSpaceID(id)
if err != nil {
return "", fmt.Errorf("resolve spaceID: %w", err)
}
@ -49,6 +48,23 @@ func (s *Service) TemplateCreateFromObject(ctx context.Context, id string) (temp
return
}
func (s *Service) templateCreateFromObjectState(sb smartblock.SmartBlock) (*state.State, error) {
st := sb.NewState().Copy()
st.SetLocalDetails(nil)
targetObjectTypeID, err := s.systemObjectService.GetTypeIdByKey(context.Background(), sb.SpaceID(), st.ObjectTypeKey())
if err != nil {
return nil, fmt.Errorf("get type id by key: %s", err)
}
st.SetDetail(bundle.RelationKeyTargetObjectType.String(), pbtypes.String(targetObjectTypeID))
st.SetObjectTypeKeys([]domain.TypeKey{bundle.TypeKeyTemplate, st.ObjectTypeKey()})
for _, rel := range sb.Relations(st) {
if rel.DataSource == model.Relation_details && !rel.Hidden {
st.RemoveDetail(rel.Key)
}
}
return st, nil
}
func (s *Service) TemplateClone(spaceID string, id string) (templateID string, err error) {
var (
st *state.State
@ -104,7 +120,7 @@ func (s *Service) ObjectDuplicate(ctx context.Context, id string) (objectID stri
return
}
spaceID, err := s.spaceService.ResolveSpaceID(id)
spaceID, err := s.resolver.ResolveSpaceID(id)
if err != nil {
return "", fmt.Errorf("resolve spaceID: %w", err)
}
@ -146,39 +162,11 @@ func (s *Service) TemplateCreateFromObjectByObjectType(ctx context.Context, obje
}
func (s *Service) CreateWorkspace(ctx context.Context, req *pb.RpcWorkspaceCreateRequest) (spaceID string, err error) {
spc, err := s.spaceService.CreateSpace(ctx)
newSpace, err := s.spaceService.Create(ctx)
if err != nil {
return "", fmt.Errorf("create space: %w", err)
}
predefinedObjectIDs, err := s.anytype.DerivePredefinedObjects(ctx, spc.Id(), true)
if err != nil {
// TODO Delete space?
return "", fmt.Errorf("derive workspace object for space %s: %w", spc.Id(), err)
}
err = DoStateAsync(s, s.anytype.AccountObjects().Workspace, func(st *state.State, b *editor.Workspaces) error {
spaces := pbtypes.CopyVal(st.Store().GetFields()["spaces"])
if spaces == nil {
spaces = pbtypes.Struct(&types.Struct{
Fields: map[string]*types.Value{
spc.Id(): pbtypes.String(predefinedObjectIDs.Workspace),
},
})
} else {
spaces.GetStructValue().Fields[spc.Id()] = pbtypes.String(predefinedObjectIDs.Workspace)
}
st.SetInStore([]string{"spaces"}, spaces)
return nil
})
if err != nil {
return "", fmt.Errorf("add space to account space: %w", err)
}
err = s.indexer.EnsurePreinstalledObjects(spc.Id())
if err != nil {
return "", fmt.Errorf("reindex space %s: %w", spc.Id(), err)
return "", fmt.Errorf("error creating space: %w", err)
}
predefinedObjectIDs := newSpace.DerivedIDs()
err = Do(s, predefinedObjectIDs.Workspace, func(b basic.DetailsSettable) error {
details := make([]*pb.RpcObjectSetDetailsDetail, 0, len(req.Details.GetFields()))
@ -191,14 +179,13 @@ func (s *Service) CreateWorkspace(ctx context.Context, req *pb.RpcWorkspaceCreat
return b.SetDetails(nil, details, true)
})
if err != nil {
return "", fmt.Errorf("set details for space %s: %w", spc.Id(), err)
return "", fmt.Errorf("set details for space %s: %w", newSpace.Id(), err)
}
_, err = s.builtinObjectService.CreateObjectsForUseCase(nil, spc.Id(), req.UseCase)
_, err = s.builtinObjectService.CreateObjectsForUseCase(nil, newSpace.Id(), req.UseCase)
if err != nil {
return "", fmt.Errorf("import use-case: %w", err)
}
return spc.Id(), err
return newSpace.Id(), err
}
// CreateLinkToTheNewObject creates an object and stores the link to it in the context block

View file

@ -1,76 +0,0 @@
package block
import (
"context"
"fmt"
"time"
"github.com/anyproto/any-sync/commonspace"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/domain"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
)
func (s *Service) CreateTreePayload(ctx context.Context, spaceID string, tp coresb.SmartBlockType, createdTime time.Time) (treestorage.TreeStorageCreatePayload, error) {
space, err := s.spaceService.GetSpace(ctx, spaceID)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
return s.CreateTreePayloadWithSpaceAndCreatedTime(ctx, space, tp, createdTime)
}
func (s *Service) CreateTreePayloadWithSpace(ctx context.Context, space commonspace.Space, tp coresb.SmartBlockType) (treestorage.TreeStorageCreatePayload, error) {
return s.CreateTreePayloadWithSpaceAndCreatedTime(ctx, space, tp, time.Now())
}
func (s *Service) CreateTreePayloadWithSpaceAndCreatedTime(ctx context.Context, space commonspace.Space, tp coresb.SmartBlockType, createdTime time.Time) (treestorage.TreeStorageCreatePayload, error) {
changePayload, err := createChangePayload(tp, nil)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
treePayload, err := createPayload(space.Id(), s.commonAccount.Account().SignKey, changePayload, createdTime.Unix())
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
return space.TreeBuilder().CreateTree(ctx, treePayload)
}
func (s *Service) CreateTreeObjectWithPayload(ctx context.Context, spaceID string, payload treestorage.TreeStorageCreatePayload, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error) {
space, err := s.spaceService.GetSpace(ctx, spaceID)
if err != nil {
return nil, err
}
id := domain.FullID{
SpaceID: spaceID,
ObjectID: payload.RootRawChange.Id,
}
tr, err := space.TreeBuilder().PutTree(ctx, payload, nil)
if err != nil {
err = fmt.Errorf("failed to put tree: %w", err)
return
}
if tr != nil {
tr.Close()
}
return s.cacheCreatedObject(ctx, id, initFunc)
}
func (s *Service) CreateTreeObject(ctx context.Context, spaceID string, tp coresb.SmartBlockType, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error) {
space, err := s.spaceService.GetSpace(ctx, spaceID)
if err != nil {
return nil, err
}
payload, err := s.CreateTreePayloadWithSpace(ctx, space, tp)
if err != nil {
return nil, err
}
return s.CreateTreeObjectWithPayload(ctx, spaceID, payload, initFunc)
}
func (s *Service) cacheCreatedObject(ctx context.Context, id domain.FullID, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error) {
ctx = objectcache.ContextWithCreateOption(ctx, initFunc)
return s.objectCache.GetObject(ctx, id)
}

View file

@ -18,7 +18,7 @@ import (
)
func (s *Service) DeleteObject(objectID string) (err error) {
spaceID, err := s.spaceService.ResolveSpaceID(objectID)
spaceID, err := s.resolver.ResolveSpaceID(objectID)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -70,7 +70,8 @@ func (s *Service) DeleteObject(objectID string) (err error) {
})
default:
var space commonspace.Space
space, err = s.spaceService.GetSpace(context.Background(), spaceID)
// TODO: [MR] should we do this via spaceService instead?
space, err = s.spaceCore.Get(context.Background(), spaceID)
if err != nil {
return
}

View file

@ -1,115 +0,0 @@
package block
import (
"context"
"errors"
"fmt"
"time"
"github.com/anyproto/any-sync/commonspace"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/block/source"
"github.com/anyproto/anytype-heart/core/domain"
)
const (
derivedObjectLoadTimeout = time.Minute * 30
)
// DeriveTreeCreatePayload creates payload for the tree of derived object.
// Method should be called before DeriveObject to prepare payload
func (s *Service) DeriveTreeCreatePayload(
ctx context.Context,
spaceID string,
key domain.UniqueKey,
) (treestorage.TreeStorageCreatePayload, error) {
space, err := s.spaceService.GetSpace(ctx, spaceID)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
changePayload, err := createChangePayload(key.SmartblockType(), key)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
treePayload := derivePayload(space.Id(), s.commonAccount.Account().SignKey, changePayload)
create, err := space.TreeBuilder().CreateTree(context.Background(), treePayload)
return create, err
}
// DeriveObject derives the object with id specified in the payload and triggers cache.Get
// DeriveTreeCreatePayload should be called first to prepare the payload and derive the tree
func (s *Service) DeriveObject(
ctx context.Context, spaceID string, payload treestorage.TreeStorageCreatePayload, newAccount bool,
) (err error) {
space, err := s.spaceService.GetSpace(ctx, spaceID)
if err != nil {
return fmt.Errorf("get space: %w", err)
}
_, err = s.getDerivedObject(ctx, space, &payload, newAccount, func(id string) *smartblock.InitContext {
return &smartblock.InitContext{Ctx: ctx, SpaceID: spaceID, State: state.NewDoc(id, nil).(*state.State)}
})
if err != nil {
log.With(zap.Error(err)).Debug("derived object with error")
return
}
return nil
}
func (s *Service) DeriveTreeObjectWithUniqueKey(ctx context.Context, spaceID string, key domain.UniqueKey, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error) {
payload, err := s.DeriveTreeCreatePayload(ctx, spaceID, key)
if err != nil {
return nil, err
}
return s.CreateTreeObjectWithPayload(ctx, spaceID, payload, initFunc)
}
func (s *Service) getDerivedObject(
ctx context.Context, space commonspace.Space, payload *treestorage.TreeStorageCreatePayload, newAccount bool, initFunc smartblock.InitFunc,
) (sb smartblock.SmartBlock, err error) {
id := domain.FullID{
SpaceID: space.Id(),
ObjectID: payload.RootRawChange.Id,
}
if newAccount {
var tr objecttree.ObjectTree
tr, err = space.TreeBuilder().PutTree(ctx, *payload, nil)
s.predefinedObjectWasMissing = true
if err != nil {
if !errors.Is(err, treestorage.ErrTreeExists) {
err = fmt.Errorf("failed to put tree: %w", err)
return
}
s.predefinedObjectWasMissing = false
// the object exists locally
return s.objectCache.GetObjectWithTimeout(ctx, id)
}
tr.Close()
return s.cacheCreatedObject(ctx, id, initFunc)
}
// timing out when getting objects from remote
// here we set very long timeout, because we must load these documents
ctx, cancel := context.WithTimeout(ctx, derivedObjectLoadTimeout)
// TODO: revive p2p (right now we are not ready to load from local clients due to the fact that we need to know when local peers connect)
ctx = objectcache.ContextWithBuildOptions(ctx, source.BuildOptions{})
defer cancel()
sb, err = s.objectCache.GetObjectWithTimeout(ctx, id)
if err != nil {
if errors.Is(err, treechangeproto.ErrGetTree) {
err = spacesyncproto.ErrSpaceMissing
}
err = fmt.Errorf("failed to get object from node: %w", err)
return
}
return
}

View file

@ -374,7 +374,7 @@ func (bs *basic) AddRelationAndSet(ctx session.Context, systemObjectService syst
return smartblock.ErrSimpleBlockNotFound
}
rel, err := systemObjectService.FetchRelationByKey(s.SpaceID(), req.RelationKey)
rel, err := systemObjectService.FetchRelationByKey(bs.SpaceID(), req.RelationKey)
if err != nil {
return
}

View file

@ -104,7 +104,7 @@ func (bs *basic) createDetailUpdate(st *state.State, detail *pb.RpcObjectSetDeta
if err := bs.addRelationLink(detail.Key, st); err != nil {
return nil, err
}
if err := bs.validateDetailFormat(st.SpaceID(), detail.Key, detail.Value); err != nil {
if err := bs.validateDetailFormat(bs.SpaceID(), detail.Key, detail.Value); err != nil {
return nil, fmt.Errorf("failed to validate relation: %w", err)
}
}
@ -259,7 +259,7 @@ func (bs *basic) setDetailSpecialCases(st *state.State, detail *pb.RpcObjectSetD
func (bs *basic) addRelationLink(relationKey string, st *state.State) error {
// TODO: add relation.WithWorkspaceId(workspaceId) filter
rel, err := bs.systemObjectService.FetchRelationByKey(st.SpaceID(), relationKey)
rel, err := bs.systemObjectService.FetchRelationByKey(bs.SpaceID(), relationKey)
if err != nil || rel == nil {
return fmt.Errorf("failed to get relation: %w", err)
}

View file

@ -26,7 +26,7 @@ var log = logging.Logger("bookmark")
func NewBookmark(
sb smartblock.SmartBlock,
picker getblock.Picker,
picker getblock.ObjectGetter,
bookmarkSvc BookmarkService,
objectStore objectstore.ObjectStore,
) Bookmark {
@ -51,7 +51,7 @@ type BookmarkService interface {
type sbookmark struct {
smartblock.SmartBlock
picker getblock.Picker
picker getblock.ObjectGetter
bookmarkSvc BookmarkService
objectStore objectstore.ObjectStore
}

View file

@ -18,7 +18,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)

View file

@ -23,7 +23,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -105,7 +105,7 @@ func (d *sdataview) SetSource(ctx session.Context, blockId string, source []stri
return d.Apply(s, smartblock.NoRestrictions)
}
dvContent, _, err := BlockBySource(s.SpaceID(), d.sbtProvider, d.systemObjectService, source)
dvContent, _, err := BlockBySource(d.SpaceID(), d.sbtProvider, d.systemObjectService, source)
if err != nil {
return
}
@ -130,7 +130,7 @@ func (d *sdataview) AddRelations(ctx session.Context, blockId string, relationKe
return err
}
for _, key := range relationKeys {
relation, err2 := d.systemObjectService.FetchRelationByKey(s.SpaceID(), key)
relation, err2 := d.systemObjectService.FetchRelationByKey(d.SpaceID(), key)
if err2 != nil {
return err2
}

View file

@ -1,10 +1,12 @@
package editor
import (
"context"
"fmt"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block/editor/bookmark"
@ -22,11 +24,24 @@ import (
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
)
var log = logging.Logger("anytype-mw-editor")
type spaceIndexer interface {
smartblock.Indexer
ReindexSpace(spaceID string) error
}
type personalIDProvider interface {
PersonalSpaceID() string
}
type bundledObjectsInstaller interface {
InstallBundledObjects(ctx context.Context, spaceID string, ids []string) ([]string, []*types.Struct, error)
}
type ObjectFactory struct {
anytype core.Service
bookmarkService bookmark.BookmarkService
@ -40,10 +55,11 @@ type ObjectFactory struct {
tempDirProvider core.TempDirProvider
fileService files.Service
config *config.Config
picker getblock.Picker
picker getblock.ObjectGetter
eventSender event.Sender
restrictionService restriction.Service
indexer smartblock.Indexer
indexer spaceIndexer
spaceService spaceService
objectDeriver objectDeriver
}
@ -65,10 +81,11 @@ func (f *ObjectFactory) Init(a *app.App) (err error) {
f.tempDirProvider = app.MustComponent[core.TempDirProvider](a)
f.sbtProvider = app.MustComponent[typeprovider.SmartBlockTypeProvider](a)
f.layoutConverter = app.MustComponent[converter.LayoutConverter](a)
f.picker = app.MustComponent[getblock.Picker](a)
f.indexer = app.MustComponent[smartblock.Indexer](a)
f.picker = app.MustComponent[getblock.ObjectGetter](a)
f.indexer = app.MustComponent[spaceIndexer](a)
f.eventSender = app.MustComponent[event.Sender](a)
f.objectDeriver = app.MustComponent[objectDeriver](a)
f.spaceService = app.MustComponent[spaceService](a)
return nil
}
@ -214,6 +231,11 @@ func (f *ObjectFactory) New(sbType coresb.SmartBlockType) (smartblock.SmartBlock
f.eventSender,
f.objectDeriver,
), nil
case coresb.SmartBlockTypeSpaceView:
return newSpaceView(
sb,
f.spaceService,
), nil
case coresb.SmartBlockTypeMissingObject:
return NewMissingObject(sb), nil
case coresb.SmartBlockTypeWidget:

View file

@ -47,7 +47,7 @@ func NewFile(
idGetter PredefinedObjectsGetter,
tempDirProvider core.TempDirProvider,
fileService files.Service,
picker getblock.Picker,
picker getblock.ObjectGetter,
) File {
return &sfile{
SmartBlock: sb,
@ -88,7 +88,7 @@ type sfile struct {
fileSource BlockService
tempDirProvider core.TempDirProvider
fileService files.Service
picker getblock.Picker
picker getblock.ObjectGetter
predefinedObjects PredefinedObjectsGetter
}
@ -322,7 +322,7 @@ type dropFilesProcess struct {
id string
spaceID string
s BlockService
picker getblock.Picker
picker getblock.ObjectGetter
fileService files.Service
tempDirProvider core.TempDirProvider
root *dropFileEntry

View file

@ -45,7 +45,7 @@ func NewUploader(
s BlockService,
fileService files.Service,
provider core.TempDirProvider,
picker getblock.Picker,
picker getblock.ObjectGetter,
) Uploader {
return &uploader{
spaceID: spaceID,
@ -107,7 +107,7 @@ func (ur UploadResult) ToBlock() file.Block {
type uploader struct {
spaceID string
service BlockService
picker getblock.Picker
picker getblock.ObjectGetter
block file.Block
getReader func(ctx context.Context) (*fileReader, error)
name string

View file

@ -42,7 +42,7 @@ func TestUploader_Upload(t *testing.T) {
fx.fileService.EXPECT().ImageAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(im, nil)
im.EXPECT().GetOriginalFile(gomock.Any()).Return(fx.file, nil)
b := newBlock(model.BlockContentFile_Image)
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.file.EXPECT().Meta().Return(&files.FileMeta{Media: "image/jpg"}).AnyTimes()
res := fx.Uploader.SetBlock(b).SetFile("./testdata/unnamed.jpg").Upload(ctx)
require.NoError(t, res.Err)
@ -55,7 +55,7 @@ func TestUploader_Upload(t *testing.T) {
fx := newFixture(t)
defer fx.tearDown()
im := fx.newImage("123")
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.fileService.EXPECT().ImageAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(im, nil)
im.EXPECT().GetOriginalFile(gomock.Any())
res := fx.Uploader.AutoType(true).SetFile("./testdata/unnamed.jpg").Upload(ctx)
@ -71,7 +71,7 @@ func TestUploader_Upload(t *testing.T) {
Added: time.Now(),
}
// fx.anytype.EXPECT().ImageAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, image.ErrFormat)
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.fileService.EXPECT().FileAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(fx.newFile("123", meta), nil)
b := newBlock(model.BlockContentFile_Image)
res := fx.Uploader.SetBlock(b).SetFile("./testdata/test.txt").Upload(ctx)
@ -92,7 +92,7 @@ func TestUploader_Upload(t *testing.T) {
fx := newFixture(t)
defer fx.tearDown()
im := fx.newImage("123")
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.fileService.EXPECT().ImageAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(im, nil)
im.EXPECT().GetOriginalFile(gomock.Any())
res := fx.Uploader.AutoType(true).SetUrl(serv.URL + "/unnamed.jpg").Upload(ctx)
@ -115,7 +115,7 @@ func TestUploader_Upload(t *testing.T) {
fx := newFixture(t)
defer fx.tearDown()
im := fx.newImage("123")
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.fileService.EXPECT().ImageAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(im, nil)
im.EXPECT().GetOriginalFile(gomock.Any())
res := fx.Uploader.AutoType(true).SetUrl(serv.URL + "/unnamed.jpg").Upload(ctx)
@ -137,7 +137,7 @@ func TestUploader_Upload(t *testing.T) {
fx := newFixture(t)
defer fx.tearDown()
im := fx.newImage("123")
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.fileService.EXPECT().ImageAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(im, nil)
im.EXPECT().GetOriginalFile(gomock.Any())
res := fx.Uploader.AutoType(true).SetUrl(serv.URL + "/unnamed.jpg?text=text").Upload(ctx)
@ -151,7 +151,7 @@ func TestUploader_Upload(t *testing.T) {
t.Run("bytes", func(t *testing.T) {
fx := newFixture(t)
defer fx.tearDown()
fx.picker.EXPECT().PickBlock(mock.Anything, mock.Anything).Return(nil, nil)
fx.picker.EXPECT().GetObject(mock.Anything, mock.Anything).Return(nil, nil)
fx.fileService.EXPECT().FileAdd(gomock.Any(), gomock.Any(), gomock.Any()).Return(fx.newFile("123", &files.FileMeta{}), nil)
res := fx.Uploader.SetBytes([]byte("my bytes")).SetName("filename").Upload(ctx)
require.NoError(t, res.Err)
@ -161,7 +161,7 @@ func TestUploader_Upload(t *testing.T) {
}
func newFixture(t *testing.T) *uplFixture {
picker := mock_getblock.NewMockPicker(t)
picker := mock_getblock.NewMockObjectGetter(t)
fx := &uplFixture{
ctrl: gomock.NewController(t),
picker: picker,
@ -181,7 +181,7 @@ type uplFixture struct {
file *testMock.MockFile
fileService *testMock.MockFileService
ctrl *gomock.Controller
picker *mock_getblock.MockPicker
picker *mock_getblock.MockObjectGetter
}
func (fx *uplFixture) newImage(hash string) *testMock.MockImage {

View file

@ -23,7 +23,7 @@ import (
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
@ -48,7 +48,7 @@ func NewPage(
objectStore objectstore.ObjectStore,
anytype core.Service,
fileBlockService file.BlockService,
picker getblock.Picker,
picker getblock.ObjectGetter,
bookmarkService bookmark.BookmarkService,
systemObjectService system_object.Service,
tempDirProvider core.TempDirProvider,
@ -124,7 +124,7 @@ func (p *Page) CreationStateMigration(ctx *smartblock.InitContext) migration.Mig
if err != nil {
log.Errorf("failed to create unique key: %v", err)
} else {
otype, err := p.systemObjectService.GetObjectByUniqueKey(s.SpaceID(), uk)
otype, err := p.systemObjectService.GetObjectByUniqueKey(p.SpaceID(), uk)
if err != nil {
log.Errorf("failed to get object by unique key: %v", err)
} else {

View file

@ -46,7 +46,7 @@ func NewProfile(
systemObjectService system_object.Service,
fileBlockService file.BlockService,
anytype core.Service,
picker getblock.Picker,
picker getblock.ObjectGetter,
bookmarkService bookmark.BookmarkService,
tempDirProvider core.TempDirProvider,
layoutConverter converter.LayoutConverter,

View file

@ -126,7 +126,6 @@ type SmartBlock interface {
AddRelationLinks(ctx session.Context, relationIds ...string) (err error)
AddRelationLinksToState(s *state.State, relationIds ...string) (err error)
RemoveExtraRelations(ctx session.Context, relationKeys []string) (err error)
TemplateCreateFromObjectState() (*state.State, error)
SetVerticalAlign(ctx session.Context, align model.BlockVerticalAlign, ids ...string) error
SetIsDeleted()
IsDeleted() bool
@ -872,7 +871,7 @@ func (sb *smartBlock) AddRelationLinksToState(s *state.State, relationKeys ...st
if len(relationKeys) == 0 {
return
}
relations, err := sb.systemObjectService.FetchRelationByKeys(s.SpaceID(), relationKeys...)
relations, err := sb.systemObjectService.FetchRelationByKeys(sb.SpaceID(), relationKeys...)
if err != nil {
return
}
@ -989,23 +988,6 @@ func (sb *smartBlock) SetVerticalAlign(ctx session.Context, align model.BlockVer
return sb.Apply(s)
}
func (sb *smartBlock) TemplateCreateFromObjectState() (*state.State, error) {
st := sb.NewState().Copy()
st.SetLocalDetails(nil)
targetObjectTypeID, err := sb.systemObjectService.GetTypeIdByKey(context.Background(), st.SpaceID(), st.ObjectTypeKey())
if err != nil {
return nil, fmt.Errorf("get type id by key: %s", err)
}
st.SetDetail(bundle.RelationKeyTargetObjectType.String(), pbtypes.String(targetObjectTypeID))
st.SetObjectTypeKeys([]domain.TypeKey{bundle.TypeKeyTemplate, st.ObjectTypeKey()})
for _, rel := range sb.Relations(st) {
if rel.DataSource == model.Relation_details && !rel.Hidden {
st.RemoveDetail(rel.Key)
}
}
return st, nil
}
func (sb *smartBlock) RemoveExtraRelations(ctx session.Context, relationIds []string) (err error) {
st := sb.NewStateCtx(ctx)
st.RemoveRelation(relationIds...)

View file

@ -0,0 +1,89 @@
package editor
import (
"errors"
"time"
"github.com/gogo/protobuf/proto"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/spaceinfo"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var ErrIncorrectSpaceInfo = errors.New("space info is incorrect")
type spaceService interface {
OnViewCreated(spaceID string)
}
// SpaceView is a wrapper around smartblock.SmartBlock that indicates the current space state
type SpaceView struct {
smartblock.SmartBlock
spaceService spaceService
}
// newSpaceView creates a new SpaceView with given deps
func newSpaceView(sb smartblock.SmartBlock, spaceService spaceService) *SpaceView {
return &SpaceView{
SmartBlock: sb,
spaceService: spaceService,
}
}
// Init initializes SpaceView
func (s *SpaceView) Init(ctx *smartblock.InitContext) (err error) {
if err = s.SmartBlock.Init(ctx); err != nil {
return
}
spaceID, err := s.targetSpaceID()
if err != nil {
return
}
s.DisableLayouts()
s.spaceService.OnViewCreated(spaceID)
return s.setSpaceInfo(ctx.State, spaceinfo.SpaceInfo{})
}
func (s *SpaceView) TryClose(objectTTL time.Duration) (res bool, err error) {
return false, nil
}
func (s *SpaceView) SetSpaceInfo(info spaceinfo.SpaceInfo) (err error) {
st := s.NewState()
if err = s.setSpaceInfo(st, info); err != nil {
return
}
return s.Apply(st)
}
func (s *SpaceView) setSpaceInfo(st *state.State, info spaceinfo.SpaceInfo) (err error) {
st.SetLocalDetail(bundle.RelationKeySpaceLocalStatus.String(), pbtypes.Int64(int64(info.LocalStatus)))
st.SetLocalDetail(bundle.RelationKeySpaceRemoteStatus.String(), pbtypes.Int64(int64(info.RemoteStatus)))
return
}
// targetSpaceID returns space id from the root of space object's tree
func (s *SpaceView) targetSpaceID() (id string, err error) {
changeInfo := s.Tree().ChangeInfo()
if changeInfo == nil {
return "", ErrIncorrectSpaceInfo
}
var (
changePayload = &model.ObjectChangePayload{}
spaceHeader = &model.SpaceObjectHeader{}
)
err = proto.Unmarshal(changeInfo.ChangePayload, changePayload)
if err != nil {
return "", ErrIncorrectSpaceInfo
}
err = proto.Unmarshal(changePayload.Data, spaceHeader)
if err != nil {
return "", ErrIncorrectSpaceInfo
}
return spaceHeader.SpaceID, nil
}

View file

@ -10,6 +10,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
smartblock2 "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
@ -17,7 +18,7 @@ import (
)
type objectDeriver interface {
DeriveTreeObjectWithUniqueKey(ctx context.Context, spaceID string, key domain.UniqueKey, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error)
DeriveTreeObject(ctx context.Context, spaceID string, params objectcache.TreeDerivationParams) (sb smartblock.SmartBlock, err error)
}
// Migrate legacy sub-objects to ordinary objects
@ -51,15 +52,18 @@ func (m *subObjectsMigration) migrateSubObject(
if err != nil {
return "", fmt.Errorf("unmarshal unique key: %w", err)
}
sb, err := m.objectDeriver.DeriveTreeObjectWithUniqueKey(ctx, m.workspace.SpaceID(), uniqueKey, func(id string) *smartblock.InitContext {
st := state.NewDocWithUniqueKey(id, nil, uniqueKey).NewState()
st.SetDetails(details)
st.SetObjectTypeKey(typeKey)
return &smartblock.InitContext{
IsNewObject: true,
State: st,
SpaceID: m.workspace.SpaceID(),
}
sb, err := m.objectDeriver.DeriveTreeObject(ctx, m.workspace.SpaceID(), objectcache.TreeDerivationParams{
Key: uniqueKey,
InitFunc: func(id string) *smartblock.InitContext {
st := state.NewDocWithUniqueKey(id, nil, uniqueKey).NewState()
st.SetDetails(details)
st.SetObjectTypeKey(typeKey)
return &smartblock.InitContext{
IsNewObject: true,
State: st,
SpaceID: m.workspace.SpaceID(),
}
},
})
if err != nil {
return "", err

View file

@ -19,14 +19,14 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/core"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
type Template struct {
*Page
picker getblock.Picker
picker getblock.ObjectGetter
}
func NewTemplate(
@ -34,7 +34,7 @@ func NewTemplate(
objectStore objectstore.ObjectStore,
anytype core.Service,
fileBlockService file.BlockService,
picker getblock.Picker,
picker getblock.ObjectGetter,
bookmarkService bookmark.BookmarkService,
systemObjectService system_object.Service,
tempDirProvider core.TempDirProvider,

View file

@ -32,7 +32,6 @@ func NewTemplateTest(t *testing.T, ctrl *gomock.Controller, templateName string)
objectStore := testMock.NewMockObjectStore(ctrl)
systemObjectService := mock_system_object.NewMockService(t)
systemObjectService.EXPECT().GetObjectTypes(mock.Anything).Return(nil, nil).Maybe()
templ := &Template{
Page: &Page{
SmartBlock: sb,

View file

@ -19,7 +19,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

View file

@ -19,6 +19,7 @@ import (
"github.com/anyproto/anytype-heart/core/block"
sb "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/getblock"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/converter"
"github.com/anyproto/anytype-heart/core/converter/dot"
@ -38,8 +39,8 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/constant"
oserror "github.com/anyproto/anytype-heart/util/os"
"github.com/anyproto/anytype-heart/util/pbtypes"
@ -59,13 +60,14 @@ type Export interface {
type export struct {
blockService *block.Service
picker getblock.Picker
picker getblock.ObjectGetter
objectStore objectstore.ObjectStore
coreService core.Service
sbtProvider typeprovider.SmartBlockTypeProvider
fileService files.Service
systemObjectService system_object.Service
spaceService space.Service
spaceService spacecore.SpaceCoreService
resolver idresolver.Resolver
}
func New() Export {
@ -77,10 +79,11 @@ func (e *export) Init(a *app.App) (err error) {
e.coreService = a.MustComponent(core.CName).(core.Service)
e.objectStore = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
e.fileService = app.MustComponent[files.Service](a)
e.picker = app.MustComponent[getblock.Picker](a)
e.picker = app.MustComponent[getblock.ObjectGetter](a)
e.resolver = a.MustComponent(idresolver.CName).(idresolver.Resolver)
e.sbtProvider = app.MustComponent[typeprovider.SmartBlockTypeProvider](a)
e.systemObjectService = app.MustComponent[system_object.Service](a)
e.spaceService = app.MustComponent[space.Service](a)
e.spaceService = app.MustComponent[spacecore.SpaceCoreService](a)
return
}
@ -375,7 +378,7 @@ func (e *export) saveFiles(ctx context.Context, b sb.SmartBlock, queue process.Q
}
func (e *export) saveFile(ctx context.Context, wr writer, hash string) (err error) {
spaceID, err := e.spaceService.ResolveSpaceID(hash)
spaceID, err := e.resolver.ResolveSpaceID(hash)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}

View file

@ -81,7 +81,7 @@ func (s *Service) DownloadFile(ctx context.Context, req *pb.RpcFileDownloadReque
}
func (s *Service) getFileOrLargestImage(ctx context.Context, hash string) (files.File, error) {
spaceID, err := s.spaceService.ResolveSpaceID(hash)
spaceID, err := s.resolver.ResolveSpaceID(hash)
if err != nil {
return nil, fmt.Errorf("resolve spaceID: %w", err)
}

View file

@ -7,13 +7,13 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
)
type Picker interface {
PickBlock(ctx context.Context, id string) (sb smartblock.SmartBlock, err error)
type ObjectGetter interface {
GetObject(ctx context.Context, id string) (sb smartblock.SmartBlock, err error)
}
func Do[t any](p Picker, objectID string, apply func(sb t) error) error {
func Do[t any](p ObjectGetter, objectID string, apply func(sb t) error) error {
ctx := context.Background()
sb, err := p.PickBlock(ctx, objectID)
sb, err := p.GetObject(ctx, objectID)
if err != nil {
return err
}

View file

@ -0,0 +1,94 @@
// Code generated by mockery v2.26.1. DO NOT EDIT.
package mock_getblock
import (
context "context"
mock "github.com/stretchr/testify/mock"
smartblock "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
)
// MockObjectGetter is an autogenerated mock type for the ObjectGetter type
type MockObjectGetter struct {
mock.Mock
}
type MockObjectGetter_Expecter struct {
mock *mock.Mock
}
func (_m *MockObjectGetter) EXPECT() *MockObjectGetter_Expecter {
return &MockObjectGetter_Expecter{mock: &_m.Mock}
}
// GetObject provides a mock function with given fields: ctx, id
func (_m *MockObjectGetter) GetObject(ctx context.Context, id string) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, id)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (smartblock.SmartBlock, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) smartblock.SmartBlock); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockObjectGetter_GetObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetObject'
type MockObjectGetter_GetObject_Call struct {
*mock.Call
}
// GetObject is a helper method to define mock.On call
// - ctx context.Context
// - id string
func (_e *MockObjectGetter_Expecter) GetObject(ctx interface{}, id interface{}) *MockObjectGetter_GetObject_Call {
return &MockObjectGetter_GetObject_Call{Call: _e.mock.On("GetObject", ctx, id)}
}
func (_c *MockObjectGetter_GetObject_Call) Run(run func(ctx context.Context, id string)) *MockObjectGetter_GetObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockObjectGetter_GetObject_Call) Return(sb smartblock.SmartBlock, err error) *MockObjectGetter_GetObject_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockObjectGetter_GetObject_Call) RunAndReturn(run func(context.Context, string) (smartblock.SmartBlock, error)) *MockObjectGetter_GetObject_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewMockObjectGetter interface {
mock.TestingT
Cleanup(func())
}
// NewMockObjectGetter creates a new instance of MockObjectGetter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockObjectGetter(t mockConstructorTestingTNewMockObjectGetter) *MockObjectGetter {
mock := &MockObjectGetter{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -1,94 +0,0 @@
// Code generated by mockery v2.26.1. DO NOT EDIT.
package mock_getblock
import (
context "context"
mock "github.com/stretchr/testify/mock"
smartblock "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
)
// MockPicker is an autogenerated mock type for the Picker type
type MockPicker struct {
mock.Mock
}
type MockPicker_Expecter struct {
mock *mock.Mock
}
func (_m *MockPicker) EXPECT() *MockPicker_Expecter {
return &MockPicker_Expecter{mock: &_m.Mock}
}
// PickBlock provides a mock function with given fields: ctx, id
func (_m *MockPicker) PickBlock(ctx context.Context, id string) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, id)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (smartblock.SmartBlock, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) smartblock.SmartBlock); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockPicker_PickBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PickBlock'
type MockPicker_PickBlock_Call struct {
*mock.Call
}
// PickBlock is a helper method to define mock.On call
// - ctx context.Context
// - id string
func (_e *MockPicker_Expecter) PickBlock(ctx interface{}, id interface{}) *MockPicker_PickBlock_Call {
return &MockPicker_PickBlock_Call{Call: _e.mock.On("PickBlock", ctx, id)}
}
func (_c *MockPicker_PickBlock_Call) Run(run func(ctx context.Context, id string)) *MockPicker_PickBlock_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockPicker_PickBlock_Call) Return(sb smartblock.SmartBlock, err error) *MockPicker_PickBlock_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockPicker_PickBlock_Call) RunAndReturn(run func(context.Context, string) (smartblock.SmartBlock, error)) *MockPicker_PickBlock_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewMockPicker interface {
mock.TestingT
Cleanup(func())
}
// NewMockPicker creates a new instance of MockPicker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockPicker(t mockConstructorTestingTNewMockPicker) *MockPicker {
mock := &MockPicker{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -16,7 +16,6 @@ import (
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/collection"
"github.com/anyproto/anytype-heart/core/block/getblock"
"github.com/anyproto/anytype-heart/core/block/import/converter"
"github.com/anyproto/anytype-heart/core/block/import/csv"
"github.com/anyproto/anytype-heart/core/block/import/html"
@ -27,6 +26,8 @@ import (
"github.com/anyproto/anytype-heart/core/block/import/txt"
"github.com/anyproto/anytype-heart/core/block/import/web"
"github.com/anyproto/anytype-heart/core/block/import/workerpool"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/filestorage/filesync"
"github.com/anyproto/anytype-heart/pb"
@ -37,7 +38,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
@ -81,14 +82,14 @@ func (i *Import) Init(a *app.App) (err error) {
for _, c := range converters {
i.converters[c.Name()] = c
}
picker := app.MustComponent[getblock.Picker](a)
factory := syncer.New(syncer.NewFileSyncer(i.s), syncer.NewBookmarkSyncer(i.s), syncer.NewIconSyncer(i.s, picker))
objectCache := app.MustComponent[objectcache.Cache](a)
resolver := a.MustComponent(idresolver.CName).(idresolver.Resolver)
factory := syncer.New(syncer.NewFileSyncer(i.s), syncer.NewBookmarkSyncer(i.s), syncer.NewIconSyncer(i.s, resolver))
store := app.MustComponent[objectstore.ObjectStore](a)
i.objectIDGetter = NewObjectIDGetter(store, coreService, i.s)
i.objectIDGetter = NewObjectIDGetter(store, coreService, objectCache)
fileStore := app.MustComponent[filestore.FileStore](a)
relationSyncer := syncer.NewFileRelationSyncer(i.s, fileStore)
i.oc = NewCreator(i.s, coreService, factory, store, relationSyncer, fileStore, picker)
i.oc = NewCreator(i.s, objectCache, coreService, factory, store, relationSyncer, fileStore)
i.sbtProvider = app.MustComponent[typeprovider.SmartBlockTypeProvider](a)
i.fileSync = a.MustComponent(filesync.CName).(filesync.FileSync)
return nil

View file

@ -14,10 +14,9 @@ import (
time "time"
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
converter "github.com/anyproto/anytype-heart/core/block/import/converter"
types "github.com/gogo/protobuf/types"
gomock "go.uber.org/mock/gomock"
converter "github.com/anyproto/anytype-heart/core/block/import/converter"
)
// MockCreator is a mock of Creator interface.

View file

@ -3,6 +3,7 @@ package importer
import (
"context"
"errors"
"fmt"
"path"
"sync"
@ -13,13 +14,14 @@ import (
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
sb "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/getblock"
"github.com/anyproto/anytype-heart/core/block/history"
"github.com/anyproto/anytype-heart/core/block/import/converter"
"github.com/anyproto/anytype-heart/core/block/import/syncer"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pb"
@ -37,7 +39,7 @@ const relationsLimit = 10
type ObjectCreator struct {
service *block.Service
picker getblock.Picker
objectCache objectcache.Cache
core core.Service
objectStore objectstore.ObjectStore
relationSyncer syncer.RelationSyncer
@ -47,12 +49,12 @@ type ObjectCreator struct {
}
func NewCreator(service *block.Service,
cache objectcache.Cache,
core core.Service,
syncFactory *syncer.Factory,
objectStore objectstore.ObjectStore,
relationSyncer syncer.RelationSyncer,
fileStore filestore.FileStore,
picker getblock.Picker,
) Creator {
return &ObjectCreator{
service: service,
@ -61,7 +63,7 @@ func NewCreator(service *block.Service,
objectStore: objectStore,
relationSyncer: relationSyncer,
fileStore: fileStore,
picker: picker,
objectCache: cache,
}
}
@ -196,23 +198,31 @@ func (oc *ObjectCreator) createNewObject(
st *state.State,
newID string,
oldIDtoNew map[string]string) (*types.Struct, error) {
sb, err := oc.service.CreateTreeObjectWithPayload(ctx, spaceID, payload, func(id string) *sb.InitContext {
return &sb.InitContext{
var respDetails *types.Struct
sb, err := oc.objectCache.CreateTreeObjectWithPayload(ctx, spaceID, payload, func(id string) *smartblock.InitContext {
return &smartblock.InitContext{
Ctx: ctx,
IsNewObject: true,
State: st,
SpaceID: spaceID,
}
})
if errors.Is(err, treestorage.ErrTreeExists) {
sb, err = oc.picker.PickBlock(ctx, newID)
}
if err != nil {
if err == nil {
respDetails = sb.Details()
} else if errors.Is(err, treestorage.ErrTreeExists) {
err = getblock.Do(oc.service, newID, func(sb smartblock.SmartBlock) error {
respDetails = sb.Details()
return nil
})
if err != nil {
return nil, fmt.Errorf("get existing object %s: %w", newID, err)
}
} else {
log.With("objectID", newID).Errorf("failed to create %s: %s", newID, err.Error())
return nil, err
}
log.With("objectID", newID).Infof("import object created %s", pbtypes.GetString(st.CombinedDetails(), bundle.RelationKeyName.String()))
respDetails := sb.Details()
// update collection after we create it
if st.Store() != nil {
oc.updateLinksInCollections(st, oldIDtoNew, true)
@ -337,7 +347,7 @@ func (oc *ObjectCreator) handleCoverRelation(spaceID string, st *state.State) []
func (oc *ObjectCreator) resetState(newID string, st *state.State) *types.Struct {
var respDetails *types.Struct
err := getblock.Do(oc.picker, newID, func(b sb.SmartBlock) error {
err := block.Do(oc.service, newID, func(b smartblock.SmartBlock) error {
err := history.ResetToVersion(b, st)
if err != nil {
log.With(zap.String("object id", newID)).Errorf("failed to set state %s: %s", newID, err.Error())
@ -383,7 +393,7 @@ func (oc *ObjectCreator) setArchived(snapshot *model.SmartBlockSnapshotBase, new
func (oc *ObjectCreator) syncFilesAndLinks(newID string) error {
tasks := make([]func() error, 0)
// todo: rewrite it in order not to create state with URLs inside links
err := getblock.Do(oc.picker, newID, func(b sb.SmartBlock) error {
err := block.Do(oc.service, newID, func(b smartblock.SmartBlock) error {
st := b.NewState()
return st.Iterate(func(bl simple.Block) (isContinue bool) {
s := oc.syncFactory.GetSyncer(bl)
@ -412,7 +422,7 @@ func (oc *ObjectCreator) syncFilesAndLinks(newID string) error {
}
func (oc *ObjectCreator) updateLinksInCollections(st *state.State, oldIDtoNew map[string]string, isNewCollection bool) {
err := block.Do(oc.service, st.RootId(), func(b sb.SmartBlock) error {
err := block.Do(oc.service, st.RootId(), func(b smartblock.SmartBlock) error {
originalState := b.NewState()
var existedObjects []string
if !isNewCollection {

View file

@ -9,8 +9,8 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/import/converter"
"github.com/anyproto/anytype-heart/core/block/object/payloadcreator"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core"
@ -41,10 +41,10 @@ type ObjectIDGetter struct {
objectStore objectstore.ObjectStore
core core.Service
createPayload map[string]treestorage.TreeStorageCreatePayload
service *block.Service
service payloadcreator.PayloadCreator
}
func NewObjectIDGetter(objectStore objectstore.ObjectStore, core core.Service, service *block.Service) IDGetter {
func NewObjectIDGetter(objectStore objectstore.ObjectStore, core core.Service, service payloadcreator.PayloadCreator) IDGetter {
return &ObjectIDGetter{
objectStore: objectStore,
service: service,
@ -90,12 +90,17 @@ func (ou *ObjectIDGetter) Get(
if err != nil {
return "", treestorage.TreeStorageCreatePayload{}, err
}
payload, err = ou.service.DeriveTreeCreatePayload(context.Background(), spaceID, uk)
payload, err = ou.service.DeriveTreePayload(context.Background(), spaceID, payloadcreator.PayloadDerivationParams{
Key: uk,
})
if err != nil {
return "", treestorage.TreeStorageCreatePayload{}, fmt.Errorf("derive tree create payload: %w", err)
}
} else {
payload, err = ou.service.CreateTreePayload(context.Background(), spaceID, sbType, createdTime)
payload, err = ou.service.CreateTreePayload(context.Background(), spaceID, payloadcreator.PayloadCreationParams{
Time: createdTime,
SmartblockType: sbType,
})
if err != nil {
return "", treestorage.TreeStorageCreatePayload{}, fmt.Errorf("create tree payload: %w", err)
}

View file

@ -29,7 +29,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/constant"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"

View file

@ -10,7 +10,7 @@ import (
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/editor/basic"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/getblock"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/block/simple"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
@ -20,12 +20,12 @@ import (
var log = logging.Logger("import")
type IconSyncer struct {
service *block.Service
picker getblock.Picker
service *block.Service
resolver idresolver.Resolver
}
func NewIconSyncer(service *block.Service, picker getblock.Picker) *IconSyncer {
return &IconSyncer{service: service, picker: picker}
func NewIconSyncer(service *block.Service, resolver idresolver.Resolver) *IconSyncer {
return &IconSyncer{service: service, resolver: resolver}
}
func (is *IconSyncer) Sync(id string, b simple.Block) error {
@ -38,7 +38,7 @@ func (is *IconSyncer) Sync(id string, b simple.Block) error {
if strings.HasPrefix(icon, "http://") || strings.HasPrefix(icon, "https://") {
req = pb.RpcFileUploadRequest{Url: icon}
}
spaceID, err := is.service.ResolveSpaceID(id)
spaceID, err := is.resolver.ResolveSpaceID(id)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -47,7 +47,7 @@ func (is *IconSyncer) Sync(id string, b simple.Block) error {
log.Errorf("failed uploading icon image file: %s", oserror.TransformError(err))
}
err = getblock.Do(is.picker, id, func(sb smartblock.SmartBlock) error {
err = block.Do(is.service, id, func(sb smartblock.SmartBlock) error {
updater := sb.(basic.Updatable)
upErr := updater.Update(nil, func(simpleBlock simple.Block) error {
simpleBlock.Model().GetText().IconImage = hash

View file

@ -0,0 +1,44 @@
package idresolver
import (
"sync"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
)
const CName = "block.object.resolver"
type Resolver interface {
app.Component
ResolveSpaceID(objectID string) (string, error)
}
func New() Resolver {
return &resolver{}
}
type resolver struct {
storage storage.ClientStorage
sync.Mutex
}
func (r *resolver) Init(a *app.App) (err error) {
r.storage = a.MustComponent(spacestorage.CName).(storage.ClientStorage)
return
}
func (r *resolver) Name() (name string) {
return CName
}
func (r *resolver) ResolveSpaceID(objectID string) (string, error) {
// TODO: [MR] remove it, because maybe we don't need it
if addr.IsBundledId(objectID) {
return addr.AnytypeMarketplaceWorkspace, nil
}
return r.storage.GetSpaceID(objectID)
}

View file

@ -5,16 +5,18 @@ import (
"errors"
"time"
"github.com/anyproto/any-sync/accountservice"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/ocache"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/anytype-heart/core/block/editor"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/object/payloadcreator"
"github.com/anyproto/anytype-heart/core/block/source"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
)
var log = logging.Logger("anytype-mw-object-cache")
@ -38,10 +40,21 @@ type cacheOpts struct {
putObject smartblock.SmartBlock
}
const CName = "client.object.objectcache"
type InitFunc = func(id string) *smartblock.InitContext
type objectFactory interface {
InitObject(id string, initCtx *smartblock.InitContext) (sb smartblock.SmartBlock, err error)
}
type Cache interface {
app.ComponentRunnable
payloadcreator.PayloadCreator
PickBlock(ctx context.Context, objectID string) (sb smartblock.SmartBlock, err error)
CreateTreeObject(ctx context.Context, spaceID string, params TreeCreationParams) (sb smartblock.SmartBlock, err error)
CreateTreeObjectWithPayload(ctx context.Context, spaceID string, payload treestorage.TreeStorageCreatePayload, initFunc InitFunc) (sb smartblock.SmartBlock, err error)
DeriveTreeObject(ctx context.Context, spaceID string, params TreeDerivationParams) (sb smartblock.SmartBlock, err error)
GetObject(ctx context.Context, id domain.FullID) (sb smartblock.SmartBlock, err error)
GetObjectWithTimeout(ctx context.Context, id domain.FullID) (sb smartblock.SmartBlock, err error)
DoLockedIfNotExists(objectID string, proc func() error) error
@ -49,12 +62,18 @@ type Cache interface {
CloseBlocks()
}
type personalIDProvider interface {
PersonalSpaceID() string
}
type objectCache struct {
objectFactory *editor.ObjectFactory
sbtProvider typeprovider.SmartBlockTypeProvider
spaceService space.Service
cache ocache.OCache
closing chan struct{}
objectFactory objectFactory
sbtProvider typeprovider.SmartBlockTypeProvider
spaceService spacecore.SpaceCoreService
provider personalIDProvider
accountService accountservice.Service
cache ocache.OCache
closing chan struct{}
}
func New() Cache {
@ -64,9 +83,11 @@ func New() Cache {
}
func (c *objectCache) Init(a *app.App) error {
c.objectFactory = app.MustComponent[*editor.ObjectFactory](a)
c.accountService = app.MustComponent[accountservice.Service](a)
c.objectFactory = app.MustComponent[objectFactory](a)
c.provider = app.MustComponent[personalIDProvider](a)
c.sbtProvider = app.MustComponent[typeprovider.SmartBlockTypeProvider](a)
c.spaceService = app.MustComponent[space.Service](a)
c.spaceService = app.MustComponent[spacecore.SpaceCoreService](a)
c.cache = ocache.New(
c.cacheLoad,
// ocache.WithLogger(log.Desugar()),
@ -78,7 +99,7 @@ func (c *objectCache) Init(a *app.App) error {
}
func (c *objectCache) Name() string {
return "object-cache"
return CName
}
func (c *objectCache) Run(_ context.Context) error {
@ -110,7 +131,6 @@ func ContextWithBuildOptions(ctx context.Context, buildOpts source.BuildOptions)
func (c *objectCache) cacheLoad(ctx context.Context, id string) (value ocache.Object, err error) {
// TODO Pass options as parameter?
opts := ctx.Value(optsKey).(cacheOpts)
buildObject := func(id string) (sb smartblock.SmartBlock, err error) {
return c.objectFactory.InitObject(id, &smartblock.InitContext{Ctx: ctx, BuildOpts: opts.buildOption, SpaceID: opts.spaceId})
}
@ -189,19 +209,6 @@ func (c *objectCache) GetObjectWithTimeout(ctx context.Context, id domain.FullID
return c.GetObject(ctx, id)
}
// PickBlock returns opened smartBlock or opens smartBlock in silent mode
func (c *objectCache) PickBlock(ctx context.Context, objectID string) (sb smartblock.SmartBlock, err error) {
spaceID, err := c.spaceService.ResolveSpaceID(objectID)
if err != nil {
// Object not loaded yet
return nil, source.ErrObjectNotFound
}
return c.GetObjectWithTimeout(ctx, domain.FullID{
SpaceID: spaceID,
ObjectID: objectID,
})
}
func (c *objectCache) DoLockedIfNotExists(objectID string, proc func() error) error {
return c.cache.DoLockedIfNotExists(objectID, proc)
}

View file

@ -0,0 +1,770 @@
// Code generated by mockery v2.26.1. DO NOT EDIT.
package mock_objectcache
import (
context "context"
app "github.com/anyproto/any-sync/app"
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
mock "github.com/stretchr/testify/mock"
smartblock "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
objectcache "github.com/anyproto/anytype-heart/core/block/object/objectcache"
payloadcreator "github.com/anyproto/anytype-heart/core/block/object/payloadcreator"
domain "github.com/anyproto/anytype-heart/core/domain"
)
// MockCache is an autogenerated mock type for the Cache type
type MockCache struct {
mock.Mock
}
type MockCache_Expecter struct {
mock *mock.Mock
}
func (_m *MockCache) EXPECT() *MockCache_Expecter {
return &MockCache_Expecter{mock: &_m.Mock}
}
// Close provides a mock function with given fields: ctx
func (_m *MockCache) Close(ctx context.Context) error {
ret := _m.Called(ctx)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockCache_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
type MockCache_Close_Call struct {
*mock.Call
}
// Close is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockCache_Expecter) Close(ctx interface{}) *MockCache_Close_Call {
return &MockCache_Close_Call{Call: _e.mock.On("Close", ctx)}
}
func (_c *MockCache_Close_Call) Run(run func(ctx context.Context)) *MockCache_Close_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockCache_Close_Call) Return(err error) *MockCache_Close_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockCache_Close_Call) RunAndReturn(run func(context.Context) error) *MockCache_Close_Call {
_c.Call.Return(run)
return _c
}
// CloseBlocks provides a mock function with given fields:
func (_m *MockCache) CloseBlocks() {
_m.Called()
}
// MockCache_CloseBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseBlocks'
type MockCache_CloseBlocks_Call struct {
*mock.Call
}
// CloseBlocks is a helper method to define mock.On call
func (_e *MockCache_Expecter) CloseBlocks() *MockCache_CloseBlocks_Call {
return &MockCache_CloseBlocks_Call{Call: _e.mock.On("CloseBlocks")}
}
func (_c *MockCache_CloseBlocks_Call) Run(run func()) *MockCache_CloseBlocks_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockCache_CloseBlocks_Call) Return() *MockCache_CloseBlocks_Call {
_c.Call.Return()
return _c
}
func (_c *MockCache_CloseBlocks_Call) RunAndReturn(run func()) *MockCache_CloseBlocks_Call {
_c.Call.Return(run)
return _c
}
// CreateTreeObject provides a mock function with given fields: ctx, spaceID, params
func (_m *MockCache) CreateTreeObject(ctx context.Context, spaceID string, params objectcache.TreeCreationParams) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, spaceID, params)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, objectcache.TreeCreationParams) (smartblock.SmartBlock, error)); ok {
return rf(ctx, spaceID, params)
}
if rf, ok := ret.Get(0).(func(context.Context, string, objectcache.TreeCreationParams) smartblock.SmartBlock); ok {
r0 = rf(ctx, spaceID, params)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, objectcache.TreeCreationParams) error); ok {
r1 = rf(ctx, spaceID, params)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_CreateTreeObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTreeObject'
type MockCache_CreateTreeObject_Call struct {
*mock.Call
}
// CreateTreeObject is a helper method to define mock.On call
// - ctx context.Context
// - spaceID string
// - params objectcache.TreeCreationParams
func (_e *MockCache_Expecter) CreateTreeObject(ctx interface{}, spaceID interface{}, params interface{}) *MockCache_CreateTreeObject_Call {
return &MockCache_CreateTreeObject_Call{Call: _e.mock.On("CreateTreeObject", ctx, spaceID, params)}
}
func (_c *MockCache_CreateTreeObject_Call) Run(run func(ctx context.Context, spaceID string, params objectcache.TreeCreationParams)) *MockCache_CreateTreeObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(objectcache.TreeCreationParams))
})
return _c
}
func (_c *MockCache_CreateTreeObject_Call) Return(sb smartblock.SmartBlock, err error) *MockCache_CreateTreeObject_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockCache_CreateTreeObject_Call) RunAndReturn(run func(context.Context, string, objectcache.TreeCreationParams) (smartblock.SmartBlock, error)) *MockCache_CreateTreeObject_Call {
_c.Call.Return(run)
return _c
}
// CreateTreeObjectWithPayload provides a mock function with given fields: ctx, spaceID, payload, initFunc
func (_m *MockCache) CreateTreeObjectWithPayload(ctx context.Context, spaceID string, payload treestorage.TreeStorageCreatePayload, initFunc func(string) *smartblock.InitContext) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, spaceID, payload, initFunc)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, treestorage.TreeStorageCreatePayload, func(string) *smartblock.InitContext) (smartblock.SmartBlock, error)); ok {
return rf(ctx, spaceID, payload, initFunc)
}
if rf, ok := ret.Get(0).(func(context.Context, string, treestorage.TreeStorageCreatePayload, func(string) *smartblock.InitContext) smartblock.SmartBlock); ok {
r0 = rf(ctx, spaceID, payload, initFunc)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, treestorage.TreeStorageCreatePayload, func(string) *smartblock.InitContext) error); ok {
r1 = rf(ctx, spaceID, payload, initFunc)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_CreateTreeObjectWithPayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTreeObjectWithPayload'
type MockCache_CreateTreeObjectWithPayload_Call struct {
*mock.Call
}
// CreateTreeObjectWithPayload is a helper method to define mock.On call
// - ctx context.Context
// - spaceID string
// - payload treestorage.TreeStorageCreatePayload
// - initFunc func(string) *smartblock.InitContext
func (_e *MockCache_Expecter) CreateTreeObjectWithPayload(ctx interface{}, spaceID interface{}, payload interface{}, initFunc interface{}) *MockCache_CreateTreeObjectWithPayload_Call {
return &MockCache_CreateTreeObjectWithPayload_Call{Call: _e.mock.On("CreateTreeObjectWithPayload", ctx, spaceID, payload, initFunc)}
}
func (_c *MockCache_CreateTreeObjectWithPayload_Call) Run(run func(ctx context.Context, spaceID string, payload treestorage.TreeStorageCreatePayload, initFunc func(string) *smartblock.InitContext)) *MockCache_CreateTreeObjectWithPayload_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(treestorage.TreeStorageCreatePayload), args[3].(func(string) *smartblock.InitContext))
})
return _c
}
func (_c *MockCache_CreateTreeObjectWithPayload_Call) Return(sb smartblock.SmartBlock, err error) *MockCache_CreateTreeObjectWithPayload_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockCache_CreateTreeObjectWithPayload_Call) RunAndReturn(run func(context.Context, string, treestorage.TreeStorageCreatePayload, func(string) *smartblock.InitContext) (smartblock.SmartBlock, error)) *MockCache_CreateTreeObjectWithPayload_Call {
_c.Call.Return(run)
return _c
}
// CreateTreePayload provides a mock function with given fields: ctx, spaceID, params
func (_m *MockCache) CreateTreePayload(ctx context.Context, spaceID string, params payloadcreator.PayloadCreationParams) (treestorage.TreeStorageCreatePayload, error) {
ret := _m.Called(ctx, spaceID, params)
var r0 treestorage.TreeStorageCreatePayload
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, payloadcreator.PayloadCreationParams) (treestorage.TreeStorageCreatePayload, error)); ok {
return rf(ctx, spaceID, params)
}
if rf, ok := ret.Get(0).(func(context.Context, string, payloadcreator.PayloadCreationParams) treestorage.TreeStorageCreatePayload); ok {
r0 = rf(ctx, spaceID, params)
} else {
r0 = ret.Get(0).(treestorage.TreeStorageCreatePayload)
}
if rf, ok := ret.Get(1).(func(context.Context, string, payloadcreator.PayloadCreationParams) error); ok {
r1 = rf(ctx, spaceID, params)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_CreateTreePayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTreePayload'
type MockCache_CreateTreePayload_Call struct {
*mock.Call
}
// CreateTreePayload is a helper method to define mock.On call
// - ctx context.Context
// - spaceID string
// - params payloadcreator.PayloadCreationParams
func (_e *MockCache_Expecter) CreateTreePayload(ctx interface{}, spaceID interface{}, params interface{}) *MockCache_CreateTreePayload_Call {
return &MockCache_CreateTreePayload_Call{Call: _e.mock.On("CreateTreePayload", ctx, spaceID, params)}
}
func (_c *MockCache_CreateTreePayload_Call) Run(run func(ctx context.Context, spaceID string, params payloadcreator.PayloadCreationParams)) *MockCache_CreateTreePayload_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(payloadcreator.PayloadCreationParams))
})
return _c
}
func (_c *MockCache_CreateTreePayload_Call) Return(_a0 treestorage.TreeStorageCreatePayload, _a1 error) *MockCache_CreateTreePayload_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockCache_CreateTreePayload_Call) RunAndReturn(run func(context.Context, string, payloadcreator.PayloadCreationParams) (treestorage.TreeStorageCreatePayload, error)) *MockCache_CreateTreePayload_Call {
_c.Call.Return(run)
return _c
}
// DeriveObjectID provides a mock function with given fields: ctx, spaceID, uniqueKey
func (_m *MockCache) DeriveObjectID(ctx context.Context, spaceID string, uniqueKey domain.UniqueKey) (string, error) {
ret := _m.Called(ctx, spaceID, uniqueKey)
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, domain.UniqueKey) (string, error)); ok {
return rf(ctx, spaceID, uniqueKey)
}
if rf, ok := ret.Get(0).(func(context.Context, string, domain.UniqueKey) string); ok {
r0 = rf(ctx, spaceID, uniqueKey)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, string, domain.UniqueKey) error); ok {
r1 = rf(ctx, spaceID, uniqueKey)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_DeriveObjectID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeriveObjectID'
type MockCache_DeriveObjectID_Call struct {
*mock.Call
}
// DeriveObjectID is a helper method to define mock.On call
// - ctx context.Context
// - spaceID string
// - uniqueKey domain.UniqueKey
func (_e *MockCache_Expecter) DeriveObjectID(ctx interface{}, spaceID interface{}, uniqueKey interface{}) *MockCache_DeriveObjectID_Call {
return &MockCache_DeriveObjectID_Call{Call: _e.mock.On("DeriveObjectID", ctx, spaceID, uniqueKey)}
}
func (_c *MockCache_DeriveObjectID_Call) Run(run func(ctx context.Context, spaceID string, uniqueKey domain.UniqueKey)) *MockCache_DeriveObjectID_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(domain.UniqueKey))
})
return _c
}
func (_c *MockCache_DeriveObjectID_Call) Return(id string, err error) *MockCache_DeriveObjectID_Call {
_c.Call.Return(id, err)
return _c
}
func (_c *MockCache_DeriveObjectID_Call) RunAndReturn(run func(context.Context, string, domain.UniqueKey) (string, error)) *MockCache_DeriveObjectID_Call {
_c.Call.Return(run)
return _c
}
// DeriveTreeObject provides a mock function with given fields: ctx, spaceID, params
func (_m *MockCache) DeriveTreeObject(ctx context.Context, spaceID string, params objectcache.TreeDerivationParams) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, spaceID, params)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, objectcache.TreeDerivationParams) (smartblock.SmartBlock, error)); ok {
return rf(ctx, spaceID, params)
}
if rf, ok := ret.Get(0).(func(context.Context, string, objectcache.TreeDerivationParams) smartblock.SmartBlock); ok {
r0 = rf(ctx, spaceID, params)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, objectcache.TreeDerivationParams) error); ok {
r1 = rf(ctx, spaceID, params)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_DeriveTreeObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeriveTreeObject'
type MockCache_DeriveTreeObject_Call struct {
*mock.Call
}
// DeriveTreeObject is a helper method to define mock.On call
// - ctx context.Context
// - spaceID string
// - params objectcache.TreeDerivationParams
func (_e *MockCache_Expecter) DeriveTreeObject(ctx interface{}, spaceID interface{}, params interface{}) *MockCache_DeriveTreeObject_Call {
return &MockCache_DeriveTreeObject_Call{Call: _e.mock.On("DeriveTreeObject", ctx, spaceID, params)}
}
func (_c *MockCache_DeriveTreeObject_Call) Run(run func(ctx context.Context, spaceID string, params objectcache.TreeDerivationParams)) *MockCache_DeriveTreeObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(objectcache.TreeDerivationParams))
})
return _c
}
func (_c *MockCache_DeriveTreeObject_Call) Return(sb smartblock.SmartBlock, err error) *MockCache_DeriveTreeObject_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockCache_DeriveTreeObject_Call) RunAndReturn(run func(context.Context, string, objectcache.TreeDerivationParams) (smartblock.SmartBlock, error)) *MockCache_DeriveTreeObject_Call {
_c.Call.Return(run)
return _c
}
// DeriveTreePayload provides a mock function with given fields: ctx, spaceID, params
func (_m *MockCache) DeriveTreePayload(ctx context.Context, spaceID string, params payloadcreator.PayloadDerivationParams) (treestorage.TreeStorageCreatePayload, error) {
ret := _m.Called(ctx, spaceID, params)
var r0 treestorage.TreeStorageCreatePayload
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, payloadcreator.PayloadDerivationParams) (treestorage.TreeStorageCreatePayload, error)); ok {
return rf(ctx, spaceID, params)
}
if rf, ok := ret.Get(0).(func(context.Context, string, payloadcreator.PayloadDerivationParams) treestorage.TreeStorageCreatePayload); ok {
r0 = rf(ctx, spaceID, params)
} else {
r0 = ret.Get(0).(treestorage.TreeStorageCreatePayload)
}
if rf, ok := ret.Get(1).(func(context.Context, string, payloadcreator.PayloadDerivationParams) error); ok {
r1 = rf(ctx, spaceID, params)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_DeriveTreePayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeriveTreePayload'
type MockCache_DeriveTreePayload_Call struct {
*mock.Call
}
// DeriveTreePayload is a helper method to define mock.On call
// - ctx context.Context
// - spaceID string
// - params payloadcreator.PayloadDerivationParams
func (_e *MockCache_Expecter) DeriveTreePayload(ctx interface{}, spaceID interface{}, params interface{}) *MockCache_DeriveTreePayload_Call {
return &MockCache_DeriveTreePayload_Call{Call: _e.mock.On("DeriveTreePayload", ctx, spaceID, params)}
}
func (_c *MockCache_DeriveTreePayload_Call) Run(run func(ctx context.Context, spaceID string, params payloadcreator.PayloadDerivationParams)) *MockCache_DeriveTreePayload_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(payloadcreator.PayloadDerivationParams))
})
return _c
}
func (_c *MockCache_DeriveTreePayload_Call) Return(storagePayload treestorage.TreeStorageCreatePayload, err error) *MockCache_DeriveTreePayload_Call {
_c.Call.Return(storagePayload, err)
return _c
}
func (_c *MockCache_DeriveTreePayload_Call) RunAndReturn(run func(context.Context, string, payloadcreator.PayloadDerivationParams) (treestorage.TreeStorageCreatePayload, error)) *MockCache_DeriveTreePayload_Call {
_c.Call.Return(run)
return _c
}
// DoLockedIfNotExists provides a mock function with given fields: objectID, proc
func (_m *MockCache) DoLockedIfNotExists(objectID string, proc func() error) error {
ret := _m.Called(objectID, proc)
var r0 error
if rf, ok := ret.Get(0).(func(string, func() error) error); ok {
r0 = rf(objectID, proc)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockCache_DoLockedIfNotExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DoLockedIfNotExists'
type MockCache_DoLockedIfNotExists_Call struct {
*mock.Call
}
// DoLockedIfNotExists is a helper method to define mock.On call
// - objectID string
// - proc func() error
func (_e *MockCache_Expecter) DoLockedIfNotExists(objectID interface{}, proc interface{}) *MockCache_DoLockedIfNotExists_Call {
return &MockCache_DoLockedIfNotExists_Call{Call: _e.mock.On("DoLockedIfNotExists", objectID, proc)}
}
func (_c *MockCache_DoLockedIfNotExists_Call) Run(run func(objectID string, proc func() error)) *MockCache_DoLockedIfNotExists_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(func() error))
})
return _c
}
func (_c *MockCache_DoLockedIfNotExists_Call) Return(_a0 error) *MockCache_DoLockedIfNotExists_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockCache_DoLockedIfNotExists_Call) RunAndReturn(run func(string, func() error) error) *MockCache_DoLockedIfNotExists_Call {
_c.Call.Return(run)
return _c
}
// GetObject provides a mock function with given fields: ctx, id
func (_m *MockCache) GetObject(ctx context.Context, id domain.FullID) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, id)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, domain.FullID) (smartblock.SmartBlock, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, domain.FullID) smartblock.SmartBlock); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, domain.FullID) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_GetObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetObject'
type MockCache_GetObject_Call struct {
*mock.Call
}
// GetObject is a helper method to define mock.On call
// - ctx context.Context
// - id domain.FullID
func (_e *MockCache_Expecter) GetObject(ctx interface{}, id interface{}) *MockCache_GetObject_Call {
return &MockCache_GetObject_Call{Call: _e.mock.On("GetObject", ctx, id)}
}
func (_c *MockCache_GetObject_Call) Run(run func(ctx context.Context, id domain.FullID)) *MockCache_GetObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(domain.FullID))
})
return _c
}
func (_c *MockCache_GetObject_Call) Return(sb smartblock.SmartBlock, err error) *MockCache_GetObject_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockCache_GetObject_Call) RunAndReturn(run func(context.Context, domain.FullID) (smartblock.SmartBlock, error)) *MockCache_GetObject_Call {
_c.Call.Return(run)
return _c
}
// GetObjectWithTimeout provides a mock function with given fields: ctx, id
func (_m *MockCache) GetObjectWithTimeout(ctx context.Context, id domain.FullID) (smartblock.SmartBlock, error) {
ret := _m.Called(ctx, id)
var r0 smartblock.SmartBlock
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, domain.FullID) (smartblock.SmartBlock, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, domain.FullID) smartblock.SmartBlock); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(smartblock.SmartBlock)
}
}
if rf, ok := ret.Get(1).(func(context.Context, domain.FullID) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockCache_GetObjectWithTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetObjectWithTimeout'
type MockCache_GetObjectWithTimeout_Call struct {
*mock.Call
}
// GetObjectWithTimeout is a helper method to define mock.On call
// - ctx context.Context
// - id domain.FullID
func (_e *MockCache_Expecter) GetObjectWithTimeout(ctx interface{}, id interface{}) *MockCache_GetObjectWithTimeout_Call {
return &MockCache_GetObjectWithTimeout_Call{Call: _e.mock.On("GetObjectWithTimeout", ctx, id)}
}
func (_c *MockCache_GetObjectWithTimeout_Call) Run(run func(ctx context.Context, id domain.FullID)) *MockCache_GetObjectWithTimeout_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(domain.FullID))
})
return _c
}
func (_c *MockCache_GetObjectWithTimeout_Call) Return(sb smartblock.SmartBlock, err error) *MockCache_GetObjectWithTimeout_Call {
_c.Call.Return(sb, err)
return _c
}
func (_c *MockCache_GetObjectWithTimeout_Call) RunAndReturn(run func(context.Context, domain.FullID) (smartblock.SmartBlock, error)) *MockCache_GetObjectWithTimeout_Call {
_c.Call.Return(run)
return _c
}
// Init provides a mock function with given fields: a
func (_m *MockCache) Init(a *app.App) error {
ret := _m.Called(a)
var r0 error
if rf, ok := ret.Get(0).(func(*app.App) error); ok {
r0 = rf(a)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockCache_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init'
type MockCache_Init_Call struct {
*mock.Call
}
// Init is a helper method to define mock.On call
// - a *app.App
func (_e *MockCache_Expecter) Init(a interface{}) *MockCache_Init_Call {
return &MockCache_Init_Call{Call: _e.mock.On("Init", a)}
}
func (_c *MockCache_Init_Call) Run(run func(a *app.App)) *MockCache_Init_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(*app.App))
})
return _c
}
func (_c *MockCache_Init_Call) Return(err error) *MockCache_Init_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockCache_Init_Call) RunAndReturn(run func(*app.App) error) *MockCache_Init_Call {
_c.Call.Return(run)
return _c
}
// Name provides a mock function with given fields:
func (_m *MockCache) Name() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// MockCache_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name'
type MockCache_Name_Call struct {
*mock.Call
}
// Name is a helper method to define mock.On call
func (_e *MockCache_Expecter) Name() *MockCache_Name_Call {
return &MockCache_Name_Call{Call: _e.mock.On("Name")}
}
func (_c *MockCache_Name_Call) Run(run func()) *MockCache_Name_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockCache_Name_Call) Return(name string) *MockCache_Name_Call {
_c.Call.Return(name)
return _c
}
func (_c *MockCache_Name_Call) RunAndReturn(run func() string) *MockCache_Name_Call {
_c.Call.Return(run)
return _c
}
// Remove provides a mock function with given fields: ctx, objectID
func (_m *MockCache) Remove(ctx context.Context, objectID string) error {
ret := _m.Called(ctx, objectID)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, objectID)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockCache_Remove_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Remove'
type MockCache_Remove_Call struct {
*mock.Call
}
// Remove is a helper method to define mock.On call
// - ctx context.Context
// - objectID string
func (_e *MockCache_Expecter) Remove(ctx interface{}, objectID interface{}) *MockCache_Remove_Call {
return &MockCache_Remove_Call{Call: _e.mock.On("Remove", ctx, objectID)}
}
func (_c *MockCache_Remove_Call) Run(run func(ctx context.Context, objectID string)) *MockCache_Remove_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockCache_Remove_Call) Return(_a0 error) *MockCache_Remove_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockCache_Remove_Call) RunAndReturn(run func(context.Context, string) error) *MockCache_Remove_Call {
_c.Call.Return(run)
return _c
}
// Run provides a mock function with given fields: ctx
func (_m *MockCache) Run(ctx context.Context) error {
ret := _m.Called(ctx)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockCache_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
type MockCache_Run_Call struct {
*mock.Call
}
// Run is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockCache_Expecter) Run(ctx interface{}) *MockCache_Run_Call {
return &MockCache_Run_Call{Call: _e.mock.On("Run", ctx)}
}
func (_c *MockCache_Run_Call) Run(run func(ctx context.Context)) *MockCache_Run_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockCache_Run_Call) Return(err error) *MockCache_Run_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockCache_Run_Call) RunAndReturn(run func(context.Context) error) *MockCache_Run_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewMockCache interface {
mock.TestingT
Cleanup(func())
}
// NewMockCache creates a new instance of MockCache. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockCache(t mockConstructorTestingTNewMockCache) *MockCache {
mock := &MockCache{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -1,4 +1,4 @@
package block
package objectcache
import (
"crypto/rand"
@ -10,10 +10,12 @@ import (
"github.com/anyproto/anytype-heart/core/domain"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
spaceservice "github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/spacecore"
)
func createChangePayload(sbType coresb.SmartBlockType, key domain.UniqueKey) (data []byte, err error) {
const ChangeType = "anytype.object"
func createChangePayload(sbType coresb.SmartBlockType, key domain.UniqueKey, spaceID string) (data []byte, err error) {
var keyStr string
if key != nil {
if key.SmartblockType() != sbType {
@ -21,15 +23,31 @@ func createChangePayload(sbType coresb.SmartBlockType, key domain.UniqueKey) (da
}
keyStr = key.InternalKey()
}
payload := &model.ObjectChangePayload{SmartBlockType: model.SmartBlockType(sbType), Key: keyStr}
if sbType == coresb.SmartBlockTypeSpaceView {
mdl := &model.SpaceObjectHeader{SpaceID: spaceID}
marshalled, err := mdl.Marshal()
if err != nil {
return nil, err
}
payload.Data = marshalled
}
return payload.Marshal()
}
func derivePayload(spaceId string, signKey crypto.PrivKey, changePayload []byte) objecttree.ObjectTreeCreatePayload {
func derivePayload(spaceId string, changePayload []byte) objecttree.ObjectTreeDerivePayload {
return objecttree.ObjectTreeDerivePayload{
ChangeType: spacecore.ChangeType,
ChangePayload: changePayload,
SpaceId: spaceId,
IsEncrypted: true,
}
}
func derivePersonalPayload(spaceId string, signKey crypto.PrivKey, changePayload []byte) objecttree.ObjectTreeCreatePayload {
return objecttree.ObjectTreeCreatePayload{
PrivKey: signKey,
ChangeType: spaceservice.ChangeType,
ChangeType: spacecore.ChangeType,
ChangePayload: changePayload,
SpaceId: spaceId,
IsEncrypted: true,
@ -43,7 +61,7 @@ func createPayload(spaceId string, signKey crypto.PrivKey, changePayload []byte,
}
return objecttree.ObjectTreeCreatePayload{
PrivKey: signKey,
ChangeType: spaceservice.ChangeType,
ChangeType: spacecore.ChangeType,
ChangePayload: changePayload,
SpaceId: spaceId,
IsEncrypted: true,

View file

@ -1,4 +1,4 @@
package block
package objectcache
import (
"testing"
@ -12,7 +12,7 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/require"
spaceservice "github.com/anyproto/anytype-heart/space"
spaceservice "github.com/anyproto/anytype-heart/space/spacecore"
)
func Test_Payloads(t *testing.T) {
@ -56,12 +56,12 @@ func Test_Payloads(t *testing.T) {
})
t.Run("test derive payload", func(t *testing.T) {
firstPayload := derivePayload("spaceId", keys.SignKey, changePayload)
firstRoot, err := objecttree.CreateObjectTreeRoot(firstPayload, aclList)
firstPayload := derivePayload("spaceId", changePayload)
firstRoot, err := objecttree.DeriveObjectTreeRoot(firstPayload, aclList)
require.NoError(t, err)
secondPayload := derivePayload("spaceId", keys.SignKey, changePayload)
secondRoot, err := objecttree.CreateObjectTreeRoot(secondPayload, aclList)
secondPayload := derivePayload("spaceId", changePayload)
secondRoot, err := objecttree.DeriveObjectTreeRoot(secondPayload, aclList)
require.NoError(t, err)
// checking that derived roots are equal

View file

@ -0,0 +1,134 @@
package objectcache
import (
"context"
"fmt"
"time"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/object/payloadcreator"
"github.com/anyproto/anytype-heart/core/domain"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
)
// TreeDerivationParams is a struct for deriving a tree
type TreeDerivationParams struct {
Key domain.UniqueKey
InitFunc InitFunc
TargetSpaceID string
}
// TreeCreationParams is a struct for creating a tree
type TreeCreationParams struct {
Time time.Time
SmartblockType coresb.SmartBlockType
InitFunc InitFunc
TargetSpaceID string
}
// CreateTreePayload creates a tree payload for a given space and smart block type
func (c *objectCache) CreateTreePayload(ctx context.Context, spaceID string, params payloadcreator.PayloadCreationParams) (treestorage.TreeStorageCreatePayload, error) {
space, err := c.spaceService.Get(ctx, spaceID)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
changePayload, err := createChangePayload(params.SmartblockType, nil, params.TargetSpaceID)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
treePayload, err := createPayload(space.Id(), c.accountService.Account().SignKey, changePayload, params.Time.Unix())
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
return space.TreeBuilder().CreateTree(ctx, treePayload)
}
// CreateTreeObject creates a tree object
func (c *objectCache) CreateTreeObject(ctx context.Context, spaceID string, params TreeCreationParams) (sb smartblock.SmartBlock, err error) {
payload, err := c.CreateTreePayload(ctx, spaceID, payloadcreator.PayloadCreationParams{
Time: params.Time,
SmartblockType: params.SmartblockType,
TargetSpaceID: params.TargetSpaceID,
})
if err != nil {
return nil, err
}
return c.CreateTreeObjectWithPayload(ctx, spaceID, payload, params.InitFunc)
}
// CreateTreeObjectWithPayload creates a tree object with a given payload and object init func
func (c *objectCache) CreateTreeObjectWithPayload(ctx context.Context, spaceID string, payload treestorage.TreeStorageCreatePayload, initFunc InitFunc) (sb smartblock.SmartBlock, err error) {
space, err := c.spaceService.Get(ctx, spaceID)
if err != nil {
return nil, err
}
id := domain.FullID{
SpaceID: spaceID,
ObjectID: payload.RootRawChange.Id,
}
tr, err := space.TreeBuilder().PutTree(ctx, payload, nil)
if err != nil {
return nil, fmt.Errorf("put tree: %w", err)
}
if tr != nil {
tr.Close()
}
ctx = ContextWithCreateOption(ctx, initFunc)
return c.GetObject(ctx, id)
}
// DeriveTreePayload derives a tree payload for a given space and smart block type
// it takes into account whether it is for personal space and if so uses old derivation logic
// to maintain backward compatibility
func (c *objectCache) DeriveTreePayload(ctx context.Context, spaceID string, params payloadcreator.PayloadDerivationParams) (storagePayload treestorage.TreeStorageCreatePayload, err error) {
space, err := c.spaceService.Get(ctx, spaceID)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
changePayload, err := createChangePayload(params.Key.SmartblockType(), params.Key, params.TargetSpaceID)
if err != nil {
return treestorage.TreeStorageCreatePayload{}, err
}
accountKeys := c.accountService.Account()
// we have to derive ids differently for personal space
if c.provider.PersonalSpaceID() == spaceID {
treePayload := derivePersonalPayload(space.Id(), accountKeys.SignKey, changePayload)
create, err := space.TreeBuilder().CreateTree(context.Background(), treePayload)
if err != nil {
return storagePayload, err
}
return create, err
}
treePayload := derivePayload(space.Id(), changePayload)
create, err := space.TreeBuilder().DeriveTree(context.Background(), treePayload)
if err != nil {
return storagePayload, err
}
return create, err
}
// DeriveTreeObject derives a tree object for a given space and smart block type
func (c *objectCache) DeriveTreeObject(ctx context.Context, spaceID string, params TreeDerivationParams) (sb smartblock.SmartBlock, err error) {
payload, err := c.DeriveTreePayload(ctx, spaceID, payloadcreator.PayloadDerivationParams{
Key: params.Key,
TargetSpaceID: params.TargetSpaceID,
})
if err != nil {
return nil, err
}
// TODO: [MR] rewrite to use any-sync derivation
return c.CreateTreeObjectWithPayload(ctx, spaceID, payload, params.InitFunc)
}
func (c *objectCache) DeriveObjectID(ctx context.Context, spaceID string, uniqueKey domain.UniqueKey) (id string, err error) {
payload, err := c.DeriveTreePayload(ctx, spaceID, payloadcreator.PayloadDerivationParams{
Key: uniqueKey,
TargetSpaceID: spaceID,
})
if err != nil {
return "", err
}
return payload.RootRawChange.Id, nil
}

View file

@ -16,6 +16,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/system_object"
"github.com/anyproto/anytype-heart/metrics"
@ -28,7 +29,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/uri"
@ -49,7 +50,8 @@ type Service interface {
type Creator struct {
blockService BlockService
blockPicker block.Picker
objectCache objectcache.Cache
blockPicker block.ObjectGetter
objectStore objectstore.ObjectStore
collectionService CollectionService
systemObjectService system_object.Service
@ -72,7 +74,8 @@ func NewCreator() *Creator {
func (c *Creator) Init(a *app.App) (err error) {
c.blockService = a.MustComponent(block.CName).(BlockService)
c.blockPicker = a.MustComponent(block.CName).(block.Picker)
c.objectCache = a.MustComponent(objectcache.CName).(objectcache.Cache)
c.blockPicker = a.MustComponent(block.CName).(block.ObjectGetter)
c.objectStore = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
c.bookmark = a.MustComponent(bookmark.CName).(bookmark.Service)
c.bookmark = a.MustComponent(bookmark.CName).(bookmark.Service)
@ -93,8 +96,6 @@ func (c *Creator) Name() (name string) {
// TODO Temporarily
type BlockService interface {
StateFromTemplate(templateID, name string) (st *state.State, err error)
CreateTreeObject(ctx context.Context, spaceID string, tp coresb.SmartBlockType, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error)
DeriveTreeObjectWithUniqueKey(ctx context.Context, spaceID string, key domain.UniqueKey, initFunc smartblock.InitFunc) (sb smartblock.SmartBlock, err error)
TemplateClone(spaceID string, id string) (templateID string, err error)
}
@ -168,12 +169,19 @@ func (c *Creator) CreateSmartBlockFromState(ctx context.Context, spaceID string,
if err != nil {
return "", nil, err
}
sb, err = c.blockService.DeriveTreeObjectWithUniqueKey(ctx, spaceID, uk, initFunc)
sb, err = c.objectCache.DeriveTreeObject(ctx, spaceID, objectcache.TreeDerivationParams{
Key: uk,
InitFunc: initFunc,
})
if err != nil {
return "", nil, err
}
} else {
sb, err = c.blockService.CreateTreeObject(ctx, spaceID, sbType, initFunc)
sb, err = c.objectCache.CreateTreeObject(ctx, spaceID, objectcache.TreeCreationParams{
Time: time.Now(),
SmartblockType: sbType,
InitFunc: initFunc,
})
if err != nil {
return
}
@ -306,7 +314,7 @@ func (w *Creator) createRelationOption(ctx context.Context, spaceID string, deta
} else if pbtypes.GetString(details, "name") == "" {
return "", nil, fmt.Errorf("name is empty")
} else if pbtypes.GetString(details, bundle.RelationKeyRelationKey.String()) == "" {
return "", nil, fmt.Errorf("invalid relation key: unknown enum")
return "", nil, fmt.Errorf("invalid relation Key: unknown enum")
}
uniqueKey, err := getUniqueKeyOrGenerate(coresb.SmartBlockTypeRelationOption, details)
@ -350,9 +358,9 @@ func (w *Creator) createObjectType(ctx context.Context, spaceID string, details
for _, relKey := range recommendedRelationKeys {
uk, err := domain.NewUniqueKey(coresb.SmartBlockTypeRelation, relKey)
if err != nil {
return "", nil, fmt.Errorf("failed to create unique key: %w", err)
return "", nil, fmt.Errorf("failed to create unique Key: %w", err)
}
id, err := w.coreService.DeriveObjectId(ctx, spaceID, uk)
id, err := w.objectCache.DeriveObjectID(ctx, spaceID, uk)
if err != nil {
return "", nil, fmt.Errorf("failed to derive object id: %w", err)
}

View file

@ -16,7 +16,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/database"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

View file

@ -0,0 +1,30 @@
package payloadcreator
import (
"context"
"time"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/anytype-heart/core/domain"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
)
// PayloadDerivationParams is a struct for deriving a payload
type PayloadDerivationParams struct {
Key domain.UniqueKey
TargetSpaceID string
}
// PayloadCreationParams is a struct for creating a payload
type PayloadCreationParams struct {
Time time.Time
SmartblockType coresb.SmartBlockType
TargetSpaceID string
}
type PayloadCreator interface {
CreateTreePayload(ctx context.Context, spaceID string, params PayloadCreationParams) (treestorage.TreeStorageCreatePayload, error)
DeriveTreePayload(ctx context.Context, spaceID string, params PayloadDerivationParams) (storagePayload treestorage.TreeStorageCreatePayload, err error)
DeriveObjectID(ctx context.Context, spaceID string, uniqueKey domain.UniqueKey) (id string, err error)
}

View file

@ -1 +0,0 @@
package treemanager

View file

@ -22,10 +22,6 @@ import (
var log = logging.Logger("anytype-mw-tree-manager")
const (
concurrentTrees = 10
)
var errAppIsNotRunning = errors.New("app is not running")
type treeManager struct {
@ -35,7 +31,6 @@ type treeManager struct {
onDelete func(id domain.FullID) error
syncer map[string]*treeSyncer
syncStarted bool
syncerLock sync.Mutex
}
@ -47,7 +42,6 @@ func New() treemanager.TreeManager {
func newTreeManager(onDelete func(id domain.FullID) error) *treeManager {
return &treeManager{
onDelete: onDelete,
syncer: make(map[string]*treeSyncer),
}
}
@ -80,15 +74,6 @@ func (m *treeManager) Close(ctx context.Context) error {
return nil
}
func (m *treeManager) StartSync() {
m.syncerLock.Lock()
defer m.syncerLock.Unlock()
m.syncStarted = true
for _, syncer := range m.syncer {
syncer.Run()
}
}
// GetTree should only be called by either space services or debug apis, not the client code
func (m *treeManager) GetTree(ctx context.Context, spaceId, id string) (tr objecttree.ObjectTree, err error) {
if !m.coreService.IsStarted() {
@ -145,19 +130,6 @@ func (m *treeManager) DeleteTree(ctx context.Context, spaceId, treeId string) (e
return
}
// NewTreeSyncer is called in commonspace.SpaceService/NewSpace, so loading a space into cache in space.Service creates a syncer
func (m *treeManager) NewTreeSyncer(spaceId string, treeManager treemanager.TreeManager) treemanager.TreeSyncer {
m.syncerLock.Lock()
defer m.syncerLock.Unlock()
syncer := newTreeSyncer(spaceId, objectcache.ObjectLoadTimeout, concurrentTrees, treeManager)
m.syncer[spaceId] = syncer
if m.syncStarted {
log.With("spaceID", spaceId).Warn("creating tree syncer after run")
syncer.Run()
}
return syncer
}
func (m *treeManager) sendOnRemoveEvent(ids ...string) {
m.eventSender.Broadcast(&pb.Event{
Messages: []*pb.EventMessage{

View file

@ -1,130 +0,0 @@
package treemanager
import (
"context"
"sync"
"testing"
"time"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
)
func TestTreeSyncer(t *testing.T) {
ctrl := gomock.NewController(t)
managerMock := mock_treemanager.NewMockTreeManager(ctrl)
spaceId := "spaceId"
peerId := "peerId"
existingId := "existing"
missingId := "missing"
missingMock := mock_objecttree.NewMockObjectTree(ctrl)
existingMock := mock_synctree.NewMockSyncTree(ctrl)
t.Run("delayed sync", func(t *testing.T) {
syncer := newTreeSyncer(spaceId, objectcache.ObjectLoadTimeout, 10, managerMock)
syncer.Init()
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(existingMock, nil)
existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, missingId).Return(missingMock, nil)
err := syncer.SyncAll(context.Background(), peerId, []string{existingId}, []string{missingId})
require.NoError(t, err)
require.NotNil(t, syncer.requestPools[peerId])
require.NotNil(t, syncer.headPools[peerId])
syncer.Run()
time.Sleep(100 * time.Millisecond)
syncer.Close()
})
t.Run("sync after run", func(t *testing.T) {
syncer := newTreeSyncer(spaceId, objectcache.ObjectLoadTimeout, 10, managerMock)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(existingMock, nil)
existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, missingId).Return(missingMock, nil)
syncer.Init()
syncer.Run()
err := syncer.SyncAll(context.Background(), peerId, []string{existingId}, []string{missingId})
require.NoError(t, err)
require.NotNil(t, syncer.requestPools[peerId])
require.NotNil(t, syncer.headPools[peerId])
time.Sleep(100 * time.Millisecond)
syncer.Close()
})
t.Run("sync same ids", func(t *testing.T) {
syncer := newTreeSyncer(spaceId, objectcache.ObjectLoadTimeout, 10, managerMock)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(existingMock, nil)
existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, missingId).Return(missingMock, nil)
syncer.Init()
syncer.Run()
err := syncer.SyncAll(context.Background(), peerId, []string{existingId, existingId}, []string{missingId, missingId, missingId})
require.NoError(t, err)
require.NotNil(t, syncer.requestPools[peerId])
require.NotNil(t, syncer.headPools[peerId])
time.Sleep(100 * time.Millisecond)
syncer.Close()
})
t.Run("sync concurrent ids", func(t *testing.T) {
ch := make(chan struct{}, 2)
syncer := newTreeSyncer(spaceId, objectcache.ObjectLoadTimeout, 2, managerMock)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(existingMock, nil)
existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, missingId+"1").DoAndReturn(func(ctx context.Context, spaceId, treeId string) (objecttree.ObjectTree, error) {
<-ch
return missingMock, nil
})
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, missingId+"2").DoAndReturn(func(ctx context.Context, spaceId, treeId string) (objecttree.ObjectTree, error) {
<-ch
return missingMock, nil
})
syncer.Init()
syncer.Run()
err := syncer.SyncAll(context.Background(), peerId, []string{existingId}, []string{missingId + "1", missingId + "2"})
require.NoError(t, err)
require.NotNil(t, syncer.requestPools[peerId])
require.NotNil(t, syncer.headPools[peerId])
time.Sleep(100 * time.Millisecond)
syncer.Close()
for i := 0; i < 2; i++ {
ch <- struct{}{}
}
})
t.Run("sync context cancel", func(t *testing.T) {
var events []string
syncer := newTreeSyncer(spaceId, objectcache.ObjectLoadTimeout, 1, managerMock)
mutex := sync.Mutex{}
managerMock.EXPECT().GetTree(gomock.Any(), spaceId, missingId).DoAndReturn(func(ctx context.Context, spaceId, treeId string) (objecttree.ObjectTree, error) {
<-ctx.Done()
mutex.Lock()
events = append(events, "after done")
mutex.Unlock()
return missingMock, nil
})
syncer.Init()
syncer.Run()
err := syncer.SyncAll(context.Background(), peerId, nil, []string{missingId})
require.NoError(t, err)
require.NotNil(t, syncer.requestPools[peerId])
require.NotNil(t, syncer.headPools[peerId])
time.Sleep(100 * time.Millisecond)
mutex.Lock()
events = append(events, "before close")
mutex.Unlock()
syncer.Close()
time.Sleep(100 * time.Millisecond)
mutex.Lock()
require.Equal(t, []string{"before close", "after done"}, events)
mutex.Unlock()
})
}

View file

@ -1,17 +1,22 @@
package treemanager
package treesyncer
import (
"context"
"sync"
"time"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/logger"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
"github.com/anyproto/any-sync/commonspace/object/treemanager"
"github.com/anyproto/any-sync/commonspace/object/treesyncer"
"github.com/anyproto/any-sync/net/peer"
"github.com/anyproto/any-sync/net/streampool"
"go.uber.org/zap"
)
var log = logger.NewNamed(treemanager.CName)
type executor struct {
pool *streampool.ExecPool
objs map[string]struct{}
@ -61,28 +66,51 @@ type treeSyncer struct {
isRunning bool
}
func newTreeSyncer(spaceId string, timeout time.Duration, concurrentReqs int, treeManager treemanager.TreeManager) *treeSyncer {
func NewTreeSyncer(spaceId string) treesyncer.TreeSyncer {
mainCtx, cancel := context.WithCancel(context.Background())
return &treeSyncer{
mainCtx: mainCtx,
cancel: cancel,
requests: concurrentReqs,
requests: 10,
spaceId: spaceId,
timeout: timeout,
timeout: time.Second * 30,
requestPools: map[string]*executor{},
headPools: map[string]*executor{},
treeManager: treeManager,
}
}
func (t *treeSyncer) Init() {
func (t *treeSyncer) Init(a *app.App) (err error) {
t.treeManager = app.MustComponent[treemanager.TreeManager](a)
return nil
}
func (t *treeSyncer) Run() {
func (t *treeSyncer) Name() (name string) {
return treesyncer.CName
}
func (t *treeSyncer) Run(ctx context.Context) (err error) {
return nil
}
func (t *treeSyncer) Close(ctx context.Context) (err error) {
t.Lock()
defer t.Unlock()
t.cancel()
t.isRunning = false
for _, pool := range t.headPools {
pool.close()
}
for _, pool := range t.requestPools {
pool.close()
}
return nil
}
func (t *treeSyncer) StartSync() {
t.Lock()
defer t.Unlock()
t.isRunning = true
log.Info("starting request pool")
log.Info("starting request pool", zap.String("spaceId", t.spaceId))
for _, p := range t.requestPools {
p.run()
}
@ -162,17 +190,3 @@ func (t *treeSyncer) updateTree(peerId, id string) {
log.Debug("success synctree.SyncWithPeer")
}
}
func (t *treeSyncer) Close() error {
t.Lock()
defer t.Unlock()
t.cancel()
t.isRunning = false
for _, pool := range t.headPools {
pool.close()
}
for _, pool := range t.requestPools {
pool.close()
}
return nil
}

View file

@ -0,0 +1,156 @@
package treesyncer
import (
"context"
"sync"
"testing"
"time"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/anyproto/anytype-heart/tests/testutil"
)
type fixture struct {
*treeSyncer
missingMock *mock_objecttree.MockObjectTree
existingMock *mock_synctree.MockSyncTree
treeManager *mock_treemanager.MockTreeManager
}
func newFixture(t *testing.T, spaceId string) *fixture {
ctrl := gomock.NewController(t)
treeManager := mock_treemanager.NewMockTreeManager(ctrl)
missingMock := mock_objecttree.NewMockObjectTree(ctrl)
existingMock := mock_synctree.NewMockSyncTree(ctrl)
a := new(app.App)
a.Register(testutil.PrepareMock(context.Background(), a, treeManager))
syncer := NewTreeSyncer(spaceId)
err := syncer.Init(a)
require.NoError(t, err)
return &fixture{
treeSyncer: syncer.(*treeSyncer),
missingMock: missingMock,
existingMock: existingMock,
treeManager: treeManager,
}
}
func TestTreeSyncer(t *testing.T) {
spaceId := "spaceId"
peerId := "peerId"
existingId := "existing"
missingId := "missing"
t.Run("delayed sync", func(t *testing.T) {
ctx := context.Background()
fx := newFixture(t, spaceId)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(fx.existingMock, nil)
fx.existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, missingId).Return(fx.missingMock, nil)
err := fx.SyncAll(context.Background(), peerId, []string{existingId}, []string{missingId})
require.NoError(t, err)
require.NotNil(t, fx.requestPools[peerId])
require.NotNil(t, fx.headPools[peerId])
fx.StartSync()
time.Sleep(100 * time.Millisecond)
fx.Close(ctx)
})
t.Run("sync after run", func(t *testing.T) {
ctx := context.Background()
fx := newFixture(t, spaceId)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(fx.existingMock, nil)
fx.existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, missingId).Return(fx.missingMock, nil)
fx.StartSync()
err := fx.SyncAll(context.Background(), peerId, []string{existingId}, []string{missingId})
require.NoError(t, err)
require.NotNil(t, fx.requestPools[peerId])
require.NotNil(t, fx.headPools[peerId])
time.Sleep(100 * time.Millisecond)
fx.Close(ctx)
})
t.Run("sync same ids", func(t *testing.T) {
ctx := context.Background()
fx := newFixture(t, spaceId)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(fx.existingMock, nil)
fx.existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, missingId).Return(fx.missingMock, nil)
fx.StartSync()
err := fx.SyncAll(context.Background(), peerId, []string{existingId, existingId}, []string{missingId, missingId, missingId})
require.NoError(t, err)
require.NotNil(t, fx.requestPools[peerId])
require.NotNil(t, fx.headPools[peerId])
time.Sleep(100 * time.Millisecond)
fx.Close(ctx)
})
t.Run("sync concurrent ids", func(t *testing.T) {
ctx := context.Background()
ch := make(chan struct{}, 2)
fx := newFixture(t, spaceId)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, existingId).Return(fx.existingMock, nil)
fx.existingMock.EXPECT().SyncWithPeer(gomock.Any(), peerId).Return(nil)
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, missingId+"1").DoAndReturn(func(ctx context.Context, spaceId, treeId string) (objecttree.ObjectTree, error) {
<-ch
return fx.missingMock, nil
})
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, missingId+"2").DoAndReturn(func(ctx context.Context, spaceId, treeId string) (objecttree.ObjectTree, error) {
<-ch
return fx.missingMock, nil
})
fx.StartSync()
err := fx.SyncAll(context.Background(), peerId, []string{existingId}, []string{missingId + "1", missingId + "2"})
require.NoError(t, err)
require.NotNil(t, fx.requestPools[peerId])
require.NotNil(t, fx.headPools[peerId])
time.Sleep(100 * time.Millisecond)
fx.Close(ctx)
for i := 0; i < 2; i++ {
ch <- struct{}{}
}
})
t.Run("sync context cancel", func(t *testing.T) {
ctx := context.Background()
var events []string
fx := newFixture(t, spaceId)
mutex := sync.Mutex{}
fx.treeManager.EXPECT().GetTree(gomock.Any(), spaceId, missingId).DoAndReturn(func(ctx context.Context, spaceId, treeId string) (objecttree.ObjectTree, error) {
<-ctx.Done()
mutex.Lock()
events = append(events, "after done")
mutex.Unlock()
return fx.missingMock, nil
})
fx.StartSync()
err := fx.SyncAll(context.Background(), peerId, nil, []string{missingId})
require.NoError(t, err)
require.NotNil(t, fx.requestPools[peerId])
require.NotNil(t, fx.headPools[peerId])
time.Sleep(100 * time.Millisecond)
mutex.Lock()
events = append(events, "before close")
mutex.Unlock()
fx.Close(ctx)
time.Sleep(100 * time.Millisecond)
mutex.Lock()
require.Equal(t, []string{"before close", "after done"}, events)
mutex.Unlock()
})
}

View file

@ -39,7 +39,6 @@ func TestService_DataviewRestrictions(t *testing.T) {
t.Run("ordinary objects don't have restrictions", func(t *testing.T) {
objectTypeID := "derivedFrom(page)"
s.systemObjectServiceMock.EXPECT().HasObjectType(objectTypeID).Return(true, nil)
restrictions := s.GetRestrictions(
newRestrictionHolder(
smartblock.SmartBlockTypePage,

View file

@ -7,19 +7,19 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/stretchr/testify/require"
"context"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/system_object/mock_system_object"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/mock_objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/tests/testutil"
)
type fixture struct {
Service
objectStoreMock *mock_objectstore.MockObjectStore
systemObjectServiceMock *mock_system_object.MockService
objectStoreMock *mock_objectstore.MockObjectStore
}
func newFixture(t *testing.T) *fixture {
@ -34,14 +34,13 @@ func newFixture(t *testing.T) *fixture {
a := &app.App{}
a.Register(objectStore)
a.Register(sbtProvider)
a.Register(testutil.PrepareMock(a, systemObjectService))
a.Register(testutil.PrepareMock(context.Background(), a, systemObjectService))
s := New()
err := s.Init(a)
require.NoError(t, err)
return &fixture{
Service: s,
objectStoreMock: objectStore,
systemObjectServiceMock: systemObjectService,
Service: s,
objectStoreMock: objectStore,
}
}

View file

@ -1,7 +1,6 @@
package restriction
import (
"errors"
"fmt"
"github.com/gogo/protobuf/types"
@ -210,13 +209,6 @@ func (s *service) getObjectRestrictions(rh RestrictionHolder) (r ObjectRestricti
r = ObjectRestrictions{}
}
}
if !errors.Is(r.Check(model.Restrictions_Template), ErrRestricted) {
if ok, err := s.systemObjectService.HasObjectType(rh.ObjectTypeID()); err != nil || !ok {
r = append(r, model.Restrictions_Template)
}
}
return
}

View file

@ -3,18 +3,15 @@ package restriction
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/stretchr/testify/assert"
)
// TODO Use constructors instead for initializing restrictionHolder structures by hand. See givenObjectType and givenRelation
func TestService_ObjectRestrictionsById(t *testing.T) {
rest := newFixture(t)
rest.systemObjectServiceMock.EXPECT().HasObjectType(mock.Anything).Return(false, nil)
assert.ErrorIs(t, rest.GetRestrictions(&restrictionHolder{
sbType: coresb.SmartBlockTypeAnytypeProfile,
@ -93,8 +90,6 @@ func TestService_ObjectRestrictionsById(t *testing.T) {
// TODO Use constructors instead for initializing restrictionHolder structures by hand. See givenObjectType and givenRelation
func TestTemplateRestriction(t *testing.T) {
rs := newFixture(t)
rs.systemObjectServiceMock.EXPECT().HasObjectType(bundle.TypeKeyPage.URL()).Return(false, nil)
rs.systemObjectServiceMock.EXPECT().HasObjectType(bundle.TypeKeyContact.URL()).Return(true, nil)
assert.ErrorIs(t, rs.GetRestrictions(&restrictionHolder{
// id: "cannot make template from Template smartblock type",
@ -123,15 +118,6 @@ func TestTemplateRestriction(t *testing.T) {
model.Restrictions_Template,
), ErrRestricted)
assert.ErrorIs(t, rs.GetRestrictions(&restrictionHolder{
// id: "cannot make template from object with objectType not added to space",
sbType: coresb.SmartBlockTypePage,
layout: model.ObjectType_basic,
objectTypeID: bundle.TypeKeyPage.URL(),
}).Object.Check(
model.Restrictions_Template,
), ErrRestricted)
assert.NoError(t, rs.GetRestrictions(&restrictionHolder{
// id: "make template from object with objectType added to space",
sbType: coresb.SmartBlockTypePage,

View file

@ -12,7 +12,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

View file

@ -26,6 +26,7 @@ import (
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/editor/template"
"github.com/anyproto/anytype-heart/core/block/history"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/block/restriction"
@ -49,7 +50,8 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/internalflag"
"github.com/anyproto/anytype-heart/util/linkpreview"
"github.com/anyproto/anytype-heart/util/mutex"
@ -105,7 +107,6 @@ type objectCreator interface {
CreateSmartBlockFromState(ctx context.Context, spaceID string, sbType coresb.SmartBlockType, objectTypeKeys []domain.TypeKey, details *types.Struct, createState *state.State) (id string, newDetails *types.Struct, err error)
CreateObject(ctx context.Context, spaceID string, req DetailsGetter, objectTypeKey domain.TypeKey) (id string, details *types.Struct, err error)
}
type DetailsGetter interface {
GetDetails() *types.Struct
}
@ -115,34 +116,27 @@ type InternalFlagsGetter interface {
type TemplateIDGetter interface {
GetTemplateId() string
}
type indexer interface {
EnsurePreinstalledObjects(spaceID string) error
}
type builtinObjects interface {
CreateObjectsForUseCase(ctx session.Context, spaceID string, req pb.RpcObjectImportUseCaseRequestUseCase) (code pb.RpcObjectImportUseCaseResponseErrorCode, err error)
}
type Service struct {
anytype core.Service
syncStatus syncstatus.Service
eventSender event.Sender
linkPreview linkpreview.LinkPreview
process process.Service
app *app.App
source source.Service
objectStore objectstore.ObjectStore
restriction restriction.Service
bookmark bookmarksvc.Service
systemObjectService system_object.Service
objectCache objectcache.Cache
indexer indexer
objectCreator objectCreator
spaceService space.Service
anytype core.Service
syncStatus syncstatus.Service
eventSender event.Sender
linkPreview linkpreview.LinkPreview
process process.Service
app *app.App
source source.Service
objectStore objectstore.ObjectStore
restriction restriction.Service
bookmark bookmarksvc.Service
systemObjectService system_object.Service
objectCache objectcache.Cache
objectCreator objectCreator
resolver idresolver.Resolver
spaceService space.SpaceService
spaceCore spacecore.SpaceCoreService
commonAccount accountservice.Service
fileStore filestore.FileStore
tempDirProvider core.TempDirProvider
@ -178,18 +172,19 @@ func (s *Service) Init(a *app.App) (err error) {
s.bookmark = a.MustComponent("bookmark-importer").(bookmarksvc.Service)
s.systemObjectService = a.MustComponent(system_object.CName).(system_object.Service)
s.objectCreator = a.MustComponent("objectCreator").(objectCreator)
s.spaceService = a.MustComponent(space.CName).(space.Service)
s.spaceService = a.MustComponent(space.CName).(space.SpaceService)
s.commonAccount = a.MustComponent(accountservice.CName).(accountservice.Service)
s.fileStore = app.MustComponent[filestore.FileStore](a)
s.fileSync = app.MustComponent[filesync.FileSync](a)
s.fileService = app.MustComponent[files.Service](a)
s.objectCache = app.MustComponent[objectcache.Cache](a)
s.resolver = a.MustComponent(idresolver.CName).(idresolver.Resolver)
s.spaceCore = app.MustComponent[spacecore.SpaceCoreService](a)
s.tempDirProvider = app.MustComponent[core.TempDirProvider](a)
s.sbtProvider = app.MustComponent[typeprovider.SmartBlockTypeProvider](a)
s.layoutConverter = app.MustComponent[converter.LayoutConverter](a)
s.indexer = app.MustComponent[indexer](a)
s.builtinObjectService = app.MustComponent[builtinObjects](a)
s.app = a
return
@ -199,12 +194,23 @@ func (s *Service) Run(ctx context.Context) (err error) {
return
}
func (s *Service) PickBlock(ctx context.Context, objectID string) (sb smartblock.SmartBlock, err error) {
return s.objectCache.PickBlock(ctx, objectID)
func (s *Service) GetObject(ctx context.Context, objectID string) (sb smartblock.SmartBlock, err error) {
spaceID, err := s.resolver.ResolveSpaceID(objectID)
if err != nil {
return nil, err
}
return s.objectCache.GetObject(ctx, domain.FullID{
ObjectID: objectID,
SpaceID: spaceID,
})
}
func (s *Service) GetObjectByFullID(ctx context.Context, id domain.FullID) (sb smartblock.SmartBlock, err error) {
return s.objectCache.GetObject(ctx, id)
}
func (s *Service) OpenBlock(sctx session.Context, id string, includeRelationsAsDependentObjects bool) (obj *model.ObjectView, err error) {
spaceID, err := s.spaceService.ResolveSpaceID(id)
spaceID, err := s.resolver.ResolveSpaceID(id)
if err != nil {
return nil, fmt.Errorf("resolve space id: %w", err)
}
@ -358,7 +364,7 @@ func (s *Service) prepareDetailsForInstallingObject(ctx context.Context, spaceID
// should never happen
return nil, err
}
id, err := s.anytype.DeriveObjectId(ctx, spaceID, uniqueKey)
id, err := s.objectCache.DeriveObjectID(ctx, spaceID, uniqueKey)
if err != nil {
// should never happen
return nil, err
@ -378,7 +384,7 @@ func (s *Service) prepareDetailsForInstallingObject(ctx context.Context, spaceID
// should never happen
return nil, err
}
id, err := s.anytype.DeriveObjectId(ctx, spaceID, uniqueKey)
id, err := s.objectCache.DeriveObjectID(ctx, spaceID, uniqueKey)
if err != nil {
// should never happen
return nil, err
@ -617,60 +623,19 @@ func (s *Service) SelectWorkspace(req *pb.RpcWorkspaceSelectRequest) error {
}
func (s *Service) GetCurrentWorkspace(req *pb.RpcWorkspaceGetCurrentRequest) (string, error) {
return "", nil
panic("should be removed")
}
func (s *Service) GetAllWorkspaces(req *pb.RpcWorkspaceGetAllRequest) ([]string, error) {
return nil, nil
panic("should be removed")
}
func (s *Service) SetIsHighlighted(req *pb.RpcWorkspaceSetIsHighlightedRequest) error {
panic("is not implemented")
// workspaceId, _ := s.anytype.GetWorkspaceIdForObject(req.ObjectId)
// return Do(s,ctx, workspaceId, func(b smartblock.SmartBlock) error {
// workspace, ok := b.(*editor.Workspaces)
// if !ok {
// return fmt.Errorf("incorrect object with workspace id")
// }
// return workspace.SetIsHighlighted(req.ObjectId, req.IsHighlighted)
// })
panic("should be removed")
}
func (s *Service) ObjectShareByLink(req *pb.RpcObjectShareByLinkRequest) (link string, err error) {
return "", fmt.Errorf("not implemented")
// workspaceId, err := s.anytype.GetWorkspaceIdForObject(req.ObjectId)
// if err == core.ErrObjectDoesNotBelongToWorkspace {
// workspaceId = s.Anytype().AccountObjects().Account
// }
// var key string
// var addrs []string
// err = Do(s,ctx, workspaceId, func(b smartblock.SmartBlock) error {
// workspace, ok := b.(*editor.Workspaces)
// if !ok {
// return fmt.Errorf("incorrect object with workspace id")
// }
// key, addrs, err = workspace.GetObjectKeyAddrs(req.ObjectId)
// return err
// })
// if err != nil {
// return "", err
// }
// payload := &model.ThreadDeeplinkPayload{
// Key: key,
// Addrs: addrs,
// }
// marshalledPayload, err := proto.Marshal(payload)
// if err != nil {
// return "", fmt.Errorf("failed to marshal deeplink payload: %w", err)
// }
// encodedPayload := base64.RawStdEncoding.EncodeToString(marshalledPayload)
//
// params := url.Values{}
// params.Add("id", req.ObjectId)
// params.Add("payload", encodedPayload)
// encoded := params.Encode()
//
// return fmt.Sprintf("%s%s", linkObjectShare, encoded), nil
panic("should be removed")
}
func (s *Service) SetPagesIsArchived(ctx session.Context, req pb.RpcObjectListSetIsArchivedRequest) error {
@ -743,7 +708,7 @@ func (s *Service) setIsArchivedForObjects(spaceID string, objectIDs []string, is
func (s *Service) partitionObjectIDsBySpaceID(objectIDs []string) (map[string][]string, error) {
res := map[string][]string{}
for _, objectID := range objectIDs {
spaceID, err := s.spaceService.ResolveSpaceID(objectID)
spaceID, err := s.resolver.ResolveSpaceID(objectID)
if err != nil {
return nil, fmt.Errorf("resolve spaceID: %w", err)
}
@ -797,7 +762,7 @@ func (s *Service) objectLinksCollectionModify(collectionId string, objectId stri
}
func (s *Service) SetPageIsFavorite(req pb.RpcObjectSetIsFavoriteRequest) (err error) {
spaceID, err := s.ResolveSpaceID(req.ContextId)
spaceID, err := s.resolver.ResolveSpaceID(req.ContextId)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -805,7 +770,7 @@ func (s *Service) SetPageIsFavorite(req pb.RpcObjectSetIsFavoriteRequest) (err e
}
func (s *Service) SetPageIsArchived(req pb.RpcObjectSetIsArchivedRequest) (err error) {
spaceID, err := s.ResolveSpaceID(req.ContextId)
spaceID, err := s.resolver.ResolveSpaceID(req.ContextId)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -895,7 +860,7 @@ func (s *Service) ObjectsDuplicate(ctx context.Context, ids []string) (newIds []
}
func (s *Service) DeleteArchivedObject(id string) (err error) {
spaceID, err := s.spaceService.ResolveSpaceID(id)
spaceID, err := s.resolver.ResolveSpaceID(id)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -987,10 +952,6 @@ func (s *Service) Close(ctx context.Context) (err error) {
return nil
}
func (s *Service) ResolveSpaceID(objectID string) (spaceID string, err error) {
return s.spaceService.ResolveSpaceID(objectID)
}
func (s *Service) StateFromTemplate(templateID, name string) (st *state.State, err error) {
if templateID == BlankTemplateID || templateID == "" {
return s.BlankTemplateState(), nil
@ -1009,7 +970,7 @@ func (s *Service) StateFromTemplate(templateID, name string) (st *state.State, e
}
func (s *Service) DoFileNonLock(id string, apply func(b file.File) error) error {
sb, err := s.PickBlock(context.Background(), id)
sb, err := s.GetObject(context.Background(), id)
if err != nil {
return err
}
@ -1057,7 +1018,7 @@ func (s *Service) ResetToState(pageID string, st *state.State) (err error) {
}
func (s *Service) ObjectBookmarkFetch(req pb.RpcObjectBookmarkFetchRequest) (err error) {
spaceID, err := s.spaceService.ResolveSpaceID(req.ContextId)
spaceID, err := s.resolver.ResolveSpaceID(req.ContextId)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -1075,7 +1036,7 @@ func (s *Service) ObjectBookmarkFetch(req pb.RpcObjectBookmarkFetchRequest) (err
}
func (s *Service) ObjectToBookmark(ctx context.Context, id string, url string) (objectId string, err error) {
spaceID, err := s.spaceService.ResolveSpaceID(id)
spaceID, err := s.resolver.ResolveSpaceID(id)
if err != nil {
return "", fmt.Errorf("resolve spaceID: %w", err)
}

View file

@ -11,6 +11,7 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block/editor/state"
@ -22,8 +23,9 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/addr"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
)
const CName = "source"
@ -32,6 +34,11 @@ func New() Service {
return &service{}
}
type idResolver interface {
BindSpaceID(spaceID string, objectID string) error
ResolveSpaceID(objectID string) (spaceID string, err error)
}
type Service interface {
NewSource(ctx context.Context, id string, spaceID string, buildOptions BuildOptions) (source Source, err error)
RegisterStaticSource(s Source) error
@ -48,7 +55,8 @@ type service struct {
sbtProvider typeprovider.SmartBlockTypeProvider
account accountservice.Service
fileStore filestore.FileStore
spaceService space.Service
spaceService spacecore.SpaceCoreService
storageService storage.ClientStorage
fileService files.Service
systemObjectService system_object.Service
@ -64,7 +72,8 @@ func (s *service) Init(a *app.App) (err error) {
s.sbtProvider = a.MustComponent(typeprovider.CName).(typeprovider.SmartBlockTypeProvider)
s.account = a.MustComponent(accountservice.CName).(accountservice.Service)
s.fileStore = app.MustComponent[filestore.FileStore](a)
s.spaceService = app.MustComponent[space.Service](a)
s.spaceService = app.MustComponent[spacecore.SpaceCoreService](a)
s.storageService = a.MustComponent(spacestorage.CName).(storage.ClientStorage)
s.systemObjectService = app.MustComponent[system_object.Service](a)
s.fileService = app.MustComponent[files.Service](a)
@ -92,7 +101,7 @@ func (s *service) NewSource(ctx context.Context, id string, spaceID string, buil
if err != nil {
return nil, err
}
err = s.spaceService.StoreSpaceID(src.Id(), src.SpaceID())
err = s.storageService.BindSpaceID(src.SpaceID(), src.Id())
if err != nil {
return nil, fmt.Errorf("store space id for object: %w", err)
}
@ -125,7 +134,7 @@ func (s *service) newSource(ctx context.Context, id string, spaceID string, buil
return staticSrc, nil
}
spc, err := s.spaceService.GetSpace(ctx, spaceID)
spc, err := s.spaceService.Get(ctx, spaceID)
if err != nil {
return nil, fmt.Errorf("get space: %w", err)
}
@ -197,7 +206,7 @@ func (s *service) RegisterStaticSource(src Source) error {
s.mu.Lock()
defer s.mu.Unlock()
s.staticIds[src.Id()] = src
err := s.spaceService.StoreSpaceID(src.Id(), src.SpaceID())
err := s.storageService.BindSpaceID(src.SpaceID(), src.Id())
if err != nil {
return fmt.Errorf("store space id for object: %w", err)
}

View file

@ -25,8 +25,8 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -83,7 +83,7 @@ type sourceDeps struct {
coreService core.Service
accountService accountservice.Service
spaceService space.Service
spaceService spacecore.SpaceCoreService
sbtProvider typeprovider.SmartBlockTypeProvider
fileService files.Service
systemObjectService system_object.Service
@ -125,7 +125,7 @@ type source struct {
coreService core.Service
fileService files.Service
accountService accountservice.Service
spaceService space.Service
spaceService spacecore.SpaceCoreService
sbtProvider typeprovider.SmartBlockTypeProvider
systemObjectService system_object.Service
}
@ -313,7 +313,7 @@ func checkChangeSize(data []byte, maxSize int) error {
}
func (s *source) ListIds() (ids []string, err error) {
spc, err := s.spaceService.GetSpace(context.Background(), s.spaceID)
spc, err := s.spaceService.Get(context.Background(), s.spaceID)
if err != nil {
return
}

View file

@ -18,7 +18,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/spacecore"
)
var log = logging.Logger("anytype-mw-configfetcher")
@ -47,6 +47,10 @@ type ConfigFetcher interface {
Refetch()
}
type personalSpaceIDGetter interface {
PersonalSpaceID() string
}
type configFetcher struct {
store objectstore.ObjectStore
eventSender event.Sender
@ -55,7 +59,8 @@ type configFetcher struct {
periodicSync periodicsync.PeriodicSync
client coordinatorclient.CoordinatorClient
spaceService space.Service
spaceService spacecore.SpaceCoreService
account personalSpaceIDGetter
wallet wallet.Wallet
lastStatus model.AccountStatusType
}
@ -91,7 +96,8 @@ func (c *configFetcher) Init(a *app.App) (err error) {
c.eventSender = a.MustComponent(event.CName).(event.Sender)
c.periodicSync = periodicsync.NewPeriodicSync(refreshIntervalSecs, timeout, c.updateStatus, logger.CtxLogger{Logger: log.Desugar()})
c.client = a.MustComponent(coordinatorclient.CName).(coordinatorclient.CoordinatorClient)
c.spaceService = a.MustComponent(space.CName).(space.Service)
c.spaceService = a.MustComponent(spacecore.CName).(spacecore.SpaceCoreService)
c.account = app.MustComponent[personalSpaceIDGetter](a)
c.fetched = make(chan struct{})
return nil
}
@ -106,9 +112,10 @@ func (c *configFetcher) updateStatus(ctx context.Context) (err error) {
close(c.fetched)
})
}()
res, err := c.client.StatusCheck(ctx, c.spaceService.AccountId())
personalSpaceID := c.account.PersonalSpaceID()
res, err := c.client.StatusCheck(ctx, personalSpaceID)
if err == coordinatorproto.ErrSpaceNotExists {
sp, cErr := c.spaceService.GetSpace(ctx, c.spaceService.AccountId())
sp, cErr := c.spaceService.Get(ctx, personalSpaceID)
if cErr != nil {
return cErr
}

View file

@ -19,7 +19,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

View file

@ -10,7 +10,7 @@ import (
"github.com/anyproto/anytype-heart/core/converter"
"github.com/anyproto/anytype-heart/core/system_object"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
)
func NewMultiConverter(format int, _ typeprovider.SmartBlockTypeProvider, _ system_object.Service) converter.MultiConverter {

View file

@ -13,7 +13,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

View file

@ -17,7 +17,6 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/space"
utildebug "github.com/anyproto/anytype-heart/util/debug"
)
@ -64,13 +63,6 @@ func (mw *Middleware) getBlockService() (bs *block.Service, err error) {
return nil, ErrNotLoggedIn
}
func (mw *Middleware) getAccountService() (a space.Service, err error) {
if a := mw.applicationService.GetApp(); a != nil {
return a.MustComponent(space.CName).(space.Service), nil
}
return nil, ErrNotLoggedIn
}
func (mw *Middleware) doBlockService(f func(bs *block.Service) error) (err error) {
bs, err := mw.getBlockService()
if err != nil {
@ -99,14 +91,6 @@ func requireApp(a *app.App) {
}
}
func (mw *Middleware) doAccountService(f func(a space.Service) error) (err error) {
bs, err := mw.getAccountService()
if err != nil {
return
}
return f(bs)
}
func (mw *Middleware) GetAnytype() core.Service {
if a := mw.applicationService.GetApp(); a != nil {
return a.MustComponent("anytype").(core.Service)

View file

@ -59,7 +59,7 @@ func (mw *Middleware) DebugTreeHeads(cctx context.Context, req *pb.RpcDebugTreeH
}
dbg := app.MustComponent(debug.CName).(debug.Debug)
treeInfo, err := dbg.TreeHeads(req.TreeId)
treeInfo, err := dbg.TreeHeads(cctx, req.TreeId)
if err != nil {
return response(err, debug.TreeInfo{})
}
@ -94,7 +94,7 @@ func (mw *Middleware) DebugSpaceSummary(cctx context.Context, req *pb.RpcDebugSp
return response(ErrNotLoggedIn, debug.SpaceSummary{})
}
dbg := app.MustComponent(debug.CName).(debug.Debug)
spaceSummary, err := dbg.SpaceSummary()
spaceSummary, err := dbg.SpaceSummary(cctx, req.SpaceId)
if err != nil {
return response(err, debug.SpaceSummary{})
}
@ -141,7 +141,7 @@ func (mw *Middleware) DebugExportLocalstore(cctx context.Context, req *pb.RpcDeb
)
err = mw.doBlockService(func(s *block.Service) error {
dbg := mw.applicationService.GetApp().MustComponent(debug.CName).(debug.Debug)
path, err = dbg.DumpLocalstore(req.SpaceId, req.DocIds, req.Path)
path, err = dbg.DumpLocalstore(cctx, req.SpaceId, req.DocIds, req.Path)
return err
})
return response(path, err)

View file

@ -19,6 +19,7 @@ import (
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
@ -36,16 +37,16 @@ func New() Debug {
type Debug interface {
app.Component
DumpTree(ctx context.Context, objectID string, path string, anonymize bool, withSvg bool) (filename string, err error)
DumpLocalstore(spaceID string, objectIds []string, path string) (filename string, err error)
SpaceSummary() (summary SpaceSummary, err error)
TreeHeads(id string) (info TreeInfo, err error)
DumpLocalstore(ctx context.Context, spaceID string, objectIds []string, path string) (filename string, err error)
SpaceSummary(ctx context.Context, spaceID string) (summary SpaceSummary, err error)
TreeHeads(ctx context.Context, id string) (info TreeInfo, err error)
}
type debug struct {
block *block.Service
store objectstore.ObjectStore
clientService space.Service
spaceService space.Service
block *block.Service
store objectstore.ObjectStore
spaceService space.SpaceService
resolver idresolver.Resolver
server *http.Server
}
@ -56,9 +57,9 @@ type Debuggable interface {
func (d *debug) Init(a *app.App) (err error) {
d.store = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
d.clientService = a.MustComponent(space.CName).(space.Service)
d.block = a.MustComponent(block.CName).(*block.Service)
d.spaceService = app.MustComponent[space.Service](a)
d.spaceService = app.MustComponent[space.SpaceService](a)
d.resolver = app.MustComponent[idresolver.Resolver](a)
d.initHandlers(a)
return nil
@ -123,12 +124,12 @@ type SpaceSummary struct {
TreeInfos []TreeInfo
}
func (d *debug) SpaceSummary() (summary SpaceSummary, err error) {
spc, err := d.clientService.AccountSpace(context.Background())
func (d *debug) SpaceSummary(ctx context.Context, spaceID string) (summary SpaceSummary, err error) {
spc, err := d.spaceService.Get(ctx, spaceID)
if err != nil {
return
}
summary.SpaceId = spc.Id()
summary.SpaceId = spaceID
for _, t := range spc.DebugAllHeads() {
summary.TreeInfos = append(summary.TreeInfos, TreeInfo{
Heads: t.Heads,
@ -138,42 +139,45 @@ func (d *debug) SpaceSummary() (summary SpaceSummary, err error) {
return
}
func (d *debug) TreeHeads(id string) (info TreeInfo, err error) {
spc, err := d.clientService.AccountSpace(context.Background())
func (d *debug) TreeHeads(ctx context.Context, id string) (info TreeInfo, err error) {
spcID, err := d.resolver.ResolveSpaceID(id)
if err != nil {
return
}
tree, err := spc.TreeBuilder().BuildHistoryTree(context.Background(), id, objecttreebuilder.HistoryTreeOpts{})
spc, err := d.spaceService.Get(ctx, spcID)
if err != nil {
return
}
tree, err := spc.TreeBuilder().BuildHistoryTree(ctx, id, objecttreebuilder.HistoryTreeOpts{})
if err != nil {
return
}
info = TreeInfo{
Id: id,
Heads: tree.Heads(),
SpaceId: spc.Id(),
SpaceId: spcID,
}
return
}
func (d *debug) DumpTree(ctx context.Context, objectID string, path string, anonymize bool, withSvg bool) (filename string, err error) {
// 0 - get space and tree
spc, err := d.clientService.AccountSpace(context.Background())
// 0 - get space
spcID, err := d.resolver.ResolveSpaceID(objectID)
if err != nil {
return
}
tree, err := spc.TreeBuilder().BuildHistoryTree(context.Background(), objectID, objecttreebuilder.HistoryTreeOpts{BuildFullTree: true})
spc, err := d.spaceService.Get(ctx, spcID)
if err != nil {
return
}
tree, err := spc.TreeBuilder().BuildHistoryTree(ctx, objectID, objecttreebuilder.HistoryTreeOpts{BuildFullTree: true})
if err != nil {
return
}
// 1 - create ZIP file
// <path>/at.dbg.bafkudtugh626rrqzah3kam4yj4lqbaw4bjayn2rz4ah4n5fpayppbvmq.20220322.121049.23.zip
spaceID, err := d.spaceService.ResolveSpaceID(objectID)
if err != nil {
return "", fmt.Errorf("resolve spaceID: %w", err)
}
exporter := &treeExporter{s: d.store, anonymized: anonymize, id: domain.FullID{
SpaceID: spaceID,
SpaceID: spcID,
ObjectID: objectID,
}}
zipFilename, err := exporter.Export(ctx, path, tree)
@ -208,7 +212,7 @@ func (d *debug) DumpTree(ctx context.Context, objectID string, path string, anon
return zipFilename, nil
}
func (d *debug) DumpLocalstore(spaceID string, objIds []string, path string) (filename string, err error) {
func (d *debug) DumpLocalstore(ctx context.Context, spaceID string, objIds []string, path string) (filename string, err error) {
if len(objIds) == 0 {
objIds, err = d.store.ListIds()
if err != nil {

View file

@ -19,6 +19,7 @@ var smartBlockTypeToKey = map[smartblock.SmartBlockType]string{
smartblock.SmartBlockTypeArchive: "archive",
smartblock.SmartBlockTypeProfilePage: "profile",
smartblock.SmartBlockTypeWidget: "widget",
smartblock.SmartBlockTypeSpaceView: "spaceview",
}
// UniqueKey is unique key composed of two parts: smartblock type and internal key.

View file

@ -1,77 +0,0 @@
package files
import (
"context"
"sync"
"github.com/ipfs/go-cid"
ipld "github.com/ipfs/go-ipld-format"
)
// Test dag. Copied from github.com/ipfs/go-ipld-format tests
type testDag struct {
mu sync.Mutex
nodes map[string]ipld.Node
}
func newTestDag() *testDag {
return &testDag{nodes: make(map[string]ipld.Node)}
}
func (d *testDag) Get(ctx context.Context, cid cid.Cid) (ipld.Node, error) {
d.mu.Lock()
defer d.mu.Unlock()
if n, ok := d.nodes[cid.KeyString()]; ok {
return n, nil
}
return nil, ipld.ErrNotFound{Cid: cid}
}
func (d *testDag) GetMany(ctx context.Context, cids []cid.Cid) <-chan *ipld.NodeOption {
d.mu.Lock()
defer d.mu.Unlock()
out := make(chan *ipld.NodeOption, len(cids))
for _, c := range cids {
if n, ok := d.nodes[c.KeyString()]; ok {
out <- &ipld.NodeOption{Node: n}
} else {
out <- &ipld.NodeOption{Err: ipld.ErrNotFound{c}}
}
}
close(out)
return out
}
func (d *testDag) Add(ctx context.Context, node ipld.Node) error {
d.mu.Lock()
defer d.mu.Unlock()
d.nodes[node.Cid().KeyString()] = node
return nil
}
func (d *testDag) AddMany(ctx context.Context, nodes []ipld.Node) error {
d.mu.Lock()
defer d.mu.Unlock()
for _, n := range nodes {
d.nodes[n.Cid().KeyString()] = n
}
return nil
}
func (d *testDag) Remove(ctx context.Context, c cid.Cid) error {
d.mu.Lock()
defer d.mu.Unlock()
delete(d.nodes, c.KeyString())
return nil
}
func (d *testDag) RemoveMany(ctx context.Context, cids []cid.Cid) error {
d.mu.Lock()
defer d.mu.Unlock()
for _, c := range cids {
delete(d.nodes, c.KeyString())
}
return nil
}
var _ ipld.DAGService = new(testDag)

View file

@ -23,6 +23,7 @@ import (
"github.com/multiformats/go-base32"
mh "github.com/multiformats/go-multihash"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/filestorage"
"github.com/anyproto/anytype-heart/core/filestorage/filesync"
@ -40,7 +41,6 @@ import (
m "github.com/anyproto/anytype-heart/pkg/lib/mill"
"github.com/anyproto/anytype-heart/pkg/lib/mill/schema"
"github.com/anyproto/anytype-heart/pkg/lib/pb/storage"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
@ -75,7 +75,7 @@ type service struct {
commonFile fileservice.FileService
fileSync filesync.FileSync
dagService ipld.DAGService
spaceService space.Service
resolver idresolver.Resolver
fileStorage filestorage.FileStorage
syncStatusWatcher SyncStatusWatcher
objectStore objectstore.ObjectStore
@ -90,11 +90,11 @@ func (s *service) Init(a *app.App) (err error) {
s.fileStore = app.MustComponent[filestore.FileStore](a)
s.commonFile = app.MustComponent[fileservice.FileService](a)
s.fileSync = app.MustComponent[filesync.FileSync](a)
s.spaceService = app.MustComponent[space.Service](a)
s.coreService = app.MustComponent[core.Service](a)
s.dagService = s.commonFile.DAGService()
s.fileStorage = app.MustComponent[filestorage.FileStorage](a)
s.resolver = app.MustComponent[idresolver.Resolver](a)
s.objectStore = app.MustComponent[objectstore.ObjectStore](a)
s.syncStatusWatcher = app.MustComponent[SyncStatusWatcher](a)
return nil

View file

@ -20,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/datastore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/tests/testutil"
)
@ -29,13 +28,27 @@ type dummySyncStatusWatcher struct{}
func (w *dummySyncStatusWatcher) Watch(spaceID string, id string, fileFunc func() []string) (new bool, err error) {
return false, nil
}
func (w *dummySyncStatusWatcher) Init(a *app.App) error { return nil }
func (w *dummySyncStatusWatcher) Name() string { return "dummySyncStatusWatcher" }
func (w *dummySyncStatusWatcher) Init(a *app.App) error {
return nil
type personalSpaceIdStub struct {
personalSpaceId string
}
func (w *dummySyncStatusWatcher) Name() string {
return "dummySyncStatusWatcher"
func (s *personalSpaceIdStub) Name() string { return "personalSpaceIdStub" }
func (s *personalSpaceIdStub) Init(a *app.App) error { return nil }
func (s *personalSpaceIdStub) PersonalSpaceID() string {
return s.personalSpaceId
}
type spaceResolverStub struct {
spaceId string
}
func (s *spaceResolverStub) Name() string { return "spaceResolverStub" }
func (s *spaceResolverStub) Init(a *app.App) error { return nil }
func (s *spaceResolverStub) ResolveSpaceID(objectID string) (string, error) {
return s.spaceId, nil
}
func TestFileAdd(t *testing.T) {
@ -50,8 +63,8 @@ func TestFileAdd(t *testing.T) {
fileSyncService := filesync.New()
spaceId := "space1"
spaceService := mock_space.NewMockService(t)
spaceService.EXPECT().AccountId().Return(spaceId).Maybe()
personalSpaceIdGetter := &personalSpaceIdStub{personalSpaceId: spaceId}
spaceIdResolver := &spaceResolverStub{spaceId: spaceId}
coreService := mock_core.NewMockService(t)
objectStore := objectstore.NewStoreFixture(t)
@ -64,11 +77,12 @@ func TestFileAdd(t *testing.T) {
a.Register(filestore.New())
a.Register(commonFileService)
a.Register(fileSyncService)
a.Register(testutil.PrepareRunnableMock(ctx, a, spaceService))
a.Register(testutil.PrepareRunnableMock(ctx, a, coreService))
a.Register(testutil.PrepareMock(a, eventSender))
a.Register(testutil.PrepareMock(ctx, a, coreService))
a.Register(testutil.PrepareMock(ctx, a, eventSender))
a.Register(blockStorage)
a.Register(objectStore)
a.Register(personalSpaceIdGetter)
a.Register(spaceIdResolver)
a.Register(&dummySyncStatusWatcher{})
a.Register(rpcStorage)
err := a.Start(ctx)

View file

@ -14,7 +14,7 @@ import (
)
func (s *service) FileOffload(ctx context.Context, fileID string, includeNotPinned bool) (totalSize uint64, err error) {
spaceID, err := s.spaceService.ResolveSpaceID(fileID)
spaceID, err := s.resolver.ResolveSpaceID(fileID)
if err != nil {
return 0, fmt.Errorf("resolve spaceID for file %s: %w", fileID, err)
}
@ -95,7 +95,7 @@ func (s *service) FileListOffload(ctx context.Context, fileIDs []string, include
}
for _, fileID := range fileIDs {
spaceID, err := s.spaceService.ResolveSpaceID(fileID)
spaceID, err := s.resolver.ResolveSpaceID(fileID)
if err != nil {
return 0, 0, fmt.Errorf("resolve spaceID for file %s: %w", fileID, err)
}

View file

@ -23,7 +23,7 @@ import (
"github.com/anyproto/anytype-heart/core/filestorage/rpcstore"
"github.com/anyproto/anytype-heart/core/wallet"
"github.com/anyproto/anytype-heart/pkg/lib/datastore"
"github.com/anyproto/anytype-heart/space/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
)
const CName = fileblockstore.CName

View file

@ -13,11 +13,10 @@ import (
reflect "reflect"
app "github.com/anyproto/any-sync/app"
gomock "go.uber.org/mock/gomock"
localstore "github.com/anyproto/anytype-heart/pkg/lib/localstore"
filestore "github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
storage "github.com/anyproto/anytype-heart/pkg/lib/pb/storage"
gomock "go.uber.org/mock/gomock"
)
// MockFileStore is a mock of FileStore interface.

View file

@ -20,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/datastore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/space"
)
const CName = "filesync"
@ -54,23 +53,27 @@ type QueueInfo struct {
RemovingQueue []*QueueItem
}
type personalSpaceIDGetter interface {
PersonalSpaceID() string
}
type SyncStatus struct {
QueueLen int
}
type fileSync struct {
dbProvider datastore.Datastore
rpcStore rpcstore.RpcStore
queue *fileSyncStore
loopCtx context.Context
loopCancel context.CancelFunc
uploadPingCh chan struct{}
removePingCh chan struct{}
dagService ipld.DAGService
fileStore filestore.FileStore
eventSender event.Sender
onUpload func(spaceID, fileID string) error
spaceService space.Service
dbProvider datastore.Datastore
rpcStore rpcstore.RpcStore
queue *fileSyncStore
loopCtx context.Context
loopCancel context.CancelFunc
uploadPingCh chan struct{}
removePingCh chan struct{}
dagService ipld.DAGService
fileStore filestore.FileStore
eventSender event.Sender
onUpload func(spaceID, fileID string) error
personalIDGetter personalSpaceIDGetter
spaceStatsLock sync.Mutex
spaceStats map[string]SpaceStat
@ -89,7 +92,7 @@ func (f *fileSync) Init(a *app.App) (err error) {
f.rpcStore = a.MustComponent(rpcstore.CName).(rpcstore.Service).NewStore()
f.dagService = a.MustComponent(fileservice.CName).(fileservice.FileService).DAGService()
f.fileStore = app.MustComponent[filestore.FileStore](a)
f.spaceService = app.MustComponent[space.Service](a)
f.personalIDGetter = app.MustComponent[personalSpaceIDGetter](a)
f.eventSender = app.MustComponent[event.Sender](a)
f.removePingCh = make(chan struct{})
f.uploadPingCh = make(chan struct{})
@ -128,7 +131,8 @@ func (f *fileSync) Run(ctx context.Context) (err error) {
func (f *fileSync) precacheSpaceStats() {
// TODO multi-spaces: init for each space: GO-1681
spaceID := f.spaceService.AccountId()
// TODO: [MR] adapt to multi-spaces
spaceID := f.personalIDGetter.PersonalSpaceID()
_, err := f.SpaceStat(context.Background(), spaceID)
if err != nil {
// Don't confuse users with 0B limit in case of error, so set default 1GB limit
@ -136,7 +140,7 @@ func (f *fileSync) precacheSpaceStats() {
SpaceId: spaceID,
BytesLimit: 1024 * 1024 * 1024, // 1 GB
})
log.Error("can't init space stats", zap.String("spaceID", f.spaceService.AccountId()), zap.Error(err))
log.Error("can't init space stats", zap.String("spaceID", f.personalIDGetter.PersonalSpaceID()), zap.Error(err))
}
}

View file

@ -15,7 +15,6 @@ import (
"github.com/anyproto/any-sync/commonfile/fileproto"
"github.com/anyproto/any-sync/commonfile/fileservice"
"github.com/anyproto/any-sync/commonspace/syncstatus"
"github.com/dgraph-io/badger/v3"
"github.com/ipfs/go-cid"
"github.com/samber/lo"
"github.com/stretchr/testify/mock"
@ -29,8 +28,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/datastore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/storage"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/tests/testutil"
)
var ctx = context.Background()
@ -81,6 +78,16 @@ func TestFileSync_RemoveFile(t *testing.T) {
fx.waitEmptyQueue(t, time.Second*5)
}
type personalSpaceIdStub struct {
personalSpaceId string
}
func (s *personalSpaceIdStub) Name() string { return "personalSpaceIdStub" }
func (s *personalSpaceIdStub) Init(a *app.App) error { return nil }
func (s *personalSpaceIdStub) PersonalSpaceID() string {
return s.personalSpaceId
}
func newFixture(t *testing.T) *fixture {
fx := &fixture{
FileSync: New(),
@ -88,12 +95,6 @@ func newFixture(t *testing.T) *fixture {
ctrl: gomock.NewController(t),
a: new(app.App),
}
var err error
bp := &badgerProvider{}
fx.tmpDir, err = os.MkdirTemp("", "*")
require.NoError(t, err)
bp.db, err = badger.Open(badger.DefaultOptions(fx.tmpDir))
require.NoError(t, err)
fx.rpcStore = mock_rpcstore.NewMockRpcStore(fx.ctrl)
fx.rpcStore.EXPECT().SpaceInfo(gomock.Any(), "space1").Return(&fileproto.SpaceInfoResponse{LimitBytes: 2 * 1024 * 1024}, nil).AnyTimes()
@ -110,20 +111,21 @@ func newFixture(t *testing.T) *fixture {
fileStoreMock.EXPECT().Close(gomock.Any()).AnyTimes()
fx.fileStoreMock = fileStoreMock
spaceService := mock_space.NewMockService(t)
spaceService.EXPECT().AccountId().Return("space1").Maybe()
personalSpaceIdGetter := &personalSpaceIdStub{personalSpaceId: "space1"}
sender := mock_event.NewMockSender(t)
sender.EXPECT().Name().Return("event")
sender.EXPECT().Init(mock.Anything).Return(nil)
sender.EXPECT().Broadcast(mock.Anything).Return().Maybe()
fx.a.Register(fx.fileService).
Register(filestorage.NewInMemory()).
Register(bp).
Register(datastore.NewInMemory()).
Register(mockRpcStoreService).
Register(fx.FileSync).
Register(fileStoreMock).
Register(testutil.PrepareRunnableMock(ctx, fx.a, spaceService)).
Register(testutil.PrepareMock(fx.a, sender))
Register(personalSpaceIdGetter).
Register(sender)
require.NoError(t, fx.a.Start(ctx))
return fx
}
@ -155,31 +157,3 @@ func (f *fixture) Finish(t *testing.T) {
defer os.RemoveAll(f.tmpDir)
require.NoError(t, f.a.Close(ctx))
}
type badgerProvider struct {
db *badger.DB
}
func (b *badgerProvider) Init(a *app.App) (err error) {
return nil
}
func (b *badgerProvider) Name() (name string) {
return datastore.CName
}
func (b *badgerProvider) Run(ctx context.Context) (err error) {
return nil
}
func (b *badgerProvider) Close(ctx context.Context) (err error) {
return b.db.Close()
}
func (b *badgerProvider) LocalStorage() (*badger.DB, error) {
return b.db, nil
}
func (b *badgerProvider) SpaceStorage() (*badger.DB, error) {
return b.db, nil
}

View file

@ -8,7 +8,7 @@ import (
"github.com/anyproto/any-sync/commonfile/fileproto/fileprotoerr"
"github.com/ipfs/go-cid"
"github.com/anyproto/anytype-heart/space/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
)
type rpcHandler struct {

View file

@ -14,11 +14,10 @@ import (
app "github.com/anyproto/any-sync/app"
fileproto "github.com/anyproto/any-sync/commonfile/fileproto"
rpcstore "github.com/anyproto/anytype-heart/core/filestorage/rpcstore"
blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
gomock "go.uber.org/mock/gomock"
rpcstore "github.com/anyproto/anytype-heart/core/filestorage/rpcstore"
)
// MockService is a mock of Service interface.

View file

@ -9,7 +9,7 @@ import (
"github.com/anyproto/any-sync/net/pool"
"github.com/anyproto/any-sync/nodeconf"
"github.com/anyproto/anytype-heart/space/peerstore"
"github.com/anyproto/anytype-heart/space/spacecore/peerstore"
)
const CName = "common.commonfile.rpcstore"

View file

@ -22,7 +22,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/anyproto/anytype-heart/space/peerstore"
"github.com/anyproto/anytype-heart/space/spacecore/peerstore"
)
var ctx = context.Background()

View file

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/history"
"github.com/anyproto/anytype-heart/pb"
@ -36,7 +37,8 @@ func (mw *Middleware) HistoryShowVersion(cctx context.Context, req *pb.RpcHistor
)
if err = mw.doBlockService(func(bs *block.Service) (err error) {
hs := mw.applicationService.GetApp().MustComponent(history.CName).(history.History)
spaceID, err := bs.ResolveSpaceID(req.ObjectId)
res := mw.applicationService.GetApp().MustComponent(idresolver.CName).(idresolver.Resolver)
spaceID, err := res.ResolveSpaceID(req.ObjectId)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -74,7 +76,8 @@ func (mw *Middleware) HistoryGetVersions(cctx context.Context, req *pb.RpcHistor
)
if err = mw.doBlockService(func(bs *block.Service) (err error) {
hs := mw.applicationService.GetApp().MustComponent(history.CName).(history.History)
spaceID, err := bs.ResolveSpaceID(req.ObjectId)
res := mw.applicationService.GetApp().MustComponent(idresolver.CName).(idresolver.Resolver)
spaceID, err := res.ResolveSpaceID(req.ObjectId)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}
@ -105,7 +108,8 @@ func (mw *Middleware) HistorySetVersion(cctx context.Context, req *pb.RpcHistory
}
return response(mw.doBlockService(func(bs *block.Service) (err error) {
hs := mw.applicationService.GetApp().MustComponent(history.CName).(history.History)
spaceID, err := bs.ResolveSpaceID(req.ObjectId)
res := mw.applicationService.GetApp().MustComponent(idresolver.CName).(idresolver.Resolver)
spaceID, err := res.ResolveSpaceID(req.ObjectId)
if err != nil {
return fmt.Errorf("resolve spaceID: %w", err)
}

View file

@ -25,7 +25,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -49,18 +49,18 @@ type History interface {
type history struct {
a core.Service
picker block.Picker
picker block.ObjectGetter
objectStore objectstore.ObjectStore
systemObjectService system_object.Service
spaceService space.Service
spaceService spacecore.SpaceCoreService
}
func (h *history) Init(a *app.App) (err error) {
h.a = a.MustComponent(core.CName).(core.Service)
h.picker = app.MustComponent[block.Picker](a)
h.picker = app.MustComponent[block.ObjectGetter](a)
h.objectStore = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
h.systemObjectService = a.MustComponent(system_object.CName).(system_object.Service)
h.spaceService = a.MustComponent(space.CName).(space.Service)
h.spaceService = a.MustComponent(spacecore.CName).(spacecore.SpaceCoreService)
return
}
@ -192,7 +192,7 @@ func (h *history) SetVersion(id domain.FullID, versionId string) (err error) {
}
func (h *history) treeWithId(id domain.FullID, beforeId string, includeBeforeId bool) (ht objecttree.HistoryTree, sbt smartblock.SmartBlockType, err error) {
spc, err := h.spaceService.GetSpace(context.Background(), id.SpaceID)
spc, err := h.spaceService.Get(context.Background(), id.SpaceID)
if err != nil {
return
}

View file

@ -75,7 +75,6 @@ func (i *indexer) runFullTextIndexer() {
func (i *indexer) prepareSearchDocument(id string) (ftDoc ftsearch.SearchDoc, err error) {
// ctx := context.WithValue(context.Background(), ocache.CacheTimeout, cacheTimeout)
ctx := context.WithValue(context.Background(), metrics.CtxKeyEntrypoint, "index_fulltext")
err = block.DoContext(i.picker, ctx, id, func(sb smartblock2.SmartBlock) error {
sbType, err := i.typeProvider.Type(sb.SpaceID(), id)
if err != nil {

View file

@ -10,25 +10,26 @@ import (
"time"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/gogo/protobuf/types"
"go.uber.org/zap"
"golang.org/x/exp/slices"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block"
smartblock2 "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
editorsb "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/source"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/files"
"github.com/anyproto/anytype-heart/metrics"
"github.com/anyproto/anytype-heart/pkg/lib/core"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/filestore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/ftsearch"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/space"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/slice"
)
@ -46,8 +47,10 @@ func New() Indexer {
type Indexer interface {
ForceFTIndex()
Index(ctx context.Context, info smartblock2.DocInfo, options ...smartblock2.IndexOption) error
EnsurePreinstalledObjects(spaceID string) error
StartFullTextIndex() error
ReindexCommonObjects() error
ReindexSpace(spaceID string) error
Index(ctx context.Context, info editorsb.DocInfo, options ...editorsb.IndexOption) error
app.ComponentRunnable
}
@ -64,20 +67,19 @@ type objectCreator interface {
) (ids []string, objects []*types.Struct, err error)
}
type syncStarter interface {
StartSync()
type personalIDProvider interface {
PersonalSpaceID() string
}
type indexer struct {
store objectstore.ObjectStore
fileStore filestore.FileStore
anytype core.Service
source source.Service
picker block.Picker
ftsearch ftsearch.FTSearch
objectCreator objectCreator
syncStarter syncStarter
fileService files.Service
store objectstore.ObjectStore
fileStore filestore.FileStore
source source.Service
picker block.ObjectGetter
ftsearch ftsearch.FTSearch
storageService storage.ClientStorage
objectCreator objectCreator
fileService files.Service
quit chan struct{}
btHash Hasher
@ -85,25 +87,28 @@ type indexer struct {
forceFt chan struct{}
typeProvider typeprovider.SmartBlockTypeProvider
spaceService space.Service
spaceCore spacecore.SpaceCoreService
provider personalIDProvider
indexedFiles *sync.Map
reindexLogFields []zap.Field
flags reindexFlags
}
func (i *indexer) Init(a *app.App) (err error) {
i.newAccount = a.MustComponent(config.CName).(*config.Config).NewAccount
i.anytype = a.MustComponent(core.CName).(core.Service)
i.store = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
i.storageService = a.MustComponent(spacestorage.CName).(storage.ClientStorage)
i.typeProvider = a.MustComponent(typeprovider.CName).(typeprovider.SmartBlockTypeProvider)
i.source = a.MustComponent(source.CName).(source.Service)
i.btHash = a.MustComponent("builtintemplate").(Hasher)
i.fileStore = app.MustComponent[filestore.FileStore](a)
i.ftsearch = app.MustComponent[ftsearch.FTSearch](a)
i.objectCreator = app.MustComponent[objectCreator](a)
i.syncStarter = app.MustComponent[syncStarter](a)
i.picker = app.MustComponent[block.Picker](a)
i.spaceService = app.MustComponent[space.Service](a)
i.picker = app.MustComponent[block.ObjectGetter](a)
i.spaceCore = app.MustComponent[spacecore.SpaceCoreService](a)
i.provider = app.MustComponent[personalIDProvider](a)
i.fileService = app.MustComponent[files.Service](a)
i.quit = make(chan struct{})
i.forceFt = make(chan struct{})
@ -115,13 +120,13 @@ func (i *indexer) Name() (name string) {
}
func (i *indexer) Run(context.Context) (err error) {
return i.StartFullTextIndex()
}
func (i *indexer) StartFullTextIndex() (err error) {
if ftErr := i.ftInit(); ftErr != nil {
log.Errorf("can't init ft: %v", ftErr)
}
err = i.reindexIfNeeded()
if err != nil {
return err
}
go i.ftLoop()
return
}
@ -131,18 +136,22 @@ func (i *indexer) Close(ctx context.Context) (err error) {
return nil
}
func (i *indexer) Index(ctx context.Context, info smartblock2.DocInfo, options ...smartblock2.IndexOption) error {
func (i *indexer) Index(ctx context.Context, info editorsb.DocInfo, options ...editorsb.IndexOption) error {
// options are stored in smartblock pkg because of cyclic dependency :(
startTime := time.Now()
opts := &smartblock2.IndexOptions{}
opts := &editorsb.IndexOptions{}
for _, o := range options {
o(opts)
}
err := i.storageService.BindSpaceID(info.SpaceID, info.Id)
if err != nil {
log.Error("failed to bind space id", zap.Error(err), zap.String("id", info.Id))
return err
}
sbType, err := i.typeProvider.Type(info.SpaceID, info.Id)
if err != nil {
sbType = smartblock.SmartBlockTypePage
}
headHashToIndex := headsHash(info.Heads)
saveIndexedHash := func() {
if headHashToIndex == "" {
@ -262,13 +271,13 @@ func (i *indexer) indexLinkedFiles(ctx context.Context, spaceID string, fileHash
if ok {
return
}
storeErr := i.spaceService.StoreSpaceID(id, spaceID)
if storeErr != nil {
log.With("id", id).Errorf("failed to store space id: %v", storeErr)
err := i.storageService.BindSpaceID(spaceID, id)
if err != nil {
log.Error("failed to bind space id", zap.Error(err), zap.String("id", id))
return
}
// file's hash is id
idxErr := i.reindexDoc(ctx, id)
idxErr := i.reindexDoc(ctx, spaceID, id)
if idxErr != nil && !errors.Is(idxErr, domain.ErrFileNotFound) {
log.With("id", id).Errorf("failed to reindex file: %s", idxErr)
}
@ -280,14 +289,6 @@ func (i *indexer) indexLinkedFiles(ctx context.Context, spaceID string, fileHash
}
}
func (i *indexer) getObjectInfo(ctx context.Context, id string) (info smartblock2.DocInfo, err error) {
err = block.DoContext(i.picker, ctx, id, func(sb smartblock2.SmartBlock) error {
info = sb.GetDocInfo()
return nil
})
return
}
func headsHash(heads []string) string {
if len(heads) == 0 {
return ""

View file

@ -0,0 +1,421 @@
// Code generated by mockery v2.26.1. DO NOT EDIT.
package mock_indexer
import (
context "context"
app "github.com/anyproto/any-sync/app"
mock "github.com/stretchr/testify/mock"
smartblock "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
)
// MockIndexer is an autogenerated mock type for the Indexer type
type MockIndexer struct {
mock.Mock
}
type MockIndexer_Expecter struct {
mock *mock.Mock
}
func (_m *MockIndexer) EXPECT() *MockIndexer_Expecter {
return &MockIndexer_Expecter{mock: &_m.Mock}
}
// Close provides a mock function with given fields: ctx
func (_m *MockIndexer) Close(ctx context.Context) error {
ret := _m.Called(ctx)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
type MockIndexer_Close_Call struct {
*mock.Call
}
// Close is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockIndexer_Expecter) Close(ctx interface{}) *MockIndexer_Close_Call {
return &MockIndexer_Close_Call{Call: _e.mock.On("Close", ctx)}
}
func (_c *MockIndexer_Close_Call) Run(run func(ctx context.Context)) *MockIndexer_Close_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockIndexer_Close_Call) Return(err error) *MockIndexer_Close_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockIndexer_Close_Call) RunAndReturn(run func(context.Context) error) *MockIndexer_Close_Call {
_c.Call.Return(run)
return _c
}
// ForceFTIndex provides a mock function with given fields:
func (_m *MockIndexer) ForceFTIndex() {
_m.Called()
}
// MockIndexer_ForceFTIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ForceFTIndex'
type MockIndexer_ForceFTIndex_Call struct {
*mock.Call
}
// ForceFTIndex is a helper method to define mock.On call
func (_e *MockIndexer_Expecter) ForceFTIndex() *MockIndexer_ForceFTIndex_Call {
return &MockIndexer_ForceFTIndex_Call{Call: _e.mock.On("ForceFTIndex")}
}
func (_c *MockIndexer_ForceFTIndex_Call) Run(run func()) *MockIndexer_ForceFTIndex_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockIndexer_ForceFTIndex_Call) Return() *MockIndexer_ForceFTIndex_Call {
_c.Call.Return()
return _c
}
func (_c *MockIndexer_ForceFTIndex_Call) RunAndReturn(run func()) *MockIndexer_ForceFTIndex_Call {
_c.Call.Return(run)
return _c
}
// Index provides a mock function with given fields: ctx, info, options
func (_m *MockIndexer) Index(ctx context.Context, info smartblock.DocInfo, options ...smartblock.IndexOption) error {
_va := make([]interface{}, len(options))
for _i := range options {
_va[_i] = options[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, info)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, smartblock.DocInfo, ...smartblock.IndexOption) error); ok {
r0 = rf(ctx, info, options...)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_Index_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Index'
type MockIndexer_Index_Call struct {
*mock.Call
}
// Index is a helper method to define mock.On call
// - ctx context.Context
// - info smartblock.DocInfo
// - options ...smartblock.IndexOption
func (_e *MockIndexer_Expecter) Index(ctx interface{}, info interface{}, options ...interface{}) *MockIndexer_Index_Call {
return &MockIndexer_Index_Call{Call: _e.mock.On("Index",
append([]interface{}{ctx, info}, options...)...)}
}
func (_c *MockIndexer_Index_Call) Run(run func(ctx context.Context, info smartblock.DocInfo, options ...smartblock.IndexOption)) *MockIndexer_Index_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]smartblock.IndexOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(smartblock.IndexOption)
}
}
run(args[0].(context.Context), args[1].(smartblock.DocInfo), variadicArgs...)
})
return _c
}
func (_c *MockIndexer_Index_Call) Return(_a0 error) *MockIndexer_Index_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockIndexer_Index_Call) RunAndReturn(run func(context.Context, smartblock.DocInfo, ...smartblock.IndexOption) error) *MockIndexer_Index_Call {
_c.Call.Return(run)
return _c
}
// Init provides a mock function with given fields: a
func (_m *MockIndexer) Init(a *app.App) error {
ret := _m.Called(a)
var r0 error
if rf, ok := ret.Get(0).(func(*app.App) error); ok {
r0 = rf(a)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init'
type MockIndexer_Init_Call struct {
*mock.Call
}
// Init is a helper method to define mock.On call
// - a *app.App
func (_e *MockIndexer_Expecter) Init(a interface{}) *MockIndexer_Init_Call {
return &MockIndexer_Init_Call{Call: _e.mock.On("Init", a)}
}
func (_c *MockIndexer_Init_Call) Run(run func(a *app.App)) *MockIndexer_Init_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(*app.App))
})
return _c
}
func (_c *MockIndexer_Init_Call) Return(err error) *MockIndexer_Init_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockIndexer_Init_Call) RunAndReturn(run func(*app.App) error) *MockIndexer_Init_Call {
_c.Call.Return(run)
return _c
}
// Name provides a mock function with given fields:
func (_m *MockIndexer) Name() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// MockIndexer_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name'
type MockIndexer_Name_Call struct {
*mock.Call
}
// Name is a helper method to define mock.On call
func (_e *MockIndexer_Expecter) Name() *MockIndexer_Name_Call {
return &MockIndexer_Name_Call{Call: _e.mock.On("Name")}
}
func (_c *MockIndexer_Name_Call) Run(run func()) *MockIndexer_Name_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockIndexer_Name_Call) Return(name string) *MockIndexer_Name_Call {
_c.Call.Return(name)
return _c
}
func (_c *MockIndexer_Name_Call) RunAndReturn(run func() string) *MockIndexer_Name_Call {
_c.Call.Return(run)
return _c
}
// ReindexCommonObjects provides a mock function with given fields:
func (_m *MockIndexer) ReindexCommonObjects() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_ReindexCommonObjects_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReindexCommonObjects'
type MockIndexer_ReindexCommonObjects_Call struct {
*mock.Call
}
// ReindexCommonObjects is a helper method to define mock.On call
func (_e *MockIndexer_Expecter) ReindexCommonObjects() *MockIndexer_ReindexCommonObjects_Call {
return &MockIndexer_ReindexCommonObjects_Call{Call: _e.mock.On("ReindexCommonObjects")}
}
func (_c *MockIndexer_ReindexCommonObjects_Call) Run(run func()) *MockIndexer_ReindexCommonObjects_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockIndexer_ReindexCommonObjects_Call) Return(_a0 error) *MockIndexer_ReindexCommonObjects_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockIndexer_ReindexCommonObjects_Call) RunAndReturn(run func() error) *MockIndexer_ReindexCommonObjects_Call {
_c.Call.Return(run)
return _c
}
// ReindexSpace provides a mock function with given fields: spaceID
func (_m *MockIndexer) ReindexSpace(spaceID string) error {
ret := _m.Called(spaceID)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(spaceID)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_ReindexSpace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReindexSpace'
type MockIndexer_ReindexSpace_Call struct {
*mock.Call
}
// ReindexSpace is a helper method to define mock.On call
// - spaceID string
func (_e *MockIndexer_Expecter) ReindexSpace(spaceID interface{}) *MockIndexer_ReindexSpace_Call {
return &MockIndexer_ReindexSpace_Call{Call: _e.mock.On("ReindexSpace", spaceID)}
}
func (_c *MockIndexer_ReindexSpace_Call) Run(run func(spaceID string)) *MockIndexer_ReindexSpace_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockIndexer_ReindexSpace_Call) Return(_a0 error) *MockIndexer_ReindexSpace_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockIndexer_ReindexSpace_Call) RunAndReturn(run func(string) error) *MockIndexer_ReindexSpace_Call {
_c.Call.Return(run)
return _c
}
// Run provides a mock function with given fields: ctx
func (_m *MockIndexer) Run(ctx context.Context) error {
ret := _m.Called(ctx)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
type MockIndexer_Run_Call struct {
*mock.Call
}
// Run is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockIndexer_Expecter) Run(ctx interface{}) *MockIndexer_Run_Call {
return &MockIndexer_Run_Call{Call: _e.mock.On("Run", ctx)}
}
func (_c *MockIndexer_Run_Call) Run(run func(ctx context.Context)) *MockIndexer_Run_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockIndexer_Run_Call) Return(err error) *MockIndexer_Run_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockIndexer_Run_Call) RunAndReturn(run func(context.Context) error) *MockIndexer_Run_Call {
_c.Call.Return(run)
return _c
}
// StartFullTextIndex provides a mock function with given fields:
func (_m *MockIndexer) StartFullTextIndex() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// MockIndexer_StartFullTextIndex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartFullTextIndex'
type MockIndexer_StartFullTextIndex_Call struct {
*mock.Call
}
// StartFullTextIndex is a helper method to define mock.On call
func (_e *MockIndexer_Expecter) StartFullTextIndex() *MockIndexer_StartFullTextIndex_Call {
return &MockIndexer_StartFullTextIndex_Call{Call: _e.mock.On("StartFullTextIndex")}
}
func (_c *MockIndexer_StartFullTextIndex_Call) Run(run func()) *MockIndexer_StartFullTextIndex_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockIndexer_StartFullTextIndex_Call) Return(_a0 error) *MockIndexer_StartFullTextIndex_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockIndexer_StartFullTextIndex_Call) RunAndReturn(run func() error) *MockIndexer_StartFullTextIndex_Call {
_c.Call.Return(run)
return _c
}
type mockConstructorTestingTNewMockIndexer interface {
mock.TestingT
Cleanup(func())
}
// NewMockIndexer creates a new instance of MockIndexer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockIndexer(t mockConstructorTestingTNewMockIndexer) *MockIndexer {
mock := &MockIndexer{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -12,6 +12,7 @@ import (
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/object/objectcache"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/metrics"
"github.com/anyproto/anytype-heart/pkg/lib/bundle"
smartblock2 "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
@ -21,7 +22,6 @@ import (
)
const (
// ForceObjectsReindexCounter reindex thread-based objects
ForceObjectsReindexCounter int32 = 8
@ -42,24 +42,38 @@ const (
ForceFilestoreKeysReindexCounter int32 = 2
)
func (i *indexer) reindexIfNeeded() error {
checksums, err := i.store.GetChecksums()
func (i *indexer) buildFlags(spaceID string) (reindexFlags, error) {
var (
checksums *model.ObjectStoreChecksums
flags reindexFlags
err error
)
if spaceID == "" {
checksums, err = i.store.GetGlobalChecksums()
} else {
checksums, err = i.store.GetChecksums(spaceID)
}
if err != nil && !errors.Is(err, badger.ErrKeyNotFound) {
return err
return reindexFlags{}, err
}
if checksums == nil {
// TODO: [MR] split object store checksums for space and common?
checksums = &model.ObjectStoreChecksums{
// do no add bundled relations checksums, because we want to index them for new accounts
ObjectsForceReindexCounter: ForceObjectsReindexCounter,
FilesForceReindexCounter: ForceFilesReindexCounter,
IdxRebuildCounter: ForceIdxRebuildCounter,
// per space
ObjectsForceReindexCounter: ForceObjectsReindexCounter,
// ?
FilesForceReindexCounter: ForceFilesReindexCounter,
// global
IdxRebuildCounter: ForceIdxRebuildCounter,
// per space
FilestoreKeysForceReindexCounter: ForceFilestoreKeysReindexCounter,
FulltextRebuild: ForceFulltextIndexCounter,
BundledObjects: ForceBundledObjectsReindexCounter,
// per space
FulltextRebuild: ForceFulltextIndexCounter,
// global
BundledObjects: ForceBundledObjectsReindexCounter,
}
}
var flags reindexFlags
if checksums.BundledRelations != bundle.RelationChecksum {
flags.bundledRelations = true
}
@ -87,132 +101,38 @@ func (i *indexer) reindexIfNeeded() error {
if checksums.IdxRebuildCounter != ForceIdxRebuildCounter {
flags.enableAll()
}
return i.reindex(flags)
return flags, nil
}
func (i *indexer) reindex(flags reindexFlags) (err error) {
if flags.any() {
log.Infof("start store reindex (%s)", flags.String())
}
if flags.objects && flags.fileObjects {
// files will be indexed within object indexing (see indexLinkedFiles)
// because we need to do it in the background.
// otherwise it will lead to the situation when files loading called from the reindex with DisableRemoteFlag
// will be waiting for the linkedFiles background indexing without this flag
flags.fileObjects = false
}
if flags.fileKeys {
err = i.fileStore.RemoveEmptyFileKeys()
if err != nil {
log.Errorf("reindex failed to RemoveEmptyFileKeys: %v", err.Error())
} else {
log.Infof("RemoveEmptyFileKeys filekeys succeed")
}
}
if flags.removeAllIndexedObjects {
ids, err := i.store.ListIds()
if err != nil {
log.Errorf("reindex failed to get all ids(removeAllIndexedObjects): %v", err.Error())
}
for _, id := range ids {
err = i.store.DeleteDetails(id)
if err != nil {
log.Errorf("reindex failed to delete details(removeAllIndexedObjects): %v", err.Error())
}
}
}
if flags.eraseIndexes {
err = i.store.EraseIndexes()
if err != nil {
log.Errorf("reindex failed to erase indexes: %v", err.Error())
} else {
log.Infof("all store indexes successfully erased")
}
}
err = i.reindexBundledObjects(flags)
func (i *indexer) ReindexSpace(spaceID string) (err error) {
flags, err := i.buildFlags(spaceID)
if err != nil {
log.Errorf("failed to reindex bundled objects: %s", err)
return
}
// We derive or init predefined blocks here in order to ensure consistency of object store.
// If we call this method before removing objects from store, we will end up with inconsistent state
// because indexing of predefined objects will not run again
predefinedObjectIDs, err := i.anytype.EnsurePredefinedBlocks(context.Background(), i.spaceService.AccountId())
if err != nil {
return fmt.Errorf("ensure predefined objects: %w", err)
}
spaceIDs := []string{i.spaceService.AccountId()}
// spaceID => workspaceID
spacesToInit := map[string]string{}
err = block.Do(i.picker, predefinedObjectIDs.Workspace, func(sb smartblock.SmartBlock) error {
st := sb.NewState()
spaces := st.Store().GetFields()["spaces"]
for k, v := range spaces.GetStructValue().GetFields() {
spacesToInit[k] = v.GetStringValue()
}
return nil
})
for spaceID, _ := range spacesToInit {
spaceIDs = append(spaceIDs, spaceID)
_, err = i.anytype.EnsurePredefinedBlocks(context.Background(), spaceID)
if err != nil {
return fmt.Errorf("ensure predefined objects for child space %s: %w", spaceID, err)
}
}
for _, spaceID := range spaceIDs {
err = i.EnsurePreinstalledObjects(spaceID)
if err != nil {
return fmt.Errorf("ensure preinstalled objects: %w", err)
}
}
// starting sync of all other objects later, because we don't want to have problems with loading of derived objects
// due to parallel load which can overload the stream
i.syncStarter.StartSync()
for _, spaceID := range spaceIDs {
err = i.reindexSpace(spaceID, flags)
if err != nil {
return fmt.Errorf("reindex space %s: %w", spaceID, err)
}
}
err = i.saveLatestChecksums()
if err != nil {
return fmt.Errorf("save latest checksums: %w", err)
}
return nil
}
func (i *indexer) reindexSpace(spaceID string, flags reindexFlags) (err error) {
ctx := objectcache.CacheOptsWithRemoteLoadDisabled(context.Background())
// for all ids except home and archive setting cache timeout for reindexing
// ctx = context.WithValue(ctx, ocache.CacheTimeout, cacheTimeout)
if flags.objects {
ids, err := i.getIdsForTypes(
spaceID,
types := []smartblock2.SmartBlockType{
smartblock2.SmartBlockTypePage,
smartblock2.SmartBlockTypeProfilePage,
smartblock2.SmartBlockTypeTemplate,
smartblock2.SmartBlockTypeArchive,
smartblock2.SmartBlockTypeHome,
smartblock2.SmartBlockTypeWorkspace,
smartblock2.SmartBlockTypeObjectType,
smartblock2.SmartBlockTypeRelation,
smartblock2.SmartBlockTypeSpaceView,
smartblock2.SmartBlockTypeProfilePage,
}
ids, err := i.getIdsForTypes(
spaceID,
types...,
)
if err != nil {
return err
}
start := time.Now()
successfullyReindexed := i.reindexIdsIgnoreErr(ctx, ids...)
successfullyReindexed := i.reindexIdsIgnoreErr(ctx, spaceID, ids...)
i.logFinishedReindexStat(metrics.ReindexTypeThreads, len(ids), successfullyReindexed, time.Since(start))
@ -263,10 +183,15 @@ func (i *indexer) reindexSpace(spaceID string, flags reindexFlags) (err error) {
}
}
return nil
return i.saveLatestChecksums(spaceID)
}
func (i *indexer) reindexBundledObjects(flags reindexFlags) error {
func (i *indexer) ReindexCommonObjects() error {
flags, err := i.buildFlags("")
if err != nil {
return err
}
err = i.removeGlobalIndexes(flags)
ctx := context.Background()
spaceID := addr.AnytypeMarketplaceWorkspace
@ -286,7 +211,7 @@ func (i *indexer) reindexBundledObjects(flags reindexFlags) error {
if flags.bundledObjects {
// hardcoded for now
ids := []string{addr.AnytypeProfileId, addr.MissingObject}
err := i.reindexIDs(ctx, metrics.ReindexTypeBundledObjects, ids)
err := i.reindexIDs(ctx, addr.AnytypeMarketplaceWorkspace, metrics.ReindexTypeBundledObjects, ids)
if err != nil {
return fmt.Errorf("reindex profile and missing object: %w", err)
}
@ -310,7 +235,51 @@ func (i *indexer) reindexBundledObjects(flags reindexFlags) error {
}
}
return nil
return i.saveLatestChecksums("")
}
func (i *indexer) removeGlobalIndexes(flags reindexFlags) (err error) {
if flags.any() {
log.Infof("start store reindex (%s)", flags.String())
}
if flags.objects && flags.fileObjects {
// files will be indexed within object indexing (see indexLinkedFiles)
// because we need to do it in the background.
// otherwise it will lead to the situation when files loading called from the reindex with DisableRemoteFlag
// will be waiting for the linkedFiles background indexing without this flag
flags.fileObjects = false
}
if flags.fileKeys {
err = i.fileStore.RemoveEmptyFileKeys()
if err != nil {
log.Errorf("reindex failed to RemoveEmptyFileKeys: %v", err.Error())
} else {
log.Infof("RemoveEmptyFileKeys filekeys succeed")
}
}
if flags.removeAllIndexedObjects {
ids, err := i.store.ListIds()
if err != nil {
log.Errorf("reindex failed to get all ids(removeAllIndexedObjects): %v", err.Error())
}
for _, id := range ids {
err = i.store.DeleteDetails(id)
if err != nil {
log.Errorf("reindex failed to delete details(removeAllIndexedObjects): %v", err.Error())
}
}
}
if flags.eraseIndexes {
err = i.store.EraseIndexes()
if err != nil {
log.Errorf("reindex failed to erase indexes: %v", err.Error())
} else {
log.Infof("all store indexes successfully erased")
}
}
return
}
func (i *indexer) reindexIDsForSmartblockTypes(ctx context.Context, spaceID string, reindexType metrics.ReindexType, sbTypes ...smartblock2.SmartBlockType) error {
@ -318,19 +287,19 @@ func (i *indexer) reindexIDsForSmartblockTypes(ctx context.Context, spaceID stri
if err != nil {
return err
}
return i.reindexIDs(ctx, reindexType, ids)
return i.reindexIDs(ctx, spaceID, reindexType, ids)
}
func (i *indexer) reindexIDs(ctx context.Context, reindexType metrics.ReindexType, ids []string) error {
func (i *indexer) reindexIDs(ctx context.Context, spaceID string, reindexType metrics.ReindexType, ids []string) error {
start := time.Now()
successfullyReindexed := i.reindexIdsIgnoreErr(ctx, ids...)
successfullyReindexed := i.reindexIdsIgnoreErr(ctx, spaceID, ids...)
i.logFinishedReindexStat(reindexType, len(ids), successfullyReindexed, time.Since(start))
return nil
}
func (i *indexer) reindexOutdatedObjects(ctx context.Context, spaceID string) (toReindex, success int, err error) {
// reindex of subobject collection always leads to reindex of the all subobjects reindexing
spc, err := i.spaceService.GetSpace(ctx, spaceID)
spc, err := i.spaceCore.Get(ctx, spaceID)
if err != nil {
return
}
@ -367,20 +336,22 @@ func (i *indexer) reindexOutdatedObjects(ctx context.Context, spaceID string) (t
}
}
success = i.reindexIdsIgnoreErr(ctx, idsToReindex...)
success = i.reindexIdsIgnoreErr(ctx, spaceID, idsToReindex...)
return len(idsToReindex), success, nil
}
func (i *indexer) reindexDoc(ctx context.Context, id string) error {
err := block.DoContext(i.picker, ctx, id, func(sb smartblock.SmartBlock) error {
func (i *indexer) reindexDoc(ctx context.Context, spaceID, id string) error {
return block.DoContextFullID(i.picker, ctx, domain.FullID{
ObjectID: id,
SpaceID: spaceID,
}, func(sb smartblock.SmartBlock) error {
return i.Index(ctx, sb.GetDocInfo())
})
return err
}
func (i *indexer) reindexIdsIgnoreErr(ctx context.Context, ids ...string) (successfullyReindexed int) {
func (i *indexer) reindexIdsIgnoreErr(ctx context.Context, spaceID string, ids ...string) (successfullyReindexed int) {
for _, id := range ids {
err := i.reindexDoc(ctx, id)
err := i.reindexDoc(ctx, spaceID, id)
if err != nil {
log.With("objectID", id).Errorf("failed to reindex: %v", err)
} else {
@ -390,40 +361,22 @@ func (i *indexer) reindexIdsIgnoreErr(ctx context.Context, ids ...string) (succe
return
}
func (i *indexer) EnsurePreinstalledObjects(spaceID string) error {
start := time.Now()
ids := make([]string, 0, len(bundle.SystemTypes)+len(bundle.SystemRelations))
for _, ot := range bundle.SystemTypes {
ids = append(ids, ot.BundledURL())
}
for _, rk := range bundle.SystemRelations {
ids = append(ids, rk.BundledURL())
}
_, _, err := i.objectCreator.InstallBundledObjects(context.Background(), spaceID, ids)
if err != nil {
return err
}
i.logFinishedReindexStat(metrics.ReindexTypeSystem, len(ids), len(ids), time.Since(start))
return nil
}
func (i *indexer) saveLatestChecksums() error {
func (i *indexer) saveLatestChecksums(spaceID string) error {
checksums := model.ObjectStoreChecksums{
BundledObjectTypes: bundle.TypeChecksum,
BundledRelations: bundle.RelationChecksum,
BundledTemplates: i.btHash.Hash(),
ObjectsForceReindexCounter: ForceObjectsReindexCounter,
FilesForceReindexCounter: ForceFilesReindexCounter,
BundledObjectTypes: bundle.TypeChecksum,
BundledRelations: bundle.RelationChecksum,
BundledTemplates: i.btHash.Hash(),
ObjectsForceReindexCounter: ForceObjectsReindexCounter,
FilesForceReindexCounter: ForceFilesReindexCounter,
IdxRebuildCounter: ForceIdxRebuildCounter,
FulltextRebuild: ForceFulltextIndexCounter,
BundledObjects: ForceBundledObjectsReindexCounter,
FilestoreKeysForceReindexCounter: ForceFilestoreKeysReindexCounter,
}
return i.store.SaveChecksums(&checksums)
if spaceID == "" {
return i.store.SaveGlobalChecksums(&checksums)
}
return i.store.SaveChecksums(spaceID, &checksums)
}
func (i *indexer) getIdsForTypes(spaceID string, sbt ...smartblock2.SmartBlockType) ([]string, error) {

View file

@ -22,7 +22,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/ftsearch"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
)

View file

@ -8,10 +8,10 @@ import (
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space"
)
func (mw *Middleware) NavigationListObjects(cctx context.Context, req *pb.RpcNavigationListObjectsRequest) *pb.RpcNavigationListObjectsResponse {
@ -51,9 +51,9 @@ func (mw *Middleware) NavigationGetObjectInfoWithLinks(cctx context.Context, req
return filtered
}
spaceService := getService[space.Service](mw)
resolver := getService[idresolver.Resolver](mw)
store := app.MustComponent[objectstore.ObjectStore](mw.applicationService.GetApp())
spaceID, err := spaceService.ResolveSpaceID(req.ObjectId)
spaceID, err := resolver.ResolveSpaceID(req.ObjectId)
if err != nil {
return response(pb.RpcNavigationGetObjectInfoWithLinksResponseError_UNKNOWN_ERROR, nil, fmt.Errorf("resolve spaceID: %w", err))
}

View file

@ -10,6 +10,7 @@ import (
"github.com/gogo/protobuf/types"
"github.com/anyproto/anytype-heart/core/block"
"github.com/anyproto/anytype-heart/core/block/object/idresolver"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/core/system_object"
"github.com/anyproto/anytype-heart/pb"
@ -68,7 +69,8 @@ func (mw *Middleware) ObjectTypeRelationAdd(cctx context.Context, req *pb.RpcObj
}
err := mw.doBlockService(func(bs *block.Service) (err error) {
spaceId, err := bs.ResolveSpaceID(req.ObjectTypeUrl)
res := mw.applicationService.GetApp().MustComponent(idresolver.CName).(idresolver.Resolver)
spaceId, err := res.ResolveSpaceID(req.ObjectTypeUrl)
if err != nil {
return err
}

View file

@ -19,7 +19,7 @@ import (
"github.com/anyproto/anytype-heart/core/system_object/mock_system_object"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/tests/testutil"
"github.com/anyproto/anytype-heart/util/testMock"
)
@ -56,7 +56,7 @@ func newFixture(t *testing.T) *fixture {
a.Register(sbtProvider)
systemObjectService := mock_system_object.NewMockService(t)
a.Register(testutil.PrepareMock(a, systemObjectService))
a.Register(testutil.PrepareMock(context.Background(), a, systemObjectService))
collectionService := &collectionServiceMock{MockCollectionService: mock_subscription.NewMockCollectionService(t)}
a.Register(collectionService)
@ -107,7 +107,7 @@ func newFixtureWithRealObjectStore(t *testing.T) *fixtureRealStore {
sbtProvider.EXPECT().Init(mock.Anything).Return(nil)
a.Register(sbtProvider)
systemObjectService := mock_system_object.NewMockService(t)
a.Register(testutil.PrepareMock(a, systemObjectService))
a.Register(testutil.PrepareMock(context.Background(), a, systemObjectService))
fx := &fixtureRealStore{
Service: New(),
a: a,

View file

@ -23,7 +23,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/typeprovider"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/slice"
)

View file

@ -33,7 +33,7 @@ const (
type fileStatusRegistry struct {
fileSyncService filesync.FileSync
fileStore filestore.FileStore
picker getblock.Picker
picker getblock.ObjectGetter
sync.Mutex
@ -44,7 +44,7 @@ type fileStatusRegistry struct {
func newFileStatusRegistry(
fileSyncService filesync.FileSync,
fileStore filestore.FileStore,
picker getblock.Picker,
picker getblock.ObjectGetter,
updateInterval time.Duration,
) *fileStatusRegistry {
return &fileStatusRegistry{

View file

@ -15,7 +15,6 @@ import (
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/datastore"
"github.com/anyproto/anytype-heart/space"
)
type fileWithSpace struct {
@ -28,16 +27,20 @@ type fileStatus struct {
updatedAt time.Time
}
type personalIDProvider interface {
PersonalSpaceID() string
}
type fileWatcher struct {
filesToWatchLock *sync.Mutex
filesToWatch map[fileWithSpace]struct{}
dbProvider datastore.Datastore
badger *badger.DB
spaceService space.Service
registry *fileStatusRegistry
updateCh chan fileWithSpace
closeCh chan struct{}
dbProvider datastore.Datastore
badger *badger.DB
provider personalIDProvider
registry *fileStatusRegistry
updateCh chan fileWithSpace
closeCh chan struct{}
updateReceiver syncstatus.UpdateReceiver
@ -45,7 +48,7 @@ type fileWatcher struct {
}
func newFileWatcher(
spaceService space.Service,
provider personalIDProvider,
dbProvider datastore.Datastore,
registry *fileStatusRegistry,
updateReceiver syncstatus.UpdateReceiver,
@ -60,7 +63,7 @@ func newFileWatcher(
updateReceiver: updateReceiver,
registry: registry,
dbProvider: dbProvider,
spaceService: spaceService,
provider: provider,
}
return watcher
}
@ -69,7 +72,7 @@ const filesToWatchPrefix = "/files_to_watch/"
func (s *fileWatcher) loadFilesToWatch() error {
return s.badger.View(func(txn *badger.Txn) error {
defaultSpaceID := s.spaceService.AccountId()
defaultSpaceID := s.provider.PersonalSpaceID()
iter := txn.NewIterator(badger.IteratorOptions{
Prefix: []byte(filesToWatchPrefix),
})

Some files were not shown because too many files have changed in this diff Show more