any-sync/node/nodespace/service.go

119 lines
3.6 KiB
Go

package nodespace
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/ocache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacestorage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
peer "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"golang.org/x/exp/slices"
"time"
)
const CName = "node.nodespace"
var log = logger.NewNamed(CName)
func New() Service {
return &service{}
}
type Service interface {
GetSpace(ctx context.Context, id string) (commonspace.Space, error)
GetOrPickSpace(ctx context.Context, id string) (commonspace.Space, error)
app.ComponentRunnable
}
type service struct {
conf commonspace.Config
spaceCache ocache.OCache
commonSpace commonspace.SpaceService
confService nodeconf.Service
spaceStorageProvider spacestorage.SpaceStorageProvider
}
func (s *service) Init(a *app.App) (err error) {
s.conf = a.MustComponent("config").(commonspace.ConfigGetter).GetSpace()
s.commonSpace = a.MustComponent(commonspace.CName).(commonspace.SpaceService)
s.confService = a.MustComponent(nodeconf.CName).(nodeconf.Service)
s.spaceStorageProvider = a.MustComponent(spacestorage.CName).(spacestorage.SpaceStorageProvider)
s.spaceCache = ocache.New(
s.loadSpace,
ocache.WithLogger(log.Sugar()),
ocache.WithGCPeriod(time.Minute),
ocache.WithTTL(time.Duration(s.conf.GCTTL)*time.Second),
)
return spacesyncproto.DRPCRegisterSpaceSync(a.MustComponent(server.CName).(server.DRPCServer), &rpcHandler{s})
}
func (s *service) Name() (name string) {
return CName
}
func (s *service) Run(ctx context.Context) (err error) {
return
}
func (s *service) GetSpace(ctx context.Context, id string) (commonspace.Space, error) {
v, err := s.spaceCache.Get(ctx, id)
if err != nil {
return nil, err
}
return v.(commonspace.Space), nil
}
func (s *service) GetOrPickSpace(ctx context.Context, id string) (sp commonspace.Space, err error) {
var v ocache.Object
peerId, err := peer.CtxPeerId(ctx)
if err != nil {
return
}
// if we are getting request from our fellow node
// don't try to wake the space, otherwise it can be possible
// that node would be waking up infinitely, depending on
// OCache ttl and HeadSync period
if slices.Contains(s.confService.GetLast().NodeIds(id), peerId) {
v, err = s.spaceCache.Pick(ctx, id)
if err != nil {
// safely checking that we don't have the space storage
// this should not open the database in case of node
if !s.spaceStorageProvider.SpaceExists(id) {
err = spacesyncproto.ErrSpaceMissing
}
return
}
} else {
// if the request is from the client it is safe to wake up the node
v, err = s.spaceCache.Get(ctx, id)
if err != nil {
return
}
}
sp = v.(commonspace.Space)
return
}
func (s *service) loadSpace(ctx context.Context, id string) (value ocache.Object, err error) {
cc, err := s.commonSpace.NewSpace(ctx, id)
if err != nil {
return
}
ns, err := newNodeSpace(cc)
if err != nil {
return
}
if err = ns.Init(ctx); err != nil {
return
}
return ns, nil
}
func (s *service) Close(ctx context.Context) (err error) {
return s.spaceCache.Close()
}