This commit is contained in:
Sergey Cherepanov 2022-12-12 20:53:18 +03:00
commit fa8ac48c2a
No known key found for this signature in database
GPG Key ID: 87F8EDE8FBDF637C
120 changed files with 12822 additions and 1223 deletions

5
.gitignore vendored
View File

@ -8,8 +8,9 @@
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
# playground folder for testing different clients # playground/tmp folder for testing different clients
playground playground/tmp
playground/debug.json
# .paw folder for macos paw client # .paw folder for macos paw client
.paw .paw

View File

@ -15,6 +15,7 @@ export PATH=$(GOPATH)/bin:$(shell echo $$PATH)
proto: proto:
$(MAKE) -C common proto $(MAKE) -C common proto
$(MAKE) -C consensus proto $(MAKE) -C consensus proto
$(MAKE) -C client proto
build: build:
$(MAKE) -C node build $(MAKE) -C node build

6
client/Makefile Normal file
View File

@ -0,0 +1,6 @@
.PHONY: proto
export GOPRIVATE=github.com/anytypeio
proto:
@$(eval GOGO_START := GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1)
$(GOGO_START) protoc --gogofaster_out=:. --go-drpc_out=protolib=github.com/gogo/protobuf:. api/apiproto/protos/*.proto

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,473 @@
// Code generated by protoc-gen-go-drpc. DO NOT EDIT.
// protoc-gen-go-drpc version: v0.0.32
// source: api/apiproto/protos/api.proto
package apiproto
import (
bytes "bytes"
context "context"
errors "errors"
jsonpb "github.com/gogo/protobuf/jsonpb"
proto "github.com/gogo/protobuf/proto"
drpc "storj.io/drpc"
drpcerr "storj.io/drpc/drpcerr"
)
type drpcEncoding_File_api_apiproto_protos_api_proto struct{}
func (drpcEncoding_File_api_apiproto_protos_api_proto) Marshal(msg drpc.Message) ([]byte, error) {
return proto.Marshal(msg.(proto.Message))
}
func (drpcEncoding_File_api_apiproto_protos_api_proto) Unmarshal(buf []byte, msg drpc.Message) error {
return proto.Unmarshal(buf, msg.(proto.Message))
}
func (drpcEncoding_File_api_apiproto_protos_api_proto) JSONMarshal(msg drpc.Message) ([]byte, error) {
var buf bytes.Buffer
err := new(jsonpb.Marshaler).Marshal(&buf, msg.(proto.Message))
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (drpcEncoding_File_api_apiproto_protos_api_proto) JSONUnmarshal(buf []byte, msg drpc.Message) error {
return jsonpb.Unmarshal(bytes.NewReader(buf), msg.(proto.Message))
}
type DRPCClientApiClient interface {
DRPCConn() drpc.Conn
CreateSpace(ctx context.Context, in *CreateSpaceRequest) (*CreateSpaceResponse, error)
DeriveSpace(ctx context.Context, in *DeriveSpaceRequest) (*DeriveSpaceResponse, error)
CreateDocument(ctx context.Context, in *CreateDocumentRequest) (*CreateDocumentResponse, error)
DeleteDocument(ctx context.Context, in *DeleteDocumentRequest) (*DeleteDocumentResponse, error)
AddText(ctx context.Context, in *AddTextRequest) (*AddTextResponse, error)
DumpTree(ctx context.Context, in *DumpTreeRequest) (*DumpTreeResponse, error)
TreeParams(ctx context.Context, in *TreeParamsRequest) (*TreeParamsResponse, error)
AllTrees(ctx context.Context, in *AllTreesRequest) (*AllTreesResponse, error)
AllSpaces(ctx context.Context, in *AllSpacesRequest) (*AllSpacesResponse, error)
LoadSpace(ctx context.Context, in *LoadSpaceRequest) (*LoadSpaceResponse, error)
}
type drpcClientApiClient struct {
cc drpc.Conn
}
func NewDRPCClientApiClient(cc drpc.Conn) DRPCClientApiClient {
return &drpcClientApiClient{cc}
}
func (c *drpcClientApiClient) DRPCConn() drpc.Conn { return c.cc }
func (c *drpcClientApiClient) CreateSpace(ctx context.Context, in *CreateSpaceRequest) (*CreateSpaceResponse, error) {
out := new(CreateSpaceResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/CreateSpace", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) DeriveSpace(ctx context.Context, in *DeriveSpaceRequest) (*DeriveSpaceResponse, error) {
out := new(DeriveSpaceResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/DeriveSpace", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) CreateDocument(ctx context.Context, in *CreateDocumentRequest) (*CreateDocumentResponse, error) {
out := new(CreateDocumentResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/CreateDocument", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) DeleteDocument(ctx context.Context, in *DeleteDocumentRequest) (*DeleteDocumentResponse, error) {
out := new(DeleteDocumentResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/DeleteDocument", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) AddText(ctx context.Context, in *AddTextRequest) (*AddTextResponse, error) {
out := new(AddTextResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/AddText", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) DumpTree(ctx context.Context, in *DumpTreeRequest) (*DumpTreeResponse, error) {
out := new(DumpTreeResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/DumpTree", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) TreeParams(ctx context.Context, in *TreeParamsRequest) (*TreeParamsResponse, error) {
out := new(TreeParamsResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/TreeParams", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) AllTrees(ctx context.Context, in *AllTreesRequest) (*AllTreesResponse, error) {
out := new(AllTreesResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/AllTrees", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) AllSpaces(ctx context.Context, in *AllSpacesRequest) (*AllSpacesResponse, error) {
out := new(AllSpacesResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/AllSpaces", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcClientApiClient) LoadSpace(ctx context.Context, in *LoadSpaceRequest) (*LoadSpaceResponse, error) {
out := new(LoadSpaceResponse)
err := c.cc.Invoke(ctx, "/clientapi.ClientApi/LoadSpace", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
type DRPCClientApiServer interface {
CreateSpace(context.Context, *CreateSpaceRequest) (*CreateSpaceResponse, error)
DeriveSpace(context.Context, *DeriveSpaceRequest) (*DeriveSpaceResponse, error)
CreateDocument(context.Context, *CreateDocumentRequest) (*CreateDocumentResponse, error)
DeleteDocument(context.Context, *DeleteDocumentRequest) (*DeleteDocumentResponse, error)
AddText(context.Context, *AddTextRequest) (*AddTextResponse, error)
DumpTree(context.Context, *DumpTreeRequest) (*DumpTreeResponse, error)
TreeParams(context.Context, *TreeParamsRequest) (*TreeParamsResponse, error)
AllTrees(context.Context, *AllTreesRequest) (*AllTreesResponse, error)
AllSpaces(context.Context, *AllSpacesRequest) (*AllSpacesResponse, error)
LoadSpace(context.Context, *LoadSpaceRequest) (*LoadSpaceResponse, error)
}
type DRPCClientApiUnimplementedServer struct{}
func (s *DRPCClientApiUnimplementedServer) CreateSpace(context.Context, *CreateSpaceRequest) (*CreateSpaceResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) DeriveSpace(context.Context, *DeriveSpaceRequest) (*DeriveSpaceResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) CreateDocument(context.Context, *CreateDocumentRequest) (*CreateDocumentResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) DeleteDocument(context.Context, *DeleteDocumentRequest) (*DeleteDocumentResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) AddText(context.Context, *AddTextRequest) (*AddTextResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) DumpTree(context.Context, *DumpTreeRequest) (*DumpTreeResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) TreeParams(context.Context, *TreeParamsRequest) (*TreeParamsResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) AllTrees(context.Context, *AllTreesRequest) (*AllTreesResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) AllSpaces(context.Context, *AllSpacesRequest) (*AllSpacesResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCClientApiUnimplementedServer) LoadSpace(context.Context, *LoadSpaceRequest) (*LoadSpaceResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
type DRPCClientApiDescription struct{}
func (DRPCClientApiDescription) NumMethods() int { return 10 }
func (DRPCClientApiDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
switch n {
case 0:
return "/clientapi.ClientApi/CreateSpace", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
CreateSpace(
ctx,
in1.(*CreateSpaceRequest),
)
}, DRPCClientApiServer.CreateSpace, true
case 1:
return "/clientapi.ClientApi/DeriveSpace", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
DeriveSpace(
ctx,
in1.(*DeriveSpaceRequest),
)
}, DRPCClientApiServer.DeriveSpace, true
case 2:
return "/clientapi.ClientApi/CreateDocument", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
CreateDocument(
ctx,
in1.(*CreateDocumentRequest),
)
}, DRPCClientApiServer.CreateDocument, true
case 3:
return "/clientapi.ClientApi/DeleteDocument", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
DeleteDocument(
ctx,
in1.(*DeleteDocumentRequest),
)
}, DRPCClientApiServer.DeleteDocument, true
case 4:
return "/clientapi.ClientApi/AddText", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
AddText(
ctx,
in1.(*AddTextRequest),
)
}, DRPCClientApiServer.AddText, true
case 5:
return "/clientapi.ClientApi/DumpTree", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
DumpTree(
ctx,
in1.(*DumpTreeRequest),
)
}, DRPCClientApiServer.DumpTree, true
case 6:
return "/clientapi.ClientApi/TreeParams", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
TreeParams(
ctx,
in1.(*TreeParamsRequest),
)
}, DRPCClientApiServer.TreeParams, true
case 7:
return "/clientapi.ClientApi/AllTrees", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
AllTrees(
ctx,
in1.(*AllTreesRequest),
)
}, DRPCClientApiServer.AllTrees, true
case 8:
return "/clientapi.ClientApi/AllSpaces", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
AllSpaces(
ctx,
in1.(*AllSpacesRequest),
)
}, DRPCClientApiServer.AllSpaces, true
case 9:
return "/clientapi.ClientApi/LoadSpace", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCClientApiServer).
LoadSpace(
ctx,
in1.(*LoadSpaceRequest),
)
}, DRPCClientApiServer.LoadSpace, true
default:
return "", nil, nil, nil, false
}
}
func DRPCRegisterClientApi(mux drpc.Mux, impl DRPCClientApiServer) error {
return mux.Register(impl, DRPCClientApiDescription{})
}
type DRPCClientApi_CreateSpaceStream interface {
drpc.Stream
SendAndClose(*CreateSpaceResponse) error
}
type drpcClientApi_CreateSpaceStream struct {
drpc.Stream
}
func (x *drpcClientApi_CreateSpaceStream) SendAndClose(m *CreateSpaceResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_DeriveSpaceStream interface {
drpc.Stream
SendAndClose(*DeriveSpaceResponse) error
}
type drpcClientApi_DeriveSpaceStream struct {
drpc.Stream
}
func (x *drpcClientApi_DeriveSpaceStream) SendAndClose(m *DeriveSpaceResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_CreateDocumentStream interface {
drpc.Stream
SendAndClose(*CreateDocumentResponse) error
}
type drpcClientApi_CreateDocumentStream struct {
drpc.Stream
}
func (x *drpcClientApi_CreateDocumentStream) SendAndClose(m *CreateDocumentResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_DeleteDocumentStream interface {
drpc.Stream
SendAndClose(*DeleteDocumentResponse) error
}
type drpcClientApi_DeleteDocumentStream struct {
drpc.Stream
}
func (x *drpcClientApi_DeleteDocumentStream) SendAndClose(m *DeleteDocumentResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_AddTextStream interface {
drpc.Stream
SendAndClose(*AddTextResponse) error
}
type drpcClientApi_AddTextStream struct {
drpc.Stream
}
func (x *drpcClientApi_AddTextStream) SendAndClose(m *AddTextResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_DumpTreeStream interface {
drpc.Stream
SendAndClose(*DumpTreeResponse) error
}
type drpcClientApi_DumpTreeStream struct {
drpc.Stream
}
func (x *drpcClientApi_DumpTreeStream) SendAndClose(m *DumpTreeResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_TreeParamsStream interface {
drpc.Stream
SendAndClose(*TreeParamsResponse) error
}
type drpcClientApi_TreeParamsStream struct {
drpc.Stream
}
func (x *drpcClientApi_TreeParamsStream) SendAndClose(m *TreeParamsResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_AllTreesStream interface {
drpc.Stream
SendAndClose(*AllTreesResponse) error
}
type drpcClientApi_AllTreesStream struct {
drpc.Stream
}
func (x *drpcClientApi_AllTreesStream) SendAndClose(m *AllTreesResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_AllSpacesStream interface {
drpc.Stream
SendAndClose(*AllSpacesResponse) error
}
type drpcClientApi_AllSpacesStream struct {
drpc.Stream
}
func (x *drpcClientApi_AllSpacesStream) SendAndClose(m *AllSpacesResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCClientApi_LoadSpaceStream interface {
drpc.Stream
SendAndClose(*LoadSpaceResponse) error
}
type drpcClientApi_LoadSpaceStream struct {
drpc.Stream
}
func (x *drpcClientApi_LoadSpaceStream) SendAndClose(m *LoadSpaceResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}

View File

@ -0,0 +1,106 @@
syntax = "proto3";
package clientapi;
option go_package = "api/apiproto";
service ClientApi {
rpc CreateSpace(CreateSpaceRequest) returns(CreateSpaceResponse);
rpc DeriveSpace(DeriveSpaceRequest) returns(DeriveSpaceResponse);
rpc CreateDocument(CreateDocumentRequest) returns(CreateDocumentResponse);
rpc DeleteDocument(DeleteDocumentRequest) returns(DeleteDocumentResponse);
rpc AddText(AddTextRequest) returns(AddTextResponse);
rpc DumpTree(DumpTreeRequest) returns(DumpTreeResponse);
rpc TreeParams(TreeParamsRequest) returns(TreeParamsResponse);
rpc AllTrees(AllTreesRequest) returns(AllTreesResponse);
rpc AllSpaces(AllSpacesRequest) returns(AllSpacesResponse);
rpc LoadSpace(LoadSpaceRequest) returns(LoadSpaceResponse);
}
message CreateSpaceRequest {
}
message CreateSpaceResponse {
string id = 1;
}
message DeriveSpaceRequest {
}
message DeriveSpaceResponse {
string id = 1;
}
message CreateDocumentRequest {
string spaceId = 1;
}
message CreateDocumentResponse {
string id = 1;
}
message DeleteDocumentRequest {
string spaceId = 1;
string documentId = 2;
}
message DeleteDocumentResponse {
}
message AddTextRequest {
string spaceId = 1;
string documentId = 2;
string text = 3;
bool isSnapshot = 4;
}
message AddTextResponse {
string documentId = 1;
string headId = 2;
string rootId = 3;
}
message DumpTreeRequest {
string spaceId = 1;
string documentId = 2;
}
message DumpTreeResponse {
string dump = 1;
}
message AllTreesRequest {
string spaceId = 1;
}
message Tree {
string id = 1;
repeated string heads = 2;
}
message AllTreesResponse {
repeated Tree trees = 1;
}
message AllSpacesRequest {
}
message AllSpacesResponse {
repeated string spaceIds = 1;
}
message LoadSpaceRequest {
string spaceId = 1;
}
message LoadSpaceResponse {
}
message TreeParamsRequest {
string spaceId = 1;
string documentId = 2;
}
message TreeParamsResponse {
string rootId = 1;
repeated string headIds = 2;
}

View File

@ -1,125 +0,0 @@
package api
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
"math/rand"
)
type Controller interface {
// DeriveSpace derives the space from current account
DeriveSpace() (id string, err error)
// CreateSpace creates new space with random data
CreateSpace() (id string, err error)
// AllSpaceIds returns ids of all spaces
AllSpaceIds() (ids []string, err error)
// LoadSpace asks node to load a particular space
LoadSpace(id string) (err error)
// CreateDocument creates new document in space
CreateDocument(spaceId string) (id string, err error)
// AllDocumentIds gets all ids of documents in space
AllDocumentIds(spaceId string) (ids []string, err error)
// AddText adds text to space document
AddText(spaceId, documentId, text string) (err error)
// DumpDocumentTree dumps the tree data into string
DumpDocumentTree(spaceId, documentId string) (dump string, err error)
ValidInvites(spaceId string) (invites []string, err error)
GenerateInvite(spaceId string) (invite string, err error)
JoinSpace(invite string) (err error)
}
type controller struct {
spaceService clientspace.Service
storageService storage.ClientStorage
docService document.Service
account account.Service
}
func newController(spaceService clientspace.Service,
storageService storage.ClientStorage,
docService document.Service,
account account.Service) Controller {
return &controller{
spaceService: spaceService,
storageService: storageService,
docService: docService,
account: account,
}
}
func (c *controller) DeriveSpace() (id string, err error) {
sp, err := c.spaceService.DeriveSpace(context.Background(), commonspace.SpaceDerivePayload{
SigningKey: c.account.Account().SignKey,
EncryptionKey: c.account.Account().EncKey,
})
if err != nil {
return
}
id = sp.Id()
return
}
func (c *controller) CreateSpace() (id string, err error) {
key, err := symmetric.NewRandom()
if err != nil {
return
}
sp, err := c.spaceService.CreateSpace(context.Background(), commonspace.SpaceCreatePayload{
SigningKey: c.account.Account().SignKey,
EncryptionKey: c.account.Account().EncKey,
ReadKey: key.Bytes(),
ReplicationKey: rand.Uint64(),
})
if err != nil {
return
}
id = sp.Id()
return
}
func (c *controller) AllSpaceIds() (ids []string, err error) {
return c.storageService.AllSpaceIds()
}
func (c *controller) LoadSpace(id string) (err error) {
_, err = c.spaceService.GetSpace(context.Background(), id)
return
}
func (c *controller) CreateDocument(spaceId string) (id string, err error) {
return c.docService.CreateDocument(spaceId)
}
func (c *controller) AllDocumentIds(spaceId string) (ids []string, err error) {
return c.docService.AllDocumentIds(spaceId)
}
func (c *controller) AddText(spaceId, documentId, text string) (err error) {
return c.docService.AddText(spaceId, documentId, text)
}
func (c *controller) DumpDocumentTree(spaceId, documentId string) (dump string, err error) {
return c.docService.DumpDocumentTree(spaceId, documentId)
}
func (c *controller) ValidInvites(spaceId string) (invites []string, err error) {
//TODO implement me
panic("implement me")
}
func (c *controller) GenerateInvite(spaceId string) (invite string, err error) {
//TODO implement me
panic("implement me")
}
func (c *controller) JoinSpace(invite string) (err error) {
//TODO implement me
panic("implement me")
}

146
client/api/rpchandler.go Normal file
View File

@ -0,0 +1,146 @@
package api
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/api/apiproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
"math/rand"
)
type rpcHandler struct {
spaceService clientspace.Service
storageService storage.ClientStorage
docService document.Service
account account.Service
}
func (r *rpcHandler) LoadSpace(ctx context.Context, request *apiproto.LoadSpaceRequest) (resp *apiproto.LoadSpaceResponse, err error) {
_, err = r.spaceService.GetSpace(context.Background(), request.SpaceId)
if err != nil {
return
}
resp = &apiproto.LoadSpaceResponse{}
return
}
func (r *rpcHandler) CreateSpace(ctx context.Context, request *apiproto.CreateSpaceRequest) (resp *apiproto.CreateSpaceResponse, err error) {
key, err := symmetric.NewRandom()
if err != nil {
return
}
sp, err := r.spaceService.CreateSpace(context.Background(), commonspace.SpaceCreatePayload{
SigningKey: r.account.Account().SignKey,
EncryptionKey: r.account.Account().EncKey,
ReadKey: key.Bytes(),
ReplicationKey: rand.Uint64(),
})
if err != nil {
return
}
id := sp.Id()
if err != nil {
return
}
resp = &apiproto.CreateSpaceResponse{Id: id}
return
}
func (r *rpcHandler) DeriveSpace(ctx context.Context, request *apiproto.DeriveSpaceRequest) (resp *apiproto.DeriveSpaceResponse, err error) {
sp, err := r.spaceService.DeriveSpace(context.Background(), commonspace.SpaceDerivePayload{
SigningKey: r.account.Account().SignKey,
EncryptionKey: r.account.Account().EncKey,
})
if err != nil {
return
}
id := sp.Id()
if err != nil {
return
}
resp = &apiproto.DeriveSpaceResponse{Id: id}
return
}
func (r *rpcHandler) CreateDocument(ctx context.Context, request *apiproto.CreateDocumentRequest) (resp *apiproto.CreateDocumentResponse, err error) {
id, err := r.docService.CreateDocument(request.SpaceId)
if err != nil {
return
}
resp = &apiproto.CreateDocumentResponse{Id: id}
return
}
func (r *rpcHandler) DeleteDocument(ctx context.Context, request *apiproto.DeleteDocumentRequest) (resp *apiproto.DeleteDocumentResponse, err error) {
err = r.docService.DeleteDocument(request.SpaceId, request.DocumentId)
if err != nil {
return
}
resp = &apiproto.DeleteDocumentResponse{}
return
}
func (r *rpcHandler) AddText(ctx context.Context, request *apiproto.AddTextRequest) (resp *apiproto.AddTextResponse, err error) {
root, head, err := r.docService.AddText(request.SpaceId, request.DocumentId, request.Text, request.IsSnapshot)
if err != nil {
return
}
resp = &apiproto.AddTextResponse{
DocumentId: request.DocumentId,
HeadId: head,
RootId: root,
}
return
}
func (r *rpcHandler) DumpTree(ctx context.Context, request *apiproto.DumpTreeRequest) (resp *apiproto.DumpTreeResponse, err error) {
dump, err := r.docService.DumpDocumentTree(request.SpaceId, request.DocumentId)
if err != nil {
return
}
resp = &apiproto.DumpTreeResponse{
Dump: dump,
}
return
}
func (r *rpcHandler) AllTrees(ctx context.Context, request *apiproto.AllTreesRequest) (resp *apiproto.AllTreesResponse, err error) {
heads, err := r.docService.AllDocumentHeads(request.SpaceId)
if err != nil {
return
}
var trees []*apiproto.Tree
for _, head := range heads {
trees = append(trees, &apiproto.Tree{
Id: head.Id,
Heads: head.Heads,
})
}
resp = &apiproto.AllTreesResponse{Trees: trees}
return
}
func (r *rpcHandler) AllSpaces(ctx context.Context, request *apiproto.AllSpacesRequest) (resp *apiproto.AllSpacesResponse, err error) {
ids, err := r.storageService.AllSpaceIds()
if err != nil {
return
}
resp = &apiproto.AllSpacesResponse{SpaceIds: ids}
return
}
func (r *rpcHandler) TreeParams(ctx context.Context, request *apiproto.TreeParamsRequest) (resp *apiproto.TreeParamsResponse, err error) {
root, heads, err := r.docService.TreeParams(request.SpaceId, request.DocumentId)
if err != nil {
return
}
resp = &apiproto.TreeParamsResponse{
RootId: root,
HeadIds: heads,
}
return
}

View File

@ -2,7 +2,7 @@ package api
import ( import (
"context" "context"
"fmt" "github.com/anytypeio/go-anytype-infrastructure-experiments/client/api/apiproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace" "github.com/anytypeio/go-anytype-infrastructure-experiments/client/clientspace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/client/document" "github.com/anytypeio/go-anytype-infrastructure-experiments/client/document"
clientstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage" clientstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/client/storage"
@ -11,37 +11,41 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
"go.uber.org/zap" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server"
"io" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
"net/http" "storj.io/drpc"
"strings"
) )
const CName = "api.service" const CName = "api.service"
var log = logger.NewNamed("api") var log = logger.NewNamed(CName)
func New() Service { func New() Service {
return &service{} return &service{BaseDrpcServer: server.NewBaseDrpcServer()}
} }
type Service interface { type Service interface {
app.ComponentRunnable app.ComponentRunnable
drpc.Mux
} }
type service struct { type service struct {
controller Controller transport secure.Service
srv *http.Server cfg *config.Config
cfg *config.Config spaceService clientspace.Service
storageService clientstorage.ClientStorage
docService document.Service
account account.Service
*server.BaseDrpcServer
} }
func (s *service) Init(a *app.App) (err error) { func (s *service) Init(a *app.App) (err error) {
s.controller = newController( s.spaceService = a.MustComponent(clientspace.CName).(clientspace.Service)
a.MustComponent(clientspace.CName).(clientspace.Service), s.storageService = a.MustComponent(storage.CName).(clientstorage.ClientStorage)
a.MustComponent(storage.CName).(clientstorage.ClientStorage), s.docService = a.MustComponent(document.CName).(document.Service)
a.MustComponent(document.CName).(document.Service), s.account = a.MustComponent(account.CName).(account.Service)
a.MustComponent(account.CName).(account.Service))
s.cfg = a.MustComponent(config.CName).(*config.Config) s.cfg = a.MustComponent(config.CName).(*config.Config)
s.transport = a.MustComponent(secure.CName).(secure.Service)
return nil return nil
} }
@ -50,132 +54,19 @@ func (s *service) Name() (name string) {
} }
func (s *service) Run(ctx context.Context) (err error) { func (s *service) Run(ctx context.Context) (err error) {
defer func() { err = s.BaseDrpcServer.Run(
if err == nil { ctx,
log.With(zap.String("port", s.cfg.APIServer.Port)).Info("api server started running") s.cfg.APIServer.ListenAddrs,
} func(handler drpc.Handler) drpc.Handler {
}() return handler
},
s.srv = &http.Server{ s.transport.BasicListener)
Addr: fmt.Sprintf(":%s", s.cfg.APIServer.Port),
}
mux := http.NewServeMux()
mux.HandleFunc("/deriveSpace", s.deriveSpace)
mux.HandleFunc("/createSpace", s.createSpace)
mux.HandleFunc("/loadSpace", s.loadSpace)
mux.HandleFunc("/allSpaceIds", s.allSpaceIds)
mux.HandleFunc("/createDocument", s.createDocument)
mux.HandleFunc("/allDocumentIds", s.allDocumentIds)
mux.HandleFunc("/addText", s.addText)
mux.HandleFunc("/dumpDocumentTree", s.dumpDocumentTree)
s.srv.Handler = mux
go s.runServer()
return nil
}
func (s *service) runServer() {
err := s.srv.ListenAndServe()
if err != nil { if err != nil {
log.With(zap.Error(err)).Error("could not run api server") return
} }
return apiproto.DRPCRegisterClientApi(s, &rpcHandler{s.spaceService, s.storageService, s.docService, s.account})
} }
func (s *service) Close(ctx context.Context) (err error) { func (s *service) Close(ctx context.Context) (err error) {
return s.srv.Shutdown(ctx) return s.BaseDrpcServer.Close(ctx)
}
func (s *service) deriveSpace(w http.ResponseWriter, req *http.Request) {
id, err := s.controller.DeriveSpace()
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, id)
}
func (s *service) loadSpace(w http.ResponseWriter, req *http.Request) {
query := req.URL.Query()
spaceId := query.Get("spaceId")
err := s.controller.LoadSpace(query.Get("spaceId"))
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, spaceId)
}
func (s *service) createSpace(w http.ResponseWriter, req *http.Request) {
id, err := s.controller.CreateSpace()
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, id)
}
func (s *service) allSpaceIds(w http.ResponseWriter, req *http.Request) {
ids, err := s.controller.AllSpaceIds()
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, strings.Join(ids, "\n"))
}
func (s *service) createDocument(w http.ResponseWriter, req *http.Request) {
query := req.URL.Query()
spaceId := query.Get("spaceId")
id, err := s.controller.CreateDocument(spaceId)
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, id)
}
func (s *service) allDocumentIds(w http.ResponseWriter, req *http.Request) {
query := req.URL.Query()
spaceId := query.Get("spaceId")
ids, err := s.controller.AllDocumentIds(spaceId)
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, strings.Join(ids, "\n"))
}
func (s *service) addText(w http.ResponseWriter, req *http.Request) {
query := req.URL.Query()
spaceId := query.Get("spaceId")
documentId := query.Get("documentId")
text := query.Get("text")
err := s.controller.AddText(spaceId, documentId, text)
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, "Text added")
}
func (s *service) dumpDocumentTree(w http.ResponseWriter, req *http.Request) {
query := req.URL.Query()
spaceId := query.Get("spaceId")
documentId := query.Get("documentId")
dump, err := s.controller.DumpDocumentTree(spaceId, documentId)
if err != nil {
sendText(w, http.StatusInternalServerError, err.Error())
return
}
sendText(w, http.StatusOK, dump)
}
func sendText(r http.ResponseWriter, code int, body string) {
r.Header().Set("Content-Type", "text/plain")
r.WriteHeader(code)
_, err := io.WriteString(r, fmt.Sprintf("%s\n", body))
if err != nil {
log.Error("writing response failed", zap.Error(err))
}
} }

View File

@ -103,6 +103,20 @@ func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (tr tree.Ob
if err != nil { if err != nil {
return return
} }
tr = doc.Tree() // we have to do this trick, otherwise the compiler won't understand that TextDocument conforms to SyncHandler interface
tr = doc.InnerTree()
return
}
func (c *treeCache) DeleteTree(ctx context.Context, spaceId, treeId string) (err error) {
tr, err := c.GetTree(ctx, spaceId, treeId)
if err != nil {
return
}
err = tr.Delete()
if err != nil {
return
}
_, err = c.cache.Remove(treeId)
return return
} }

View File

@ -19,22 +19,34 @@ func (r *rpcHandler) PullSpace(ctx context.Context, request *spacesyncproto.Pull
return return
} }
description := sp.Description() spaceDesc, err := sp.Description()
if err != nil {
err = spacesyncproto.ErrUnexpected
return
}
resp = &spacesyncproto.PullSpaceResponse{ resp = &spacesyncproto.PullSpaceResponse{
SpaceHeader: description.SpaceHeader, Payload: &spacesyncproto.SpacePayload{
AclPayload: description.AclPayload, SpaceHeader: spaceDesc.SpaceHeader,
AclPayloadId: description.AclId, AclPayloadId: spaceDesc.AclId,
AclPayload: spaceDesc.AclPayload,
SpaceSettingsPayload: spaceDesc.SpaceSettingsPayload,
SpaceSettingsPayloadId: spaceDesc.SpaceSettingsId,
},
} }
return return
} }
func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpaceRequest) (resp *spacesyncproto.PushSpaceResponse, err error) { func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpaceRequest) (resp *spacesyncproto.PushSpaceResponse, err error) {
description := commonspace.SpaceDescription{ description := commonspace.SpaceDescription{
SpaceHeader: req.SpaceHeader, SpaceHeader: req.Payload.SpaceHeader,
AclId: req.AclPayloadId, AclId: req.Payload.AclPayloadId,
AclPayload: req.AclPayload, AclPayload: req.Payload.AclPayload,
SpaceSettingsPayload: req.Payload.SpaceSettingsPayload,
SpaceSettingsId: req.Payload.SpaceSettingsPayloadId,
} }
err = r.s.AddSpace(ctx, description) ctx = context.WithValue(ctx, commonspace.AddSpaceCtxKey, description)
_, err = r.s.GetSpace(ctx, description.SpaceHeader.GetId())
if err != nil { if err != nil {
return return
} }

View File

@ -23,7 +23,6 @@ func New() Service {
type Service interface { type Service interface {
GetSpace(ctx context.Context, id string) (commonspace.Space, error) GetSpace(ctx context.Context, id string) (commonspace.Space, error)
AddSpace(ctx context.Context, description commonspace.SpaceDescription) (err error)
CreateSpace(ctx context.Context, payload commonspace.SpaceCreatePayload) (commonspace.Space, error) CreateSpace(ctx context.Context, payload commonspace.SpaceCreatePayload) (commonspace.Space, error)
DeriveSpace(ctx context.Context, payload commonspace.SpaceDerivePayload) (commonspace.Space, error) DeriveSpace(ctx context.Context, payload commonspace.SpaceDerivePayload) (commonspace.Space, error)
app.ComponentRunnable app.ComponentRunnable
@ -91,10 +90,6 @@ func (s *service) GetSpace(ctx context.Context, id string) (container commonspac
return v.(commonspace.Space), nil return v.(commonspace.Space), nil
} }
func (s *service) AddSpace(ctx context.Context, description commonspace.SpaceDescription) (err error) {
return s.commonSpace.AddSpace(ctx, description)
}
func (s *service) loadSpace(ctx context.Context, id string) (value ocache.Object, err error) { func (s *service) loadSpace(ctx context.Context, id string) (value ocache.Object, err error) {
cc, err := s.commonSpace.NewSpace(ctx, id) cc, err := s.commonSpace.NewSpace(ctx, id)
if err != nil { if err != nil {

View File

@ -8,15 +8,19 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app" "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/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
) )
type Service interface { type Service interface {
app.Component app.Component
CreateDocument(spaceId string) (id string, err error) CreateDocument(spaceId string) (id string, err error)
DeleteDocument(spaceId, documentId string) (err error)
AllDocumentIds(spaceId string) (ids []string, err error) AllDocumentIds(spaceId string) (ids []string, err error)
AddText(spaceId, documentId, text string) (err error) AllDocumentHeads(spaceId string) (ids []diffservice.TreeHeads, err error)
AddText(spaceId, documentId, text string, isSnapshot bool) (root, head string, err error)
DumpDocumentTree(spaceId, documentId string) (dump string, err error) DumpDocumentTree(spaceId, documentId string) (dump string, err error)
TreeParams(spaceId, documentId string) (root string, head []string, err error)
} }
const CName = "client.document" const CName = "client.document"
@ -49,12 +53,16 @@ func (s *service) CreateDocument(spaceId string) (id string, err error) {
if err != nil { if err != nil {
return return
} }
doc, err := textdocument.CreateTextDocument(context.Background(), space, s.account, nil) id, err = textdocument.CreateTextDocument(context.Background(), space, s.account)
return
}
func (s *service) DeleteDocument(spaceId, documentId string) (err error) {
space, err := s.spaceService.GetSpace(context.Background(), spaceId)
if err != nil { if err != nil {
return return
} }
id = doc.Tree().ID() return space.DeleteTree(context.Background(), documentId)
return
} }
func (s *service) AllDocumentIds(spaceId string) (ids []string, err error) { func (s *service) AllDocumentIds(spaceId string) (ids []string, err error) {
@ -66,12 +74,21 @@ func (s *service) AllDocumentIds(spaceId string) (ids []string, err error) {
return return
} }
func (s *service) AddText(spaceId, documentId, text string) (err error) { func (s *service) AllDocumentHeads(spaceId string) (ids []diffservice.TreeHeads, err error) {
space, err := s.spaceService.GetSpace(context.Background(), spaceId)
if err != nil {
return
}
ids = space.DebugAllHeads()
return
}
func (s *service) AddText(spaceId, documentId, text string, isSnapshot bool) (root, head string, err error) {
doc, err := s.cache.GetDocument(context.Background(), spaceId, documentId) doc, err := s.cache.GetDocument(context.Background(), spaceId, documentId)
if err != nil { if err != nil {
return return
} }
return doc.AddText(text) return doc.AddText(text, isSnapshot)
} }
func (s *service) DumpDocumentTree(spaceId, documentId string) (dump string, err error) { func (s *service) DumpDocumentTree(spaceId, documentId string) (dump string, err error) {
@ -79,5 +96,13 @@ func (s *service) DumpDocumentTree(spaceId, documentId string) (dump string, err
if err != nil { if err != nil {
return return
} }
return doc.Tree().DebugDump() return doc.DebugDump()
}
func (s *service) TreeParams(spaceId, documentId string) (root string, heads []string, err error) {
tr, err := s.cache.GetTree(context.Background(), spaceId, documentId)
if err != nil {
return
}
return tr.Root().Id, tr.Heads(), nil
} }

View File

@ -11,37 +11,29 @@ import (
) )
type TextDocument interface { type TextDocument interface {
Tree() tree.ObjectTree tree.ObjectTree
AddText(text string) error InnerTree() tree.ObjectTree
AddText(text string, isSnapshot bool) (string, string, error)
Text() (string, error) Text() (string, error)
TreeDump() string TreeDump() string
Close() error Close() error
} }
type textDocument struct { type textDocument struct {
objTree tree.ObjectTree tree.ObjectTree
account account.Service account account.Service
} }
func CreateTextDocument( func CreateTextDocument(
ctx context.Context, ctx context.Context,
space commonspace.Space, space commonspace.Space,
account account.Service, account account.Service) (id string, err error) {
listener updatelistener.UpdateListener) (doc TextDocument, err error) {
payload := tree.ObjectTreeCreatePayload{ payload := tree.ObjectTreeCreatePayload{
SignKey: account.Account().SignKey, SignKey: account.Account().SignKey,
SpaceId: space.Id(), SpaceId: space.Id(),
Identity: account.Account().Identity, Identity: account.Account().Identity,
} }
t, err := space.CreateTree(ctx, payload, listener) return space.CreateTree(ctx, payload)
if err != nil {
return
}
return &textDocument{
objTree: t,
account: account,
}, nil
} }
func NewTextDocument(ctx context.Context, space commonspace.Space, id string, listener updatelistener.UpdateListener, account account.Service) (doc TextDocument, err error) { func NewTextDocument(ctx context.Context, space commonspace.Space, id string, listener updatelistener.UpdateListener, account account.Service) (doc TextDocument, err error) {
@ -50,16 +42,16 @@ func NewTextDocument(ctx context.Context, space commonspace.Space, id string, li
return return
} }
return &textDocument{ return &textDocument{
objTree: t, ObjectTree: t,
account: account, account: account,
}, nil }, nil
} }
func (t *textDocument) Tree() tree.ObjectTree { func (t *textDocument) InnerTree() tree.ObjectTree {
return t.objTree return t.ObjectTree
} }
func (t *textDocument) AddText(text string) (err error) { func (t *textDocument) AddText(text string, isSnapshot bool) (root, head string, err error) {
content := &testchanges.TextContent_TextAppend{ content := &testchanges.TextContent_TextAppend{
TextAppend: &testchanges.TextAppend{Text: text}, TextAppend: &testchanges.TextAppend{Text: text},
} }
@ -73,22 +65,27 @@ func (t *textDocument) AddText(text string) (err error) {
if err != nil { if err != nil {
return return
} }
t.objTree.Lock() t.Lock()
defer t.objTree.Unlock() defer t.Unlock()
_, err = t.objTree.AddContent(context.Background(), tree.SignableChangeContent{ addRes, err := t.AddContent(context.Background(), tree.SignableChangeContent{
Data: res, Data: res,
Key: t.account.Account().SignKey, Key: t.account.Account().SignKey,
Identity: t.account.Account().Identity, Identity: t.account.Account().Identity,
IsSnapshot: false, IsSnapshot: isSnapshot,
}) })
if err != nil {
return
}
root = t.Root().Id
head = addRes.Heads[0]
return return
} }
func (t *textDocument) Text() (text string, err error) { func (t *textDocument) Text() (text string, err error) {
t.objTree.RLock() t.RLock()
defer t.objTree.RUnlock() defer t.RUnlock()
err = t.objTree.Iterate( err = t.Iterate(
func(decrypted []byte) (any, error) { func(decrypted []byte) (any, error) {
textChange := &testchanges.TextData{} textChange := &testchanges.TextData{}
err = proto.Unmarshal(decrypted, textChange) err = proto.Unmarshal(decrypted, textChange)
@ -110,7 +107,3 @@ func (t *textDocument) Text() (text string, err error) {
func (t *textDocument) TreeDump() string { func (t *textDocument) TreeDump() string {
return t.TreeDump() return t.TreeDump()
} }
func (t *textDocument) Close() error {
return nil
}

View File

@ -31,18 +31,20 @@ func (a aclKeys) RawRecordKey(id string) []byte {
} }
type treeKeys struct { type treeKeys struct {
id string id string
spaceId string spaceId string
headsKey []byte headsKey []byte
rootKey []byte rootKey []byte
rawChangePrefix []byte
} }
func newTreeKeys(spaceId, id string) treeKeys { func newTreeKeys(spaceId, id string) treeKeys {
return treeKeys{ return treeKeys{
id: id, id: id,
spaceId: spaceId, spaceId: spaceId,
headsKey: storage.JoinStringsToBytes("space", spaceId, "t", id, "heads"), headsKey: storage.JoinStringsToBytes("space", spaceId, "t", id, "heads"),
rootKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId", id), rootKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId", id),
rawChangePrefix: storage.JoinStringsToBytes("space", spaceId, "t", id),
} }
} }
@ -58,15 +60,23 @@ func (t treeKeys) RawChangeKey(id string) []byte {
return storage.JoinStringsToBytes("space", t.spaceId, "t", t.id, id) return storage.JoinStringsToBytes("space", t.spaceId, "t", t.id, id)
} }
func (t treeKeys) RawChangePrefix() []byte {
return t.rawChangePrefix
}
type spaceKeys struct { type spaceKeys struct {
headerKey []byte spaceId string
treePrefixKey []byte headerKey []byte
treePrefixKey []byte
spaceSettingsIdKey []byte
} }
func newSpaceKeys(spaceId string) spaceKeys { func newSpaceKeys(spaceId string) spaceKeys {
return spaceKeys{ return spaceKeys{
headerKey: storage.JoinStringsToBytes("space", "header", spaceId), spaceId: spaceId,
treePrefixKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId"), headerKey: storage.JoinStringsToBytes("space", "header", spaceId),
treePrefixKey: storage.JoinStringsToBytes("space", spaceId, "t", "rootId"),
spaceSettingsIdKey: storage.JoinStringsToBytes("space", spaceId, "spaceSettingsId"),
} }
} }
@ -78,6 +88,14 @@ func (s spaceKeys) TreeRootPrefix() []byte {
return s.treePrefixKey return s.treePrefixKey
} }
func (s spaceKeys) SpaceSettingsId() []byte {
return s.spaceSettingsIdKey
}
func (s spaceKeys) TreeDeletedKey(id string) []byte {
return storage.JoinStringsToBytes("space", s.spaceId, "deleted", id)
}
type storageServiceKeys struct { type storageServiceKeys struct {
spacePrefix []byte spacePrefix []byte
} }

View File

@ -4,19 +4,21 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/dgraph-io/badger/v3" "github.com/dgraph-io/badger/v3"
"sync"
) )
type spaceStorage struct { type spaceStorage struct {
spaceId string spaceId string
objDb *badger.DB spaceSettingsId string
keys spaceKeys objDb *badger.DB
aclStorage storage.ListStorage keys spaceKeys
header *spacesyncproto.RawSpaceHeaderWithId aclStorage storage.ListStorage
mx sync.Mutex header *spacesyncproto.RawSpaceHeaderWithId
} }
var spaceValidationFunc = spacestorage.ValidateSpaceStorageCreatePayload
func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.SpaceStorage, err error) { func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.SpaceStorage, err error) {
keys := newSpaceKeys(spaceId) keys := newSpaceKeys(spaceId)
err = objDb.View(func(txn *badger.Txn) error { err = objDb.View(func(txn *badger.Txn) error {
@ -30,10 +32,15 @@ func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.Space
return err return err
} }
spaceSettingsId, err := getTxn(txn, keys.SpaceSettingsId())
if err != nil {
return err
}
store = &spaceStorage{ store = &spaceStorage{
spaceId: spaceId, spaceId: spaceId,
objDb: objDb, spaceSettingsId: string(spaceSettingsId),
keys: keys, objDb: objDb,
keys: keys,
header: &spacesyncproto.RawSpaceHeaderWithId{ header: &spacesyncproto.RawSpaceHeaderWithId{
RawHeader: header, RawHeader: header,
Id: spaceId, Id: spaceId,
@ -43,7 +50,7 @@ func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.Space
return nil return nil
}) })
if err == badger.ErrKeyNotFound { if err == badger.ErrKeyNotFound {
err = spacesyncproto.ErrSpaceMissing err = spacestorage.ErrSpaceStorageMissing
} }
return return
} }
@ -51,11 +58,35 @@ func newSpaceStorage(objDb *badger.DB, spaceId string) (store spacestorage.Space
func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload) (store spacestorage.SpaceStorage, err error) { func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload) (store spacestorage.SpaceStorage, err error) {
keys := newSpaceKeys(payload.SpaceHeaderWithId.Id) keys := newSpaceKeys(payload.SpaceHeaderWithId.Id)
if hasDB(db, keys.HeaderKey()) { if hasDB(db, keys.HeaderKey()) {
err = spacesyncproto.ErrSpaceExists err = spacestorage.ErrSpaceStorageExists
return
}
err = spaceValidationFunc(payload)
if err != nil {
return
}
spaceStore := &spaceStorage{
spaceId: payload.SpaceHeaderWithId.Id,
objDb: db,
keys: keys,
spaceSettingsId: payload.SpaceSettingsWithId.Id,
header: payload.SpaceHeaderWithId,
}
_, err = spaceStore.CreateTreeStorage(storage.TreeStorageCreatePayload{
RootRawChange: payload.SpaceSettingsWithId,
Changes: []*treechangeproto.RawTreeChangeWithId{payload.SpaceSettingsWithId},
Heads: []string{payload.SpaceSettingsWithId.Id},
})
if err != nil {
return return
} }
err = db.Update(func(txn *badger.Txn) error { err = db.Update(func(txn *badger.Txn) error {
aclStorage, err := createListStorage(payload.SpaceHeaderWithId.Id, db, txn, payload.RecWithId) err = txn.Set(keys.SpaceSettingsId(), []byte(payload.SpaceSettingsWithId.Id))
if err != nil {
return err
}
aclStorage, err := createListStorage(payload.SpaceHeaderWithId.Id, db, txn, payload.AclWithId)
if err != nil { if err != nil {
return err return err
} }
@ -65,15 +96,10 @@ func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePa
return err return err
} }
store = &spaceStorage{ spaceStore.aclStorage = aclStorage
spaceId: payload.SpaceHeaderWithId.Id,
objDb: db,
keys: keys,
aclStorage: aclStorage,
header: payload.SpaceHeaderWithId,
}
return nil return nil
}) })
store = spaceStore
return return
} }
@ -81,15 +107,15 @@ func (s *spaceStorage) Id() string {
return s.spaceId return s.spaceId
} }
func (s *spaceStorage) SpaceSettingsId() string {
return s.spaceSettingsId
}
func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) { func (s *spaceStorage) TreeStorage(id string) (storage.TreeStorage, error) {
return newTreeStorage(s.objDb, s.spaceId, id) return newTreeStorage(s.objDb, s.spaceId, id)
} }
func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) { func (s *spaceStorage) CreateTreeStorage(payload storage.TreeStorageCreatePayload) (ts storage.TreeStorage, err error) {
// we have mutex here, so we prevent overwriting the heads of a tree on concurrent creation
s.mx.Lock()
defer s.mx.Unlock()
return createTreeStorage(s.objDb, s.spaceId, payload) return createTreeStorage(s.objDb, s.spaceId, payload)
} }
@ -112,7 +138,8 @@ func (s *spaceStorage) StoredIds() (ids []string, err error) {
for it.Rewind(); it.Valid(); it.Next() { for it.Rewind(); it.Valid(); it.Next() {
item := it.Item() item := it.Item()
id := item.Key() id := make([]byte, 0, len(item.Key()))
id = item.KeyCopy(id)
if len(id) <= len(s.keys.TreeRootPrefix())+1 { if len(id) <= len(s.keys.TreeRootPrefix())+1 {
continue continue
} }
@ -124,6 +151,27 @@ func (s *spaceStorage) StoredIds() (ids []string, err error) {
return return
} }
func (s *spaceStorage) SetTreeDeletedStatus(id, status string) (err error) {
return s.objDb.Update(func(txn *badger.Txn) error {
return txn.Set(s.keys.TreeDeletedKey(id), []byte(status))
})
}
func (s *spaceStorage) TreeDeletedStatus(id string) (status string, err error) {
err = s.objDb.View(func(txn *badger.Txn) error {
res, err := getTxn(txn, s.keys.TreeDeletedKey(id))
if err != nil {
return err
}
status = string(res)
return nil
})
if err == badger.ErrKeyNotFound {
err = nil
}
return
}
func (s *spaceStorage) Close() (err error) { func (s *spaceStorage) Close() (err error) {
return nil return nil
} }

View File

@ -4,7 +4,9 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"sort"
"strconv" "strconv"
"testing" "testing"
) )
@ -18,9 +20,14 @@ func spaceTestPayload() spacestorage.SpaceStorageCreatePayload {
Payload: []byte("aclRoot"), Payload: []byte("aclRoot"),
Id: "aclRootId", Id: "aclRootId",
} }
settings := &treechangeproto.RawTreeChangeWithId{
RawChange: []byte("settings"),
Id: "settingsId",
}
return spacestorage.SpaceStorageCreatePayload{ return spacestorage.SpaceStorageCreatePayload{
RecWithId: aclRoot, AclWithId: aclRoot,
SpaceHeaderWithId: header, SpaceHeaderWithId: header,
SpaceSettingsWithId: settings,
} }
} }
@ -31,7 +38,7 @@ func testSpace(t *testing.T, store spacestorage.SpaceStorage, payload spacestora
aclStorage, err := store.ACLStorage() aclStorage, err := store.ACLStorage()
require.NoError(t, err) require.NoError(t, err)
testList(t, aclStorage, payload.RecWithId, payload.RecWithId.Id) testList(t, aclStorage, payload.AclWithId, payload.AclWithId.Id)
} }
func TestSpaceStorage_Create(t *testing.T) { func TestSpaceStorage_Create(t *testing.T) {
@ -68,7 +75,7 @@ func TestSpaceStorage_NewAndCreateTree(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
testSpace(t, store, payload) testSpace(t, store, payload)
t.Run("create tree and get tree", func(t *testing.T) { t.Run("create tree, get tree and mark deleted", func(t *testing.T) {
payload := treeTestPayload() payload := treeTestPayload()
treeStore, err := store.CreateTreeStorage(payload) treeStore, err := store.CreateTreeStorage(payload)
require.NoError(t, err) require.NoError(t, err)
@ -77,6 +84,14 @@ func TestSpaceStorage_NewAndCreateTree(t *testing.T) {
otherStore, err := store.TreeStorage(payload.RootRawChange.Id) otherStore, err := store.TreeStorage(payload.RootRawChange.Id)
require.NoError(t, err) require.NoError(t, err)
testTreePayload(t, otherStore, payload) testTreePayload(t, otherStore, payload)
initialStatus := "deleted"
err = store.SetTreeDeletedStatus(otherStore.Id(), initialStatus)
require.NoError(t, err)
status, err := store.TreeDeletedStatus(otherStore.Id())
require.NoError(t, err)
require.Equal(t, initialStatus, status)
}) })
} }
@ -101,8 +116,11 @@ func TestSpaceStorage_StoredIds(t *testing.T) {
_, err := store.CreateTreeStorage(treePayload) _, err := store.CreateTreeStorage(treePayload)
require.NoError(t, err) require.NoError(t, err)
} }
ids = append(ids, payload.SpaceSettingsWithId.Id)
sort.Strings(ids)
storedIds, err := store.StoredIds() storedIds, err := store.StoredIds()
require.NoError(t, err) require.NoError(t, err)
sort.Strings(storedIds)
require.Equal(t, ids, storedIds) require.Equal(t, ids, storedIds)
} }

View File

@ -136,3 +136,46 @@ func (t *treeStorage) GetRawChange(ctx context.Context, id string) (raw *treecha
func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) { func (t *treeStorage) HasChange(ctx context.Context, id string) (bool, error) {
return hasDB(t.db, t.keys.RawChangeKey(id)), nil return hasDB(t.db, t.keys.RawChangeKey(id)), nil
} }
func (t *treeStorage) Delete() (err error) {
storedKeys, err := t.storedKeys()
if err != nil {
return
}
err = t.db.Update(func(txn *badger.Txn) error {
for _, k := range storedKeys {
err = txn.Delete(k)
if err != nil {
return err
}
}
return nil
})
return
}
func (t *treeStorage) storedKeys() (keys [][]byte, err error) {
err = t.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
// this will get all raw changes and also "heads"
opts.Prefix = t.keys.RawChangePrefix()
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
key := item.Key()
keyCopy := make([]byte, 0, len(key))
keyCopy = item.KeyCopy(keyCopy)
keys = append(keys, keyCopy)
}
return nil
})
if err != nil {
return
}
keys = append(keys, t.keys.RootIdKey())
return
}

View File

@ -61,6 +61,42 @@ func (fx *fixture) stop(t *testing.T) {
require.NoError(t, fx.db.Close()) require.NoError(t, fx.db.Close())
} }
func (fx *fixture) testNoKeysExist(t *testing.T, spaceId, treeId string) {
treeKeys := newTreeKeys(spaceId, treeId)
var keys [][]byte
err := fx.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
opts.Prefix = treeKeys.RawChangePrefix()
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
key := item.Key()
keyCopy := make([]byte, 0, len(key))
keyCopy = item.KeyCopy(key)
keys = append(keys, keyCopy)
}
return nil
})
require.NoError(t, err)
require.Equal(t, 0, len(keys))
err = fx.db.View(func(txn *badger.Txn) error {
_, err = getTxn(txn, treeKeys.RootIdKey())
require.Equal(t, err, badger.ErrKeyNotFound)
_, err = getTxn(txn, treeKeys.HeadsKey())
require.Equal(t, err, badger.ErrKeyNotFound)
return nil
})
}
func TestTreeStorage_Create(t *testing.T) { func TestTreeStorage_Create(t *testing.T) {
fx := newFixture(t) fx := newFixture(t)
fx.open(t) fx.open(t)
@ -121,3 +157,32 @@ func TestTreeStorage_Methods(t *testing.T) {
require.False(t, has) require.False(t, has)
}) })
} }
func TestTreeStorage_Delete(t *testing.T) {
fx := newFixture(t)
fx.open(t)
payload := treeTestPayload()
spaceId := "spaceId"
_, err := createTreeStorage(fx.db, spaceId, payload)
require.NoError(t, err)
fx.stop(t)
fx.open(t)
defer fx.stop(t)
store, err := newTreeStorage(fx.db, spaceId, payload.RootRawChange.Id)
require.NoError(t, err)
testTreePayload(t, store, payload)
t.Run("add raw change, get change and has change", func(t *testing.T) {
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "newId"}
require.NoError(t, store.AddRawChange(newChange))
err = store.Delete()
require.NoError(t, err)
_, err = newTreeStorage(fx.db, spaceId, payload.RootRawChange.Id)
require.Equal(t, err, storage.ErrUnknownTreeId)
fx.testNoKeysExist(t, spaceId, payload.RootRawChange.Id)
})
}

View File

@ -3,7 +3,7 @@ export GOPRIVATE=github.com/anytypeio
proto: proto:
@echo 'Generating protobuf packages (Go)...' @echo 'Generating protobuf packages (Go)...'
# Uncomment if needed
@$(eval GOGO_START := GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1) @$(eval GOGO_START := GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1)
@$(eval P_ACL_RECORDS_PATH_PB := pkg/acl/aclrecordproto) @$(eval P_ACL_RECORDS_PATH_PB := pkg/acl/aclrecordproto)
@$(eval P_TREE_CHANGES_PATH_PB := pkg/acl/treechangeproto) @$(eval P_TREE_CHANGES_PATH_PB := pkg/acl/treechangeproto)

View File

@ -0,0 +1,78 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/account (interfaces: Service)
// Package mock_account is a generated GoMock package.
package mock_account
import (
reflect "reflect"
app "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app"
account "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/account"
gomock "github.com/golang/mock/gomock"
)
// MockService is a mock of Service interface.
type MockService struct {
ctrl *gomock.Controller
recorder *MockServiceMockRecorder
}
// MockServiceMockRecorder is the mock recorder for MockService.
type MockServiceMockRecorder struct {
mock *MockService
}
// NewMockService creates a new mock instance.
func NewMockService(ctrl *gomock.Controller) *MockService {
mock := &MockService{ctrl: ctrl}
mock.recorder = &MockServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockService) EXPECT() *MockServiceMockRecorder {
return m.recorder
}
// Account mocks base method.
func (m *MockService) Account() *account.AccountData {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Account")
ret0, _ := ret[0].(*account.AccountData)
return ret0
}
// Account indicates an expected call of Account.
func (mr *MockServiceMockRecorder) Account() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Account", reflect.TypeOf((*MockService)(nil).Account))
}
// Init mocks base method.
func (m *MockService) Init(arg0 *app.App) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Init", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Init indicates an expected call of Init.
func (mr *MockServiceMockRecorder) Init(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockService)(nil).Init), arg0)
}
// Name mocks base method.
func (m *MockService) Name() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Name")
ret0, _ := ret[0].(string)
return ret0
}
// Name indicates an expected call of Name.
func (mr *MockServiceMockRecorder) Name() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockService)(nil).Name))
}

View File

@ -1,3 +1,4 @@
//go:generate mockgen -destination mock_account/mock_account.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/account Service
package account package account
import ( import (

View File

@ -3,6 +3,7 @@ package commonspace
import ( import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/objectgetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/objectgetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncacl" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncacl"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
) )
@ -11,13 +12,15 @@ type commonSpaceGetter struct {
spaceId string spaceId string
aclList *syncacl.SyncACL aclList *syncacl.SyncACL
treeGetter treegetter.TreeGetter treeGetter treegetter.TreeGetter
settings settingsdocument.SettingsDocument
} }
func newCommonSpaceGetter(spaceId string, aclList *syncacl.SyncACL, treeGetter treegetter.TreeGetter) objectgetter.ObjectGetter { func newCommonSpaceGetter(spaceId string, aclList *syncacl.SyncACL, treeGetter treegetter.TreeGetter, settings settingsdocument.SettingsDocument) objectgetter.ObjectGetter {
return &commonSpaceGetter{ return &commonSpaceGetter{
spaceId: spaceId, spaceId: spaceId,
aclList: aclList, aclList: aclList,
treeGetter: treeGetter, treeGetter: treeGetter,
settings: settings,
} }
} }
@ -26,6 +29,10 @@ func (c *commonSpaceGetter) GetObject(ctx context.Context, objectId string) (obj
obj = c.aclList obj = c.aclList
return return
} }
if c.settings.ID() == objectId {
obj = c.settings.(objectgetter.Object)
return
}
t, err := c.treeGetter.GetTree(ctx, c.spaceId, objectId) t, err := c.treeGetter.GetTree(ctx, c.spaceId, objectId)
if err != nil { if err != nil {
return return

View File

@ -0,0 +1,28 @@
package commonspace
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
treestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
)
type commonStorage struct {
storage.SpaceStorage
}
func newCommonStorage(spaceStorage storage.SpaceStorage) storage.SpaceStorage {
return &commonStorage{
SpaceStorage: spaceStorage,
}
}
func (c *commonStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (store treestorage.TreeStorage, err error) {
status, err := c.TreeDeletedStatus(payload.RootRawChange.Id)
if err != nil {
return
}
if status == "" {
return c.SpaceStorage.CreateTreeStorage(payload)
}
err = storage.ErrTreeStorageAlreadyDeleted
return
}

View File

@ -1,34 +1,43 @@
//go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer,PeriodicSync //go:generate mockgen -destination mock_diffservice/mock_diffservice.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice DiffSyncer
package diffservice package diffservice
import ( import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/periodicsync"
"go.uber.org/zap" "go.uber.org/zap"
"strings" "strings"
) )
type DiffService interface { type TreeHeads struct {
HeadNotifiable Id string
HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error) Heads []string
RemoveObject(id string) }
AllIds() []string
Init(objectIds []string) type DiffService interface {
UpdateHeads(id string, heads []string)
HandleRangeRequest(ctx context.Context, req *spacesyncproto.HeadSyncRequest) (resp *spacesyncproto.HeadSyncResponse, err error)
RemoveObjects(ids []string)
AllIds() []string
DebugAllHeads() (res []TreeHeads)
Init(objectIds []string, deletionState deletionstate.DeletionState)
Close() (err error) Close() (err error)
} }
type diffService struct { type diffService struct {
spaceId string spaceId string
periodicSync PeriodicSync periodicSync periodicsync.PeriodicSync
storage storage.SpaceStorage storage storage.SpaceStorage
diff ldiff.Diff diff ldiff.Diff
log *zap.Logger log *zap.Logger
syncer DiffSyncer
syncPeriod int syncPeriod int
} }
@ -45,11 +54,12 @@ func NewDiffService(
l := log.With(zap.String("spaceId", spaceId)) l := log.With(zap.String("spaceId", spaceId))
factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient) factory := spacesyncproto.ClientFactoryFunc(spacesyncproto.NewDRPCSpaceClient)
syncer := newDiffSyncer(spaceId, diff, confConnector, cache, storage, factory, l) syncer := newDiffSyncer(spaceId, diff, confConnector, cache, storage, factory, l)
periodicSync := newPeriodicSync(syncPeriod, syncer, l) periodicSync := periodicsync.NewPeriodicSync(syncPeriod, syncer.Sync, l)
return &diffService{ return &diffService{
spaceId: spaceId, spaceId: spaceId,
storage: storage, storage: storage,
syncer: syncer,
periodicSync: periodicSync, periodicSync: periodicSync,
diff: diff, diff: diff,
log: log, log: log,
@ -57,8 +67,9 @@ func NewDiffService(
} }
} }
func (d *diffService) Init(objectIds []string) { func (d *diffService) Init(objectIds []string, deletionState deletionstate.DeletionState) {
d.fillDiff(objectIds) d.fillDiff(objectIds)
d.syncer.Init(deletionState)
d.periodicSync.Run() d.periodicSync.Run()
} }
@ -67,19 +78,27 @@ func (d *diffService) HandleRangeRequest(ctx context.Context, req *spacesyncprot
} }
func (d *diffService) UpdateHeads(id string, heads []string) { func (d *diffService) UpdateHeads(id string, heads []string) {
d.diff.Set(ldiff.Element{ d.syncer.UpdateHeads(id, heads)
Id: id,
Head: concatStrings(heads),
})
} }
func (d *diffService) AllIds() []string { func (d *diffService) AllIds() []string {
return d.diff.Ids() return d.diff.Ids()
} }
func (d *diffService) RemoveObject(id string) { func (d *diffService) DebugAllHeads() (res []TreeHeads) {
// TODO: add space document to remove ids els := d.diff.Elements()
d.diff.RemoveId(id) for _, el := range els {
idHead := TreeHeads{
Id: el.Id,
Heads: splitString(el.Head),
}
res = append(res, idHead)
}
return
}
func (d *diffService) RemoveObjects(ids []string) {
d.syncer.RemoveObjects(ids)
} }
func (d *diffService) Close() (err error) { func (d *diffService) Close() (err error) {
@ -121,3 +140,11 @@ func concatStrings(strs []string) string {
} }
return b.String() return b.String()
} }
func splitString(str string) (res []string) {
const cidLen = 59
for i := 0; i < len(str); i += cidLen {
res = append(res, str[i:i+cidLen])
}
return
}

View File

@ -3,10 +3,12 @@ package diffservice
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
mock_storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage" mock_storage2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff/mock_ldiff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff/mock_ldiff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/periodicsync/mock_periodicsync"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"testing" "testing"
) )
@ -17,10 +19,12 @@ func TestDiffService(t *testing.T) {
spaceId := "spaceId" spaceId := "spaceId"
l := logger.NewNamed("sync") l := logger.NewNamed("sync")
pSyncMock := mock_diffservice.NewMockPeriodicSync(ctrl) pSyncMock := mock_periodicsync.NewMockPeriodicSync(ctrl)
storageMock := mock_storage.NewMockSpaceStorage(ctrl) storageMock := mock_storage.NewMockSpaceStorage(ctrl)
treeStorageMock := mock_storage2.NewMockTreeStorage(ctrl) treeStorageMock := mock_storage2.NewMockTreeStorage(ctrl)
diffMock := mock_ldiff.NewMockDiff(ctrl) diffMock := mock_ldiff.NewMockDiff(ctrl)
syncer := mock_diffservice.NewMockDiffSyncer(ctrl)
delState := mock_deletionstate.NewMockDeletionState(ctrl)
syncPeriod := 1 syncPeriod := 1
initId := "initId" initId := "initId"
@ -28,6 +32,7 @@ func TestDiffService(t *testing.T) {
spaceId: spaceId, spaceId: spaceId,
storage: storageMock, storage: storageMock,
periodicSync: pSyncMock, periodicSync: pSyncMock,
syncer: syncer,
diff: diffMock, diff: diffMock,
log: l, log: l,
syncPeriod: syncPeriod, syncPeriod: syncPeriod,
@ -36,22 +41,25 @@ func TestDiffService(t *testing.T) {
t.Run("init", func(t *testing.T) { t.Run("init", func(t *testing.T) {
storageMock.EXPECT().TreeStorage(initId).Return(treeStorageMock, nil) storageMock.EXPECT().TreeStorage(initId).Return(treeStorageMock, nil)
treeStorageMock.EXPECT().Heads().Return([]string{"h1", "h2"}, nil) treeStorageMock.EXPECT().Heads().Return([]string{"h1", "h2"}, nil)
syncer.EXPECT().Init(delState)
diffMock.EXPECT().Set(ldiff.Element{ diffMock.EXPECT().Set(ldiff.Element{
Id: initId, Id: initId,
Head: "h1h2", Head: "h1h2",
}) })
pSyncMock.EXPECT().Run() pSyncMock.EXPECT().Run()
service.Init([]string{initId}) service.Init([]string{initId}, delState)
}) })
t.Run("update heads", func(t *testing.T) { t.Run("update heads", func(t *testing.T) {
diffMock.EXPECT().Set(ldiff.Element{ syncer.EXPECT().UpdateHeads(initId, []string{"h1", "h2"})
Id: initId,
Head: "h1h2",
})
service.UpdateHeads(initId, []string{"h1", "h2"}) service.UpdateHeads(initId, []string{"h1", "h2"})
}) })
t.Run("remove objects", func(t *testing.T) {
syncer.EXPECT().RemoveObjects([]string{"h1", "h2"})
service.RemoveObjects([]string{"h1", "h2"})
})
t.Run("close", func(t *testing.T) { t.Run("close", func(t *testing.T) {
pSyncMock.EXPECT().Close() pSyncMock.EXPECT().Close()
service.Close() service.Close()

View File

@ -3,8 +3,10 @@ package diffservice
import ( import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
@ -16,6 +18,9 @@ import (
type DiffSyncer interface { type DiffSyncer interface {
Sync(ctx context.Context) error Sync(ctx context.Context) error
RemoveObjects(ids []string)
UpdateHeads(id string, heads []string)
Init(deletionState deletionstate.DeletionState)
} }
func newDiffSyncer( func newDiffSyncer(
@ -45,6 +50,28 @@ type diffSyncer struct {
storage storage.SpaceStorage storage storage.SpaceStorage
clientFactory spacesyncproto.ClientFactory clientFactory spacesyncproto.ClientFactory
log *zap.Logger log *zap.Logger
deletionState deletionstate.DeletionState
}
func (d *diffSyncer) Init(deletionState deletionstate.DeletionState) {
d.deletionState = deletionState
d.deletionState.AddObserver(d.RemoveObjects)
}
func (d *diffSyncer) RemoveObjects(ids []string) {
for _, id := range ids {
d.diff.RemoveId(id)
}
}
func (d *diffSyncer) UpdateHeads(id string, heads []string) {
if d.deletionState.Exists(id) {
return
}
d.diff.Set(ldiff.Element{
Id: id,
Head: concatStrings(heads),
})
} }
func (d *diffSyncer) Sync(ctx context.Context) error { func (d *diffSyncer) Sync(ctx context.Context) error {
@ -74,21 +101,35 @@ func (d *diffSyncer) syncWithPeer(ctx context.Context, p peer.Peer) (err error)
if err == spacesyncproto.ErrSpaceMissing { if err == spacesyncproto.ErrSpaceMissing {
return d.sendPushSpaceRequest(ctx, cl) return d.sendPushSpaceRequest(ctx, cl)
} }
totalLen := len(newIds) + len(changedIds) + len(removedIds)
// not syncing ids which were removed through settings document
filteredIds := d.deletionState.FilterJoin(newIds, changedIds, removedIds)
ctx = peer.CtxWithPeerId(ctx, p.Id()) ctx = peer.CtxWithPeerId(ctx, p.Id())
d.pingTreesInCache(ctx, newIds) d.pingTreesInCache(ctx, filteredIds)
d.pingTreesInCache(ctx, changedIds)
d.pingTreesInCache(ctx, removedIds)
d.log.Info("sync done:", zap.Int("newIds", len(newIds)), d.log.Info("sync done:", zap.Int("newIds", len(newIds)),
zap.Int("changedIds", len(changedIds)), zap.Int("changedIds", len(changedIds)),
zap.Int("removedIds", len(removedIds))) zap.Int("removedIds", len(removedIds)),
zap.Int("already deleted ids", totalLen-len(filteredIds)))
return return
} }
func (d *diffSyncer) pingTreesInCache(ctx context.Context, trees []string) { func (d *diffSyncer) pingTreesInCache(ctx context.Context, trees []string) {
for _, tId := range trees { for _, tId := range trees {
_, _ = d.cache.GetTree(ctx, d.spaceId, tId) tree, err := d.cache.GetTree(ctx, d.spaceId, tId)
if err != nil {
continue
}
syncTree, ok := tree.(synctree.SyncTree)
if !ok {
continue
}
// the idea why we call it directly is that if we try to get it from cache
// it may be already there (i.e. loaded)
// and build func will not be called, thus we won't sync the tree
// therefore we just do it manually
syncTree.Ping()
} }
} }
@ -108,10 +149,24 @@ func (d *diffSyncer) sendPushSpaceRequest(ctx context.Context, cl spacesyncproto
return return
} }
settingsStorage, err := d.storage.TreeStorage(d.storage.SpaceSettingsId())
if err != nil {
return
}
spaceSettingsRoot, err := settingsStorage.Root()
if err != nil {
return
}
spacePayload := &spacesyncproto.SpacePayload{
SpaceHeader: header,
AclPayload: root.Payload,
AclPayloadId: root.Id,
SpaceSettingsPayload: spaceSettingsRoot.RawChange,
SpaceSettingsPayloadId: spaceSettingsRoot.Id,
}
_, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{ _, err = cl.PushSpace(ctx, &spacesyncproto.PushSpaceRequest{
SpaceHeader: header, Payload: spacePayload,
AclPayload: root.Payload,
AclPayloadId: root.Id,
}) })
return return
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/remotediff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto/mock_spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
@ -13,6 +14,9 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf/mock_nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
mock_aclstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage" mock_aclstorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage"
mock_treestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff/mock_ldiff" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ldiff/mock_ldiff"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/libp2p/go-libp2p/core/sec" "github.com/libp2p/go-libp2p/core/sec"
@ -25,6 +29,7 @@ import (
type pushSpaceRequestMatcher struct { type pushSpaceRequestMatcher struct {
spaceId string spaceId string
aclRootId string aclRootId string
settingsId string
spaceHeader *spacesyncproto.RawSpaceHeaderWithId spaceHeader *spacesyncproto.RawSpaceHeaderWithId
} }
@ -34,7 +39,7 @@ func (p pushSpaceRequestMatcher) Matches(x interface{}) bool {
return false return false
} }
return res.AclPayloadId == p.aclRootId && res.SpaceHeader == p.spaceHeader return res.Payload.AclPayloadId == p.aclRootId && res.Payload.SpaceHeader == p.spaceHeader && res.Payload.SpaceSettingsPayloadId == p.settingsId
} }
func (p pushSpaceRequestMatcher) String() string { func (p pushSpaceRequestMatcher) String() string {
@ -77,10 +82,12 @@ func (m mockPeer) NewStream(ctx context.Context, rpc string, enc drpc.Encoding)
func newPushSpaceRequestMatcher( func newPushSpaceRequestMatcher(
spaceId string, spaceId string,
aclRootId string, aclRootId string,
settingsId string,
spaceHeader *spacesyncproto.RawSpaceHeaderWithId) *pushSpaceRequestMatcher { spaceHeader *spacesyncproto.RawSpaceHeaderWithId) *pushSpaceRequestMatcher {
return &pushSpaceRequestMatcher{ return &pushSpaceRequestMatcher{
spaceId: spaceId, spaceId: spaceId,
aclRootId: aclRootId, aclRootId: aclRootId,
settingsId: settingsId,
spaceHeader: spaceHeader, spaceHeader: spaceHeader,
} }
} }
@ -99,18 +106,22 @@ func TestDiffSyncer_Sync(t *testing.T) {
factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient { factory := spacesyncproto.ClientFactoryFunc(func(cc drpc.Conn) spacesyncproto.DRPCSpaceClient {
return clientMock return clientMock
}) })
delState := mock_deletionstate.NewMockDeletionState(ctrl)
spaceId := "spaceId" spaceId := "spaceId"
aclRootId := "aclRootId" aclRootId := "aclRootId"
l := logger.NewNamed(spaceId) l := logger.NewNamed(spaceId)
diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l) diffSyncer := newDiffSyncer(spaceId, diffMock, connectorMock, cacheMock, stMock, factory, l)
delState.EXPECT().AddObserver(gomock.Any())
diffSyncer.Init(delState)
t.Run("diff syncer sync simple", func(t *testing.T) { t.Run("diff syncer sync", func(t *testing.T) {
connectorMock.EXPECT(). connectorMock.EXPECT().
GetResponsiblePeers(gomock.Any(), spaceId). GetResponsiblePeers(gomock.Any(), spaceId).
Return([]peer.Peer{mockPeer{}}, nil) Return([]peer.Peer{mockPeer{}}, nil)
diffMock.EXPECT(). diffMock.EXPECT().
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
Return([]string{"new"}, []string{"changed"}, nil, nil) Return([]string{"new"}, []string{"changed"}, nil, nil)
delState.EXPECT().FilterJoin(gomock.Any()).Return([]string{"new", "changed"})
for _, arg := range []string{"new", "changed"} { for _, arg := range []string{"new", "changed"} {
cacheMock.EXPECT(). cacheMock.EXPECT().
GetTree(gomock.Any(), spaceId, arg). GetTree(gomock.Any(), spaceId, arg).
@ -127,12 +138,37 @@ func TestDiffSyncer_Sync(t *testing.T) {
require.Error(t, diffSyncer.Sync(ctx)) require.Error(t, diffSyncer.Sync(ctx))
}) })
t.Run("deletion state remove objects", func(t *testing.T) {
deletedId := "id"
delState.EXPECT().Exists(deletedId).Return(true)
// this should not result in any mock being called
diffSyncer.UpdateHeads(deletedId, []string{"someHead"})
})
t.Run("update heads updates diff", func(t *testing.T) {
newId := "newId"
newHeads := []string{"h1", "h2"}
diffMock.EXPECT().Set(ldiff.Element{
Id: newId,
Head: concatStrings(newHeads),
})
delState.EXPECT().Exists(newId).Return(false)
diffSyncer.UpdateHeads(newId, newHeads)
})
t.Run("diff syncer sync space missing", func(t *testing.T) { t.Run("diff syncer sync space missing", func(t *testing.T) {
aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl) aclStorageMock := mock_aclstorage.NewMockListStorage(ctrl)
settingsStorage := mock_treestorage.NewMockTreeStorage(ctrl)
settingsId := "settingsId"
aclRoot := &aclrecordproto.RawACLRecordWithId{ aclRoot := &aclrecordproto.RawACLRecordWithId{
Id: aclRootId, Id: aclRootId,
} }
settingsRoot := &treechangeproto.RawTreeChangeWithId{
Id: settingsId,
}
spaceHeader := &spacesyncproto.RawSpaceHeaderWithId{} spaceHeader := &spacesyncproto.RawSpaceHeaderWithId{}
spaceSettingsId := "spaceSettingsId"
connectorMock.EXPECT(). connectorMock.EXPECT().
GetResponsiblePeers(gomock.Any(), spaceId). GetResponsiblePeers(gomock.Any(), spaceId).
@ -140,17 +176,18 @@ func TestDiffSyncer_Sync(t *testing.T) {
diffMock.EXPECT(). diffMock.EXPECT().
Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))). Diff(gomock.Any(), gomock.Eq(remotediff.NewRemoteDiff(spaceId, clientMock))).
Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing) Return(nil, nil, nil, spacesyncproto.ErrSpaceMissing)
stMock.EXPECT().
ACLStorage(). stMock.EXPECT().ACLStorage().Return(aclStorageMock, nil)
Return(aclStorageMock, nil) stMock.EXPECT().SpaceHeader().Return(spaceHeader, nil)
stMock.EXPECT(). stMock.EXPECT().SpaceSettingsId().Return(spaceSettingsId)
SpaceHeader(). stMock.EXPECT().TreeStorage(spaceSettingsId).Return(settingsStorage, nil)
Return(spaceHeader, nil)
settingsStorage.EXPECT().Root().Return(settingsRoot, nil)
aclStorageMock.EXPECT(). aclStorageMock.EXPECT().
Root(). Root().
Return(aclRoot, nil) Return(aclRoot, nil)
clientMock.EXPECT(). clientMock.EXPECT().
PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRootId, spaceHeader)). PushSpace(gomock.Any(), newPushSpaceRequestMatcher(spaceId, aclRootId, settingsId, spaceHeader)).
Return(nil, nil) Return(nil, nil)
require.NoError(t, diffSyncer.Sync(ctx)) require.NoError(t, diffSyncer.Sync(ctx))

View File

@ -1,5 +0,0 @@
package diffservice
type HeadNotifiable interface {
UpdateHeads(id string, heads []string)
}

View File

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer,PeriodicSync) // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice (interfaces: DiffSyncer)
// Package mock_diffservice is a generated GoMock package. // Package mock_diffservice is a generated GoMock package.
package mock_diffservice package mock_diffservice
@ -8,6 +8,7 @@ import (
context "context" context "context"
reflect "reflect" reflect "reflect"
deletionstate "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
@ -34,6 +35,30 @@ func (m *MockDiffSyncer) EXPECT() *MockDiffSyncerMockRecorder {
return m.recorder return m.recorder
} }
// Init mocks base method.
func (m *MockDiffSyncer) Init(arg0 deletionstate.DeletionState) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Init", arg0)
}
// Init indicates an expected call of Init.
func (mr *MockDiffSyncerMockRecorder) Init(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockDiffSyncer)(nil).Init), arg0)
}
// RemoveObjects mocks base method.
func (m *MockDiffSyncer) RemoveObjects(arg0 []string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RemoveObjects", arg0)
}
// RemoveObjects indicates an expected call of RemoveObjects.
func (mr *MockDiffSyncerMockRecorder) RemoveObjects(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveObjects", reflect.TypeOf((*MockDiffSyncer)(nil).RemoveObjects), arg0)
}
// Sync mocks base method. // Sync mocks base method.
func (m *MockDiffSyncer) Sync(arg0 context.Context) error { func (m *MockDiffSyncer) Sync(arg0 context.Context) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -48,49 +73,14 @@ func (mr *MockDiffSyncerMockRecorder) Sync(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDiffSyncer)(nil).Sync), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sync", reflect.TypeOf((*MockDiffSyncer)(nil).Sync), arg0)
} }
// MockPeriodicSync is a mock of PeriodicSync interface. // UpdateHeads mocks base method.
type MockPeriodicSync struct { func (m *MockDiffSyncer) UpdateHeads(arg0 string, arg1 []string) {
ctrl *gomock.Controller
recorder *MockPeriodicSyncMockRecorder
}
// MockPeriodicSyncMockRecorder is the mock recorder for MockPeriodicSync.
type MockPeriodicSyncMockRecorder struct {
mock *MockPeriodicSync
}
// NewMockPeriodicSync creates a new mock instance.
func NewMockPeriodicSync(ctrl *gomock.Controller) *MockPeriodicSync {
mock := &MockPeriodicSync{ctrl: ctrl}
mock.recorder = &MockPeriodicSyncMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockPeriodicSync) EXPECT() *MockPeriodicSyncMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockPeriodicSync) Close() {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Close") m.ctrl.Call(m, "UpdateHeads", arg0, arg1)
} }
// Close indicates an expected call of Close. // UpdateHeads indicates an expected call of UpdateHeads.
func (mr *MockPeriodicSyncMockRecorder) Close() *gomock.Call { func (mr *MockDiffSyncerMockRecorder) UpdateHeads(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeriodicSync)(nil).Close)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateHeads", reflect.TypeOf((*MockDiffSyncer)(nil).UpdateHeads), arg0, arg1)
}
// Run mocks base method.
func (m *MockPeriodicSync) Run() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Run")
}
// Run indicates an expected call of Run.
func (mr *MockPeriodicSyncMockRecorder) Run() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockPeriodicSync)(nil).Run))
} }

View File

@ -3,7 +3,9 @@ package commonspace
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
aclrecordproto2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" aclrecordproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/cid"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
"hash/fnv" "hash/fnv"
@ -11,6 +13,11 @@ import (
"time" "time"
) )
const (
SpaceSettingsChangeType = "reserved.spacesettings"
SpaceDerivationScheme = "derivation.standard"
)
func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) { func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload storage.SpaceStorageCreatePayload, err error) {
// unmarshalling signing and encryption keys // unmarshalling signing and encryption keys
identity, err := payload.SigningKey.GetPublic().Raw() identity, err := payload.SigningKey.GetPublic().Raw()
@ -23,8 +30,8 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
} }
// preparing header and space id // preparing header and space id
bytes := make([]byte, 32) spaceHeaderSeed := make([]byte, 32)
_, err = rand.Read(bytes) _, err = rand.Read(spaceHeaderSeed)
if err != nil { if err != nil {
return return
} }
@ -33,7 +40,7 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
Timestamp: time.Now().UnixNano(), Timestamp: time.Now().UnixNano(),
SpaceType: payload.SpaceType, SpaceType: payload.SpaceType,
ReplicationKey: payload.ReplicationKey, ReplicationKey: payload.ReplicationKey,
Seed: bytes, Seed: spaceHeaderSeed,
} }
marshalled, err := header.Marshal() marshalled, err := header.Marshal()
if err != nil { if err != nil {
@ -68,12 +75,11 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
} }
// preparing acl // preparing acl
aclRoot := &aclrecordproto2.ACLRoot{ aclRoot := &aclrecordproto.ACLRoot{
Identity: identity, Identity: identity,
EncryptionKey: encPubKey, EncryptionKey: encPubKey,
SpaceId: spaceId, SpaceId: spaceId,
EncryptedReadKey: encReadKey, EncryptedReadKey: encReadKey,
DerivationScheme: "",
CurrentReadKeyHash: readKeyHash, CurrentReadKeyHash: readKeyHash,
Timestamp: time.Now().UnixNano(), Timestamp: time.Now().UnixNano(),
} }
@ -82,10 +88,31 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload st
return return
} }
builder := tree.NewChangeBuilder(common.NewKeychain(), nil)
spaceSettingsSeed := make([]byte, 32)
_, err = rand.Read(spaceSettingsSeed)
if err != nil {
return
}
_, settingsRoot, err := builder.BuildInitialContent(tree.InitialContent{
AclHeadId: rawWithId.Id,
Identity: aclRoot.Identity,
SigningKey: payload.SigningKey,
SpaceId: spaceId,
Seed: spaceSettingsSeed,
ChangeType: SpaceSettingsChangeType,
Timestamp: time.Now().UnixNano(),
})
if err != nil {
return
}
// creating storage // creating storage
storagePayload = storage.SpaceStorageCreatePayload{ storagePayload = storage.SpaceStorageCreatePayload{
RecWithId: rawWithId, AclWithId: rawWithId,
SpaceHeaderWithId: rawHeaderWithId, SpaceHeaderWithId: rawHeaderWithId,
SpaceSettingsWithId: settingsRoot,
} }
return return
} }
@ -144,7 +171,7 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload st
} }
// deriving and encrypting read key // deriving and encrypting read key
readKey, err := aclrecordproto2.ACLReadKeyDerive(signPrivKey, encPrivKey) readKey, err := aclrecordproto.ACLReadKeyDerive(signPrivKey, encPrivKey)
if err != nil { if err != nil {
return return
} }
@ -160,29 +187,41 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload st
} }
// preparing acl // preparing acl
aclRoot := &aclrecordproto2.ACLRoot{ aclRoot := &aclrecordproto.ACLRoot{
Identity: identity, Identity: identity,
EncryptionKey: encPubKey, EncryptionKey: encPubKey,
SpaceId: spaceId, SpaceId: spaceId,
EncryptedReadKey: encReadKey, EncryptedReadKey: encReadKey,
DerivationScheme: "", DerivationScheme: SpaceDerivationScheme,
CurrentReadKeyHash: readKeyHash, CurrentReadKeyHash: readKeyHash,
Timestamp: time.Now().UnixNano(),
} }
rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey) rawWithId, err := marshalACLRoot(aclRoot, payload.SigningKey)
if err != nil { if err != nil {
return return
} }
builder := tree.NewChangeBuilder(common.NewKeychain(), nil)
_, settingsRoot, err := builder.BuildInitialContent(tree.InitialContent{
AclHeadId: rawWithId.Id,
Identity: aclRoot.Identity,
SigningKey: payload.SigningKey,
SpaceId: spaceId,
ChangeType: SpaceSettingsChangeType,
})
if err != nil {
return
}
// creating storage // creating storage
storagePayload = storage.SpaceStorageCreatePayload{ storagePayload = storage.SpaceStorageCreatePayload{
RecWithId: rawWithId, AclWithId: rawWithId,
SpaceHeaderWithId: rawHeaderWithId, SpaceHeaderWithId: rawHeaderWithId,
SpaceSettingsWithId: settingsRoot,
} }
return return
} }
func marshalACLRoot(aclRoot *aclrecordproto2.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto2.RawACLRecordWithId, err error) { func marshalACLRoot(aclRoot *aclrecordproto.ACLRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawACLRecordWithId, err error) {
marshalledRoot, err := aclRoot.Marshal() marshalledRoot, err := aclRoot.Marshal()
if err != nil { if err != nil {
return return
@ -191,7 +230,7 @@ func marshalACLRoot(aclRoot *aclrecordproto2.ACLRoot, key signingkey.PrivKey) (r
if err != nil { if err != nil {
return return
} }
raw := &aclrecordproto2.RawACLRecord{ raw := &aclrecordproto.RawACLRecord{
Payload: marshalledRoot, Payload: marshalledRoot,
Signature: signature, Signature: signature,
} }
@ -203,7 +242,7 @@ func marshalACLRoot(aclRoot *aclrecordproto2.ACLRoot, key signingkey.PrivKey) (r
if err != nil { if err != nil {
return return
} }
rawWithId = &aclrecordproto2.RawACLRecordWithId{ rawWithId = &aclrecordproto.RawACLRecordWithId{
Payload: marshalledRaw, Payload: marshalledRaw,
Id: aclHeadId, Id: aclHeadId,
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
) )
const CName = "common.commonspace" const CName = "common.commonspace"
@ -25,11 +26,14 @@ func New() Service {
return &service{} return &service{}
} }
type ctxKey int
const AddSpaceCtxKey ctxKey = 0
type Service interface { type Service interface {
DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (string, error) DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (string, error)
CreateSpace(ctx context.Context, payload SpaceCreatePayload) (string, error) CreateSpace(ctx context.Context, payload SpaceCreatePayload) (string, error)
NewSpace(ctx context.Context, id string) (sp Space, err error) NewSpace(ctx context.Context, id string) (sp Space, err error)
AddSpace(ctx context.Context, spaceDescription SpaceDescription) (err error)
app.Component app.Component
} }
@ -82,47 +86,23 @@ func (s *service) DeriveSpace(ctx context.Context, payload SpaceDerivePayload) (
return store.Id(), nil return store.Id(), nil
} }
func (s *service) AddSpace(ctx context.Context, spaceDescription SpaceDescription) (err error) {
_, err = s.storageProvider.SpaceStorage(spaceDescription.SpaceHeader.Id)
if err == nil {
err = spacesyncproto.ErrSpaceExists
return
}
if err != storage.ErrSpaceStorageMissing {
err = spacesyncproto.ErrUnexpected
return
}
payload := storage.SpaceStorageCreatePayload{
RecWithId: &aclrecordproto.RawACLRecordWithId{
Payload: spaceDescription.AclPayload,
Id: spaceDescription.AclId,
},
SpaceHeaderWithId: spaceDescription.SpaceHeader,
}
st, err := s.storageProvider.CreateSpaceStorage(payload)
if err != nil {
err = spacesyncproto.ErrUnexpected
if err == storage.ErrSpaceStorageExists {
err = spacesyncproto.ErrSpaceExists
}
return
}
err = st.Close()
return
}
func (s *service) NewSpace(ctx context.Context, id string) (Space, error) { func (s *service) NewSpace(ctx context.Context, id string) (Space, error) {
st, err := s.storageProvider.SpaceStorage(id) st, err := s.storageProvider.SpaceStorage(id)
if err != nil { if err != nil {
if err != spacesyncproto.ErrSpaceMissing { if err != storage.ErrSpaceStorageMissing {
return nil, err return nil, err
} }
st, err = s.getSpaceStorageFromRemote(ctx, id) if description, ok := ctx.Value(AddSpaceCtxKey).(SpaceDescription); ok {
if err != nil { st, err = s.addSpaceStorage(ctx, description)
err = storage.ErrSpaceStorageMissing if err != nil {
return nil, err return nil, err
}
} else {
st, err = s.getSpaceStorageFromRemote(ctx, id)
if err != nil {
return nil, err
}
} }
} }
@ -142,10 +122,33 @@ func (s *service) NewSpace(ctx context.Context, id string) (Space, error) {
return sp, nil return sp, nil
} }
func (s *service) addSpaceStorage(ctx context.Context, spaceDescription SpaceDescription) (st storage.SpaceStorage, err error) {
payload := storage.SpaceStorageCreatePayload{
AclWithId: &aclrecordproto.RawACLRecordWithId{
Payload: spaceDescription.AclPayload,
Id: spaceDescription.AclId,
},
SpaceHeaderWithId: spaceDescription.SpaceHeader,
SpaceSettingsWithId: &treechangeproto.RawTreeChangeWithId{
RawChange: spaceDescription.SpaceSettingsPayload,
Id: spaceDescription.SpaceSettingsId,
},
}
st, err = s.storageProvider.CreateSpaceStorage(payload)
if err != nil {
err = spacesyncproto.ErrUnexpected
if err == storage.ErrSpaceStorageExists {
err = spacesyncproto.ErrSpaceExists
}
return
}
return
}
func (s *service) getSpaceStorageFromRemote(ctx context.Context, id string) (st storage.SpaceStorage, err error) { func (s *service) getSpaceStorageFromRemote(ctx context.Context, id string) (st storage.SpaceStorage, err error) {
var p peer.Peer var p peer.Peer
lastConfiguration := s.configurationService.GetLast() lastConfiguration := s.configurationService.GetLast()
// for nodes we always get remote space only if we have id in the context // we can't connect to client if it is a node
if lastConfiguration.IsResponsible(id) { if lastConfiguration.IsResponsible(id) {
err = spacesyncproto.ErrSpaceMissing err = spacesyncproto.ErrSpaceMissing
return return
@ -161,12 +164,17 @@ func (s *service) getSpaceStorageFromRemote(ctx context.Context, id string) (st
if err != nil { if err != nil {
return return
} }
st, err = s.storageProvider.CreateSpaceStorage(storage.SpaceStorageCreatePayload{ st, err = s.storageProvider.CreateSpaceStorage(storage.SpaceStorageCreatePayload{
RecWithId: &aclrecordproto.RawACLRecordWithId{ AclWithId: &aclrecordproto.RawACLRecordWithId{
Payload: res.AclPayload, Payload: res.Payload.AclPayload,
Id: res.AclPayloadId, Id: res.Payload.AclPayloadId,
}, },
SpaceHeaderWithId: res.SpaceHeader, SpaceSettingsWithId: &treechangeproto.RawTreeChangeWithId{
RawChange: res.Payload.SpaceSettingsPayload,
Id: res.Payload.SpaceSettingsPayloadId,
},
SpaceHeaderWithId: res.Payload.SpaceHeader,
}) })
return return
} }

View File

@ -0,0 +1,53 @@
package settingsdocument
import (
"context"
)
type deleteLoop struct {
deleteCtx context.Context
deleteCancel context.CancelFunc
deleteChan chan struct{}
deleteFunc func()
loopDone chan struct{}
}
func newDeleteLoop(deleteFunc func()) *deleteLoop {
ctx, cancel := context.WithCancel(context.Background())
return &deleteLoop{
deleteCtx: ctx,
deleteCancel: cancel,
deleteChan: make(chan struct{}, 1),
deleteFunc: deleteFunc,
loopDone: make(chan struct{}),
}
}
func (dl *deleteLoop) Run() {
go dl.loop()
}
func (dl *deleteLoop) loop() {
defer close(dl.loopDone)
dl.deleteFunc()
for {
select {
case <-dl.deleteCtx.Done():
return
case <-dl.deleteChan:
dl.deleteFunc()
}
}
}
func (dl *deleteLoop) notify() {
select {
case dl.deleteChan <- struct{}{}:
default:
}
}
func (dl *deleteLoop) Close() {
dl.deleteCancel()
<-dl.loopDone
}

View File

@ -0,0 +1,39 @@
package settingsdocument
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"go.uber.org/zap"
)
type Deleter interface {
Delete()
}
type deleter struct {
st storage.SpaceStorage
state deletionstate.DeletionState
getter treegetter.TreeGetter
}
func newDeleter(st storage.SpaceStorage, state deletionstate.DeletionState, getter treegetter.TreeGetter) Deleter {
return &deleter{st, state, getter}
}
func (d *deleter) Delete() {
allQueued := d.state.GetQueued()
for _, id := range allQueued {
err := d.getter.DeleteTree(context.Background(), d.st.Id(), id)
if err != nil && err != storage.ErrTreeStorageAlreadyDeleted {
log.With(zap.String("id", id), zap.Error(err)).Error("failed to delete object")
continue
}
err = d.state.Delete(id)
if err != nil {
log.With(zap.String("id", id), zap.Error(err)).Error("failed to mark object as deleted")
}
log.With(zap.String("id", id), zap.Error(err)).Debug("object successfully deleted")
}
}

View File

@ -0,0 +1,52 @@
package settingsdocument
import (
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter/mock_treegetter"
"github.com/golang/mock/gomock"
"testing"
)
func TestDeleter_Delete(t *testing.T) {
ctrl := gomock.NewController(t)
treeGetter := mock_treegetter.NewMockTreeGetter(ctrl)
st := mock_storage.NewMockSpaceStorage(ctrl)
delState := mock_deletionstate.NewMockDeletionState(ctrl)
deleter := newDeleter(st, delState, treeGetter)
t.Run("deleter delete queued", func(t *testing.T) {
id := "id"
spaceId := "spaceId"
delState.EXPECT().GetQueued().Return([]string{id})
st.EXPECT().Id().Return(spaceId)
treeGetter.EXPECT().DeleteTree(gomock.Any(), spaceId, id).Return(nil)
delState.EXPECT().Delete(id).Return(nil)
deleter.Delete()
})
t.Run("deleter delete already deleted", func(t *testing.T) {
id := "id"
spaceId := "spaceId"
delState.EXPECT().GetQueued().Return([]string{id})
st.EXPECT().Id().Return(spaceId)
treeGetter.EXPECT().DeleteTree(gomock.Any(), spaceId, id).Return(storage.ErrTreeStorageAlreadyDeleted)
delState.EXPECT().Delete(id).Return(nil)
deleter.Delete()
})
t.Run("deleter delete error", func(t *testing.T) {
id := "id"
spaceId := "spaceId"
delState.EXPECT().GetQueued().Return([]string{id})
st.EXPECT().Id().Return(spaceId)
treeGetter.EXPECT().DeleteTree(gomock.Any(), spaceId, id).Return(fmt.Errorf("some error"))
deleter.Delete()
})
}

View File

@ -0,0 +1,153 @@
//go:generate mockgen -destination mock_deletionstate/mock_deletionstate.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate DeletionState
package deletionstate
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"sync"
)
type StateUpdateObserver func(ids []string)
type DeletionState interface {
AddObserver(observer StateUpdateObserver)
Add(ids []string) (err error)
GetQueued() (ids []string)
Delete(id string) (err error)
Exists(id string) bool
FilterJoin(ids ...[]string) (filtered []string)
CreateDeleteChange(id string, isSnapshot bool) (res []byte, err error)
}
type deletionState struct {
sync.RWMutex
queued map[string]struct{}
deleted map[string]struct{}
stateUpdateObservers []StateUpdateObserver
storage storage.SpaceStorage
}
func NewDeletionState(storage storage.SpaceStorage) DeletionState {
return &deletionState{
queued: map[string]struct{}{},
deleted: map[string]struct{}{},
storage: storage,
}
}
func (st *deletionState) AddObserver(observer StateUpdateObserver) {
st.Lock()
defer st.Unlock()
st.stateUpdateObservers = append(st.stateUpdateObservers, observer)
}
func (st *deletionState) Add(ids []string) (err error) {
st.Lock()
defer func() {
st.Unlock()
if err != nil {
return
}
for _, ob := range st.stateUpdateObservers {
ob(ids)
}
}()
for _, id := range ids {
if _, exists := st.deleted[id]; exists {
continue
}
if _, exists := st.queued[id]; exists {
continue
}
var status string
status, err = st.storage.TreeDeletedStatus(id)
if err != nil {
return
}
switch status {
case storage.TreeDeletedStatusQueued:
st.queued[id] = struct{}{}
case storage.TreeDeletedStatusDeleted:
st.deleted[id] = struct{}{}
default:
st.queued[id] = struct{}{}
err = st.storage.SetTreeDeletedStatus(id, storage.TreeDeletedStatusQueued)
if err != nil {
return
}
}
}
return
}
func (st *deletionState) GetQueued() (ids []string) {
st.RLock()
defer st.RUnlock()
ids = make([]string, 0, len(st.queued))
for id := range st.queued {
ids = append(ids, id)
}
return
}
func (st *deletionState) Delete(id string) (err error) {
st.Lock()
defer st.Unlock()
delete(st.queued, id)
st.deleted[id] = struct{}{}
err = st.storage.SetTreeDeletedStatus(id, storage.TreeDeletedStatusDeleted)
if err != nil {
return
}
return
}
func (st *deletionState) Exists(id string) bool {
st.RLock()
defer st.RUnlock()
return st.exists(id)
}
func (st *deletionState) FilterJoin(ids ...[]string) (filtered []string) {
st.RLock()
defer st.RUnlock()
filter := func(ids []string) {
for _, id := range ids {
if !st.exists(id) {
filtered = append(filtered, id)
}
}
}
for _, arr := range ids {
filter(arr)
}
return
}
func (st *deletionState) CreateDeleteChange(id string, isSnapshot bool) (res []byte, err error) {
content := &spacesyncproto.SpaceSettingsContent_ObjectDelete{
ObjectDelete: &spacesyncproto.ObjectDelete{Id: id},
}
change := &spacesyncproto.SettingsData{
Content: []*spacesyncproto.SpaceSettingsContent{
{content},
},
Snapshot: nil,
}
// TODO: add snapshot logic
res, err = change.Marshal()
return
}
func (st *deletionState) exists(id string) bool {
if _, exists := st.deleted[id]; exists {
return true
}
if _, exists := st.queued[id]; exists {
return true
}
return false
}

View File

@ -0,0 +1,127 @@
package deletionstate
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing"
)
type fixture struct {
ctrl *gomock.Controller
delState *deletionState
spaceStorage *mock_storage.MockSpaceStorage
}
func newFixture(t *testing.T) *fixture {
ctrl := gomock.NewController(t)
spaceStorage := mock_storage.NewMockSpaceStorage(ctrl)
delState := NewDeletionState(spaceStorage).(*deletionState)
return &fixture{
ctrl: ctrl,
delState: delState,
spaceStorage: spaceStorage,
}
}
func (fx *fixture) stop() {
fx.ctrl.Finish()
}
func TestDeletionState_Add(t *testing.T) {
t.Run("add new", func(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, storage.TreeDeletedStatusQueued).Return(nil)
err := fx.delState.Add([]string{id})
require.NoError(t, err)
require.Contains(t, fx.delState.queued, id)
})
t.Run("add existing queued", func(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(storage.TreeDeletedStatusQueued, nil)
err := fx.delState.Add([]string{id})
require.NoError(t, err)
require.Contains(t, fx.delState.queued, id)
})
t.Run("add existing deleted", func(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return(storage.TreeDeletedStatusDeleted, nil)
err := fx.delState.Add([]string{id})
require.NoError(t, err)
require.Contains(t, fx.delState.deleted, id)
})
}
func TestDeletionState_GetQueued(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
fx.delState.queued["id1"] = struct{}{}
fx.delState.queued["id2"] = struct{}{}
queued := fx.delState.GetQueued()
require.Equal(t, []string{"id1", "id2"}, queued)
}
func TestDeletionState_FilterJoin(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
fx.delState.queued["id1"] = struct{}{}
fx.delState.queued["id2"] = struct{}{}
filtered := fx.delState.FilterJoin([]string{"id1"}, []string{"id3", "id2"}, []string{"id4"})
require.Equal(t, []string{"id3", "id4"}, filtered)
}
func TestDeletionState_AddObserver(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
var queued []string
fx.delState.AddObserver(func(ids []string) {
queued = ids
})
id := "newId"
fx.spaceStorage.EXPECT().TreeDeletedStatus(id).Return("", nil)
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, storage.TreeDeletedStatusQueued).Return(nil)
err := fx.delState.Add([]string{id})
require.NoError(t, err)
require.Contains(t, fx.delState.queued, id)
require.Equal(t, []string{id}, queued)
}
func TestDeletionState_Delete(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
id := "deletedId"
fx.delState.queued[id] = struct{}{}
fx.spaceStorage.EXPECT().SetTreeDeletedStatus(id, storage.TreeDeletedStatusDeleted).Return(nil)
err := fx.delState.Delete(id)
require.NoError(t, err)
require.Contains(t, fx.delState.deleted, id)
require.NotContains(t, fx.delState.queued, id)
}
func TestDeletionState_Exists(t *testing.T) {
fx := newFixture(t)
defer fx.stop()
fx.delState.queued["id1"] = struct{}{}
fx.delState.deleted["id2"] = struct{}{}
require.True(t, fx.delState.Exists("id1"))
require.True(t, fx.delState.Exists("id2"))
require.False(t, fx.delState.Exists("id3"))
}

View File

@ -0,0 +1,136 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate (interfaces: DeletionState)
// Package mock_deletionstate is a generated GoMock package.
package mock_deletionstate
import (
reflect "reflect"
deletionstate "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
gomock "github.com/golang/mock/gomock"
)
// MockDeletionState is a mock of DeletionState interface.
type MockDeletionState struct {
ctrl *gomock.Controller
recorder *MockDeletionStateMockRecorder
}
// MockDeletionStateMockRecorder is the mock recorder for MockDeletionState.
type MockDeletionStateMockRecorder struct {
mock *MockDeletionState
}
// NewMockDeletionState creates a new mock instance.
func NewMockDeletionState(ctrl *gomock.Controller) *MockDeletionState {
mock := &MockDeletionState{ctrl: ctrl}
mock.recorder = &MockDeletionStateMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDeletionState) EXPECT() *MockDeletionStateMockRecorder {
return m.recorder
}
// Add mocks base method.
func (m *MockDeletionState) Add(arg0 []string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Add", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Add indicates an expected call of Add.
func (mr *MockDeletionStateMockRecorder) Add(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockDeletionState)(nil).Add), arg0)
}
// AddObserver mocks base method.
func (m *MockDeletionState) AddObserver(arg0 deletionstate.StateUpdateObserver) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "AddObserver", arg0)
}
// AddObserver indicates an expected call of AddObserver.
func (mr *MockDeletionStateMockRecorder) AddObserver(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddObserver", reflect.TypeOf((*MockDeletionState)(nil).AddObserver), arg0)
}
// CreateDeleteChange mocks base method.
func (m *MockDeletionState) CreateDeleteChange(arg0 string, arg1 bool) ([]byte, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "CreateDeleteChange", arg0, arg1)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// CreateDeleteChange indicates an expected call of CreateDeleteChange.
func (mr *MockDeletionStateMockRecorder) CreateDeleteChange(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeleteChange", reflect.TypeOf((*MockDeletionState)(nil).CreateDeleteChange), arg0, arg1)
}
// Delete mocks base method.
func (m *MockDeletionState) Delete(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockDeletionStateMockRecorder) Delete(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDeletionState)(nil).Delete), arg0)
}
// Exists mocks base method.
func (m *MockDeletionState) Exists(arg0 string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Exists", arg0)
ret0, _ := ret[0].(bool)
return ret0
}
// Exists indicates an expected call of Exists.
func (mr *MockDeletionStateMockRecorder) Exists(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockDeletionState)(nil).Exists), arg0)
}
// FilterJoin mocks base method.
func (m *MockDeletionState) FilterJoin(arg0 ...[]string) []string {
m.ctrl.T.Helper()
varargs := []interface{}{}
for _, a := range arg0 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "FilterJoin", varargs...)
ret0, _ := ret[0].([]string)
return ret0
}
// FilterJoin indicates an expected call of FilterJoin.
func (mr *MockDeletionStateMockRecorder) FilterJoin(arg0 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterJoin", reflect.TypeOf((*MockDeletionState)(nil).FilterJoin), arg0...)
}
// GetQueued mocks base method.
func (m *MockDeletionState) GetQueued() []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetQueued")
ret0, _ := ret[0].([]string)
return ret0
}
// GetQueued indicates an expected call of GetQueued.
func (mr *MockDeletionStateMockRecorder) GetQueued() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQueued", reflect.TypeOf((*MockDeletionState)(nil).GetQueued))
}

View File

@ -0,0 +1,59 @@
package settingsdocument
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
"github.com/gogo/protobuf/proto"
)
type DeletedIdsProvider interface {
ProvideIds(tr tree.ObjectTree, startId string) (ids []string, lastId string, err error)
}
type provider struct{}
func (p *provider) processChange(change *tree.Change, rootId, startId string, ids []string) []string {
// ignoring root change which has empty model or startId change
if change.Model == nil || (change.Id == startId && startId != "") {
return ids
}
deleteChange := change.Model.(*spacesyncproto.SettingsData)
// getting data from snapshot if we start from it
if change.Id == rootId {
ids = deleteChange.Snapshot.DeletedIds
return ids
}
// otherwise getting data from content
for _, cnt := range deleteChange.Content {
if cnt.GetObjectDelete() != nil {
ids = append(ids, cnt.GetObjectDelete().GetId())
}
}
return ids
}
func (p *provider) ProvideIds(tr tree.ObjectTree, startId string) (ids []string, lastId string, err error) {
rootId := tr.Root().Id
process := func(change *tree.Change) bool {
lastId = change.Id
ids = p.processChange(change, rootId, startId, ids)
return true
}
convert := func(decrypted []byte) (res any, err error) {
deleteChange := &spacesyncproto.SettingsData{}
err = proto.Unmarshal(decrypted, deleteChange)
if err != nil {
return nil, err
}
return deleteChange, nil
}
if startId == "" {
err = tr.IterateFrom(tr.ID(), convert, process)
} else {
err = tr.IterateFrom(startId, convert, process)
}
return
}

View File

@ -0,0 +1,94 @@
package settingsdocument
import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
mock_tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree/mock_objecttree"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing"
)
func TestProvider_ProcessChange(t *testing.T) {
//ctrl := gomock.NewController(t)
//objTree := mock_tree.NewMockObjectTree(ctrl)
prov := &provider{}
//defer ctrl.Finish()
t.Run("empty model", func(t *testing.T) {
ch := &tree.Change{}
startId := "startId"
rootId := "rootId"
ids := []string{startId}
otherIds := prov.processChange(ch, rootId, startId, ids)
require.Equal(t, []string{startId}, otherIds)
})
t.Run("changeId is equal to startId", func(t *testing.T) {
ch := &tree.Change{}
ch.Model = &spacesyncproto.SettingsData{}
ch.Id = "startId"
startId := "startId"
rootId := "rootId"
ids := []string{startId}
otherIds := prov.processChange(ch, rootId, startId, ids)
require.Equal(t, []string{startId}, otherIds)
})
t.Run("changeId is equal to rootId, startId is empty", func(t *testing.T) {
ch := &tree.Change{}
ch.Model = &spacesyncproto.SettingsData{
Snapshot: &spacesyncproto.SpaceSettingsSnapshot{
DeletedIds: []string{"id1", "id2"},
},
}
ch.Id = "rootId"
startId := ""
rootId := "rootId"
otherIds := prov.processChange(ch, rootId, startId, nil)
require.Equal(t, []string{"id1", "id2"}, otherIds)
})
t.Run("changeId is equal to rootId, startId is empty", func(t *testing.T) {
ch := &tree.Change{}
ch.Model = &spacesyncproto.SettingsData{
Content: []*spacesyncproto.SpaceSettingsContent{
{&spacesyncproto.SpaceSettingsContent_ObjectDelete{
ObjectDelete: &spacesyncproto.ObjectDelete{Id: "id1"},
}},
},
}
ch.Id = "someId"
startId := "startId"
rootId := "rootId"
otherIds := prov.processChange(ch, rootId, startId, nil)
require.Equal(t, []string{"id1"}, otherIds)
})
}
func TestProvider_ProvideIds(t *testing.T) {
ctrl := gomock.NewController(t)
objTree := mock_tree.NewMockObjectTree(ctrl)
prov := &provider{}
defer ctrl.Finish()
t.Run("startId is empty", func(t *testing.T) {
ch := &tree.Change{Id: "rootId"}
objTree.EXPECT().Root().Return(ch)
objTree.EXPECT().ID().Return("id")
objTree.EXPECT().IterateFrom("id", gomock.Any(), gomock.Any()).Return(nil)
_, _, err := prov.ProvideIds(objTree, "")
require.NoError(t, err)
})
t.Run("startId is not empty", func(t *testing.T) {
ch := &tree.Change{Id: "rootId"}
objTree.EXPECT().Root().Return(ch)
objTree.EXPECT().IterateFrom("startId", gomock.Any(), gomock.Any()).Return(nil)
_, _, err := prov.ProvideIds(objTree, "startId")
require.NoError(t, err)
})
}

View File

@ -0,0 +1,86 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument (interfaces: DeletedIdsProvider,Deleter)
// Package mock_settingsdocument is a generated GoMock package.
package mock_settingsdocument
import (
reflect "reflect"
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
gomock "github.com/golang/mock/gomock"
)
// MockDeletedIdsProvider is a mock of DeletedIdsProvider interface.
type MockDeletedIdsProvider struct {
ctrl *gomock.Controller
recorder *MockDeletedIdsProviderMockRecorder
}
// MockDeletedIdsProviderMockRecorder is the mock recorder for MockDeletedIdsProvider.
type MockDeletedIdsProviderMockRecorder struct {
mock *MockDeletedIdsProvider
}
// NewMockDeletedIdsProvider creates a new mock instance.
func NewMockDeletedIdsProvider(ctrl *gomock.Controller) *MockDeletedIdsProvider {
mock := &MockDeletedIdsProvider{ctrl: ctrl}
mock.recorder = &MockDeletedIdsProviderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDeletedIdsProvider) EXPECT() *MockDeletedIdsProviderMockRecorder {
return m.recorder
}
// ProvideIds mocks base method.
func (m *MockDeletedIdsProvider) ProvideIds(arg0 tree.ObjectTree, arg1 string) ([]string, string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ProvideIds", arg0, arg1)
ret0, _ := ret[0].([]string)
ret1, _ := ret[1].(string)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// ProvideIds indicates an expected call of ProvideIds.
func (mr *MockDeletedIdsProviderMockRecorder) ProvideIds(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProvideIds", reflect.TypeOf((*MockDeletedIdsProvider)(nil).ProvideIds), arg0, arg1)
}
// MockDeleter is a mock of Deleter interface.
type MockDeleter struct {
ctrl *gomock.Controller
recorder *MockDeleterMockRecorder
}
// MockDeleterMockRecorder is the mock recorder for MockDeleter.
type MockDeleterMockRecorder struct {
mock *MockDeleter
}
// NewMockDeleter creates a new mock instance.
func NewMockDeleter(ctrl *gomock.Controller) *MockDeleter {
mock := &MockDeleter{ctrl: ctrl}
mock.recorder = &MockDeleterMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockDeleter) EXPECT() *MockDeleterMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockDeleter) Delete() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Delete")
}
// Delete indicates an expected call of Delete.
func (mr *MockDeleterMockRecorder) Delete() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockDeleter)(nil).Delete))
}

View File

@ -0,0 +1,173 @@
//go:generate mockgen -destination mock_settingsdocument/mock_settingsdocument.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument DeletedIdsProvider,Deleter
package settingsdocument
import (
"context"
"errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
"go.uber.org/zap"
)
var log = logger.NewNamed("commonspace.settingsdocument")
type SettingsDocument interface {
synctree.SyncTree
Init(ctx context.Context) (err error)
DeleteObject(id string) (err error)
}
var (
ErrDeleteSelf = errors.New("cannot delete seld")
ErrAlreadyDeleted = errors.New("the document is already deleted")
ErrDocDoesNotExist = errors.New("the document does not exist")
)
type BuildTreeFunc func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error)
type Deps struct {
BuildFunc BuildTreeFunc
Account account.Service
TreeGetter treegetter.TreeGetter
Store spacestorage.SpaceStorage
DeletionState deletionstate.DeletionState
// testing dependencies
prov DeletedIdsProvider
del Deleter
}
type settingsDocument struct {
synctree.SyncTree
account account.Service
spaceId string
treeGetter treegetter.TreeGetter
store spacestorage.SpaceStorage
prov DeletedIdsProvider
buildFunc BuildTreeFunc
loop *deleteLoop
deletionState deletionstate.DeletionState
lastChangeId string
}
func NewSettingsDocument(deps Deps, spaceId string) (doc SettingsDocument) {
var deleter Deleter
if deps.del == nil {
deleter = newDeleter(deps.Store, deps.DeletionState, deps.TreeGetter)
} else {
deleter = deps.del
}
loop := newDeleteLoop(func() {
deleter.Delete()
})
deps.DeletionState.AddObserver(func(ids []string) {
loop.notify()
})
s := &settingsDocument{
loop: loop,
spaceId: spaceId,
account: deps.Account,
deletionState: deps.DeletionState,
treeGetter: deps.TreeGetter,
store: deps.Store,
buildFunc: deps.BuildFunc,
}
// this is needed mainly for testing
if deps.prov == nil {
s.prov = &provider{}
} else {
s.prov = deps.prov
}
doc = s
return
}
func (s *settingsDocument) updateIds(tr tree.ObjectTree, lastChangeId string) {
s.lastChangeId = lastChangeId
ids, lastId, err := s.prov.ProvideIds(tr, s.lastChangeId)
if err != nil {
log.With(zap.Strings("ids", ids), zap.Error(err)).Error("failed to update state")
return
}
s.lastChangeId = lastId
if err = s.deletionState.Add(ids); err != nil {
log.With(zap.Strings("ids", ids), zap.Error(err)).Error("failed to queue ids to delete")
}
}
// Update is called as part of UpdateListener interface
func (s *settingsDocument) Update(tr tree.ObjectTree) {
s.updateIds(tr, s.lastChangeId)
}
// Rebuild is called as part of UpdateListener interface (including when the object is built for the first time, e.g. on Init call)
func (s *settingsDocument) Rebuild(tr tree.ObjectTree) {
// at initial build "s" may not contain the object tree, so it is safer to provide it from the function parameter
s.updateIds(tr, "")
}
func (s *settingsDocument) Init(ctx context.Context) (err error) {
settingsId := s.store.SpaceSettingsId()
log.Debug("space settings id", zap.String("id", settingsId))
s.SyncTree, err = s.buildFunc(ctx, settingsId, s)
if err != nil {
return
}
s.loop.Run()
return
}
func (s *settingsDocument) Close() error {
s.loop.Close()
return s.SyncTree.Close()
}
func (s *settingsDocument) DeleteObject(id string) (err error) {
s.Lock()
defer s.Unlock()
if s.ID() == id {
err = ErrDeleteSelf
return
}
if s.deletionState.Exists(id) {
err = ErrAlreadyDeleted
return nil
}
_, err = s.store.TreeStorage(id)
if err != nil {
err = ErrDocDoesNotExist
return
}
// TODO: add snapshot logic
res, err := s.deletionState.CreateDeleteChange(id, false)
if err != nil {
return
}
accountData := s.account.Account()
_, err = s.AddContent(context.Background(), tree.SignableChangeContent{
Data: res,
Key: accountData.SignKey,
Identity: accountData.Identity,
IsSnapshot: false,
IsEncrypted: false,
})
if err != nil {
return
}
s.Update(s)
return
}

View File

@ -0,0 +1,190 @@
package settingsdocument
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account/mock_account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate/mock_deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/mock_settingsdocument"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter/mock_treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"sync"
"testing"
"time"
)
type testSyncTreeMock struct {
*mock_synctree.MockSyncTree
m sync.Mutex
}
func newTestObjMock(mockTree *mock_synctree.MockSyncTree) *testSyncTreeMock {
return &testSyncTreeMock{
MockSyncTree: mockTree,
}
}
func (t *testSyncTreeMock) Lock() {
t.m.Lock()
}
func (t *testSyncTreeMock) Unlock() {
t.m.Unlock()
}
type settingsFixture struct {
spaceId string
docId string
doc *settingsDocument
ctrl *gomock.Controller
treeGetter *mock_treegetter.MockTreeGetter
spaceStorage *mock_storage.MockSpaceStorage
provider *mock_settingsdocument.MockDeletedIdsProvider
deleter *mock_settingsdocument.MockDeleter
syncTree *mock_synctree.MockSyncTree
delState *mock_deletionstate.MockDeletionState
account *mock_account.MockService
}
func newSettingsFixture(t *testing.T) *settingsFixture {
spaceId := "spaceId"
docId := "documentId"
ctrl := gomock.NewController(t)
acc := mock_account.NewMockService(ctrl)
treeGetter := mock_treegetter.NewMockTreeGetter(ctrl)
st := mock_storage.NewMockSpaceStorage(ctrl)
delState := mock_deletionstate.NewMockDeletionState(ctrl)
prov := mock_settingsdocument.NewMockDeletedIdsProvider(ctrl)
syncTree := mock_synctree.NewMockSyncTree(ctrl)
del := mock_settingsdocument.NewMockDeleter(ctrl)
delState.EXPECT().AddObserver(gomock.Any())
buildFunc := BuildTreeFunc(func(ctx context.Context, id string, listener updatelistener.UpdateListener) (synctree.SyncTree, error) {
require.Equal(t, docId, id)
return newTestObjMock(syncTree), nil
})
deps := Deps{
BuildFunc: buildFunc,
Account: acc,
TreeGetter: treeGetter,
Store: st,
DeletionState: delState,
prov: prov,
del: del,
}
doc := NewSettingsDocument(deps, spaceId).(*settingsDocument)
return &settingsFixture{
spaceId: spaceId,
docId: docId,
doc: doc,
ctrl: ctrl,
treeGetter: treeGetter,
spaceStorage: st,
provider: prov,
deleter: del,
syncTree: syncTree,
account: acc,
delState: delState,
}
}
func (fx *settingsFixture) stop() {
fx.ctrl.Finish()
}
func TestSettingsDocument_Init(t *testing.T) {
fx := newSettingsFixture(t)
defer fx.stop()
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
fx.deleter.EXPECT().Delete()
fx.syncTree.EXPECT().Close().Return(nil)
err := fx.doc.Init(context.Background())
require.NoError(t, err)
err = fx.doc.Close()
require.NoError(t, err)
}
func TestSettingsDocument_DeleteObject(t *testing.T) {
fx := newSettingsFixture(t)
defer fx.stop()
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
fx.deleter.EXPECT().Delete()
err := fx.doc.Init(context.Background())
require.NoError(t, err)
time.Sleep(100 * time.Millisecond)
delId := "delId"
fx.syncTree.EXPECT().ID().Return("syncId")
fx.delState.EXPECT().Exists(delId).Return(false)
fx.spaceStorage.EXPECT().TreeStorage(delId).Return(nil, nil)
res := []byte("settingsData")
fx.delState.EXPECT().CreateDeleteChange(delId, false).Return(res, nil)
accountData := &account.AccountData{
Identity: []byte("id"),
PeerKey: nil,
SignKey: &signingkey.Ed25519PrivateKey{},
EncKey: nil,
}
fx.account.EXPECT().Account().Return(accountData)
fx.syncTree.EXPECT().AddContent(gomock.Any(), tree.SignableChangeContent{
Data: res,
Key: accountData.SignKey,
Identity: accountData.Identity,
IsSnapshot: false,
IsEncrypted: false,
}).Return(tree.AddResult{}, nil)
lastChangeId := "someId"
retIds := []string{"id1", "id2"}
fx.doc.lastChangeId = lastChangeId
fx.provider.EXPECT().ProvideIds(gomock.Not(nil), lastChangeId).Return(retIds, retIds[len(retIds)-1], nil)
fx.delState.EXPECT().Add(retIds).Return(nil)
err = fx.doc.DeleteObject(delId)
require.NoError(t, err)
require.Equal(t, retIds[len(retIds)-1], fx.doc.lastChangeId)
fx.syncTree.EXPECT().Close().Return(nil)
err = fx.doc.Close()
require.NoError(t, err)
}
func TestSettingsDocument_Rebuild(t *testing.T) {
fx := newSettingsFixture(t)
defer fx.stop()
fx.spaceStorage.EXPECT().SpaceSettingsId().Return(fx.docId)
fx.deleter.EXPECT().Delete()
err := fx.doc.Init(context.Background())
require.NoError(t, err)
time.Sleep(100 * time.Millisecond)
lastChangeId := "someId"
retIds := []string{"id1", "id2"}
fx.doc.lastChangeId = lastChangeId
fx.provider.EXPECT().ProvideIds(gomock.Not(nil), "").Return(retIds, retIds[len(retIds)-1], nil)
fx.delState.EXPECT().Add(retIds).Return(nil)
fx.doc.Rebuild(fx.doc)
require.Equal(t, retIds[len(retIds)-1], fx.doc.lastChangeId)
fx.syncTree.EXPECT().Close().Return(nil)
err = fx.doc.Close()
require.NoError(t, err)
}

View File

@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/settingsdocument/deletionstate"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncacl" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncacl"
@ -16,6 +18,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/encryptionkey"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/asymmetric/signingkey"
"github.com/zeebo/errs" "github.com/zeebo/errs"
@ -48,9 +51,11 @@ type SpaceDerivePayload struct {
} }
type SpaceDescription struct { type SpaceDescription struct {
SpaceHeader *spacesyncproto.RawSpaceHeaderWithId SpaceHeader *spacesyncproto.RawSpaceHeaderWithId
AclId string AclId string
AclPayload []byte AclPayload []byte
SpaceSettingsId string
SpaceSettingsPayload []byte
} }
func NewSpaceId(id string, repKey uint64) string { func NewSpaceId(id string, repKey uint64) string {
@ -58,17 +63,22 @@ func NewSpaceId(id string, repKey uint64) string {
} }
type Space interface { type Space interface {
ocache.ObjectLocker
ocache.ObjectLastUsage
Id() string Id() string
Init(ctx context.Context) error Init(ctx context.Context) error
StoredIds() []string StoredIds() []string
Description() SpaceDescription DebugAllHeads() []diffservice.TreeHeads
Description() (SpaceDescription, error)
SpaceSyncRpc() RpcHandler SpaceSyncRpc() RpcHandler
DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload) (string, error)
CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tree.ObjectTree, error) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload) (string, error)
BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree.ObjectTree, error) BuildTree(ctx context.Context, id string, listener updatelistener.UpdateListener) (tree.ObjectTree, error)
DeleteTree(ctx context.Context, id string) (err error)
Close() error Close() error
} }
@ -80,35 +90,58 @@ type space struct {
rpc *rpcHandler rpc *rpcHandler
syncService syncservice.SyncService syncService syncservice.SyncService
diffService diffservice.DiffService diffService diffservice.DiffService
storage storage.SpaceStorage storage storage.SpaceStorage
cache treegetter.TreeGetter cache treegetter.TreeGetter
account account.Service account account.Service
aclList *syncacl.SyncACL aclList *syncacl.SyncACL
configuration nodeconf.Configuration configuration nodeconf.Configuration
settingsDocument settingsdocument.SettingsDocument
isClosed atomic.Bool isClosed atomic.Bool
treesUsed atomic.Int32
} }
func (s *space) LastUsage() time.Time { func (s *space) LastUsage() time.Time {
return s.syncService.LastUsage() return s.syncService.LastUsage()
} }
func (s *space) Locked() bool {
locked := s.treesUsed.Load() > 1
log.With(zap.Int32("trees used", s.treesUsed.Load()), zap.Bool("locked", locked)).Debug("space lock status check")
return locked
}
func (s *space) Id() string { func (s *space) Id() string {
return s.id return s.id
} }
func (s *space) Description() SpaceDescription { func (s *space) Description() (desc SpaceDescription, err error) {
root := s.aclList.Root() root := s.aclList.Root()
return SpaceDescription{ settingsStorage, err := s.storage.TreeStorage(s.storage.SpaceSettingsId())
SpaceHeader: s.header, if err != nil {
AclId: root.Id, return
AclPayload: root.Payload,
} }
settingsRoot, err := settingsStorage.Root()
if err != nil {
return
}
desc = SpaceDescription{
SpaceHeader: s.header,
AclId: root.Id,
AclPayload: root.Payload,
SpaceSettingsId: settingsRoot.Id,
SpaceSettingsPayload: settingsRoot.RawChange,
}
return
} }
func (s *space) Init(ctx context.Context) (err error) { func (s *space) Init(ctx context.Context) (err error) {
log.With(zap.String("spaceId", s.id)).Debug("initializing space")
s.storage = newCommonStorage(s.storage)
header, err := s.storage.SpaceHeader() header, err := s.storage.SpaceHeader()
if err != nil { if err != nil {
return return
@ -128,9 +161,32 @@ func (s *space) Init(ctx context.Context) (err error) {
return return
} }
s.aclList = syncacl.NewSyncACL(aclList, s.syncService.StreamPool()) s.aclList = syncacl.NewSyncACL(aclList, s.syncService.StreamPool())
objectGetter := newCommonSpaceGetter(s.id, s.aclList, s.cache)
deletionState := deletionstate.NewDeletionState(s.storage)
deps := settingsdocument.Deps{
BuildFunc: func(ctx context.Context, id string, listener updatelistener.UpdateListener) (t synctree.SyncTree, err error) {
res, err := s.BuildTree(ctx, id, listener)
if err != nil {
return
}
t = res.(synctree.SyncTree)
return
},
Account: s.account,
TreeGetter: s.cache,
Store: s.storage,
DeletionState: deletionState,
}
s.settingsDocument = settingsdocument.NewSettingsDocument(deps, s.id)
objectGetter := newCommonSpaceGetter(s.id, s.aclList, s.cache, s.settingsDocument)
s.syncService.Init(objectGetter) s.syncService.Init(objectGetter)
s.diffService.Init(initialIds) s.diffService.Init(initialIds, deletionState)
err = s.settingsDocument.Init(ctx)
if err != nil {
return
}
return nil return nil
} }
@ -150,38 +206,38 @@ func (s *space) StoredIds() []string {
return s.diffService.AllIds() return s.diffService.AllIds()
} }
func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) { func (s *space) DebugAllHeads() []diffservice.TreeHeads {
return s.diffService.DebugAllHeads()
}
func (s *space) DeriveTree(ctx context.Context, payload tree.ObjectTreeCreatePayload) (id string, err error) {
if s.isClosed.Load() { if s.isClosed.Load() {
err = ErrSpaceClosed err = ErrSpaceClosed
return return
} }
deps := synctree.CreateDeps{ deps := synctree.CreateDeps{
SpaceId: s.id, SpaceId: s.id,
Payload: payload, Payload: payload,
StreamPool: s.syncService.StreamPool(), StreamPool: s.syncService.StreamPool(),
Configuration: s.configuration, Configuration: s.configuration,
HeadNotifiable: s.diffService, AclList: s.aclList,
Listener: listener, SpaceStorage: s.storage,
AclList: s.aclList,
CreateStorage: s.storage.CreateTreeStorage,
} }
return synctree.DeriveSyncTree(ctx, deps) return synctree.DeriveSyncTree(ctx, deps)
} }
func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload, listener updatelistener.UpdateListener) (tr tree.ObjectTree, err error) { func (s *space) CreateTree(ctx context.Context, payload tree.ObjectTreeCreatePayload) (id string, err error) {
if s.isClosed.Load() { if s.isClosed.Load() {
err = ErrSpaceClosed err = ErrSpaceClosed
return return
} }
deps := synctree.CreateDeps{ deps := synctree.CreateDeps{
SpaceId: s.id, SpaceId: s.id,
Payload: payload, Payload: payload,
StreamPool: s.syncService.StreamPool(), StreamPool: s.syncService.StreamPool(),
Configuration: s.configuration, Configuration: s.configuration,
HeadNotifiable: s.diffService, AclList: s.aclList,
Listener: listener, SpaceStorage: s.storage,
AclList: s.aclList,
CreateStorage: s.storage.CreateTreeStorage,
} }
return synctree.CreateSyncTree(ctx, deps) return synctree.CreateSyncTree(ctx, deps)
} }
@ -199,10 +255,15 @@ func (s *space) BuildTree(ctx context.Context, id string, listener updatelistene
Listener: listener, Listener: listener,
AclList: s.aclList, AclList: s.aclList,
SpaceStorage: s.storage, SpaceStorage: s.storage,
TreeUsage: &s.treesUsed,
} }
return synctree.BuildSyncTreeOrGetRemote(ctx, id, deps) return synctree.BuildSyncTreeOrGetRemote(ctx, id, deps)
} }
func (s *space) DeleteTree(ctx context.Context, id string) (err error) {
return s.settingsDocument.DeleteObject(id)
}
func (s *space) Close() error { func (s *space) Close() error {
log.With(zap.String("id", s.id)).Debug("space is closing") log.With(zap.String("id", s.id)).Debug("space is closing")
defer func() { defer func() {
@ -216,6 +277,9 @@ func (s *space) Close() error {
if err := s.syncService.Close(); err != nil { if err := s.syncService.Close(); err != nil {
mError.Add(err) mError.Add(err)
} }
if err := s.settingsDocument.Close(); err != nil {
mError.Add(err)
}
if err := s.aclList.Close(); err != nil { if err := s.aclList.Close(); err != nil {
mError.Add(err) mError.Add(err)
} }

View File

@ -64,9 +64,7 @@ message ObjectSyncMessage {
// PushSpaceRequest is a request to add space on a node containing only one acl record // PushSpaceRequest is a request to add space on a node containing only one acl record
message PushSpaceRequest { message PushSpaceRequest {
RawSpaceHeaderWithId spaceHeader = 1; SpacePayload payload = 1;
bytes aclPayload = 2;
string aclPayloadId = 3;
} }
// PushSpaceResponse is an empty response // PushSpaceResponse is an empty response
@ -79,9 +77,15 @@ message PullSpaceRequest {
// PullSpaceResponse is a response with header and acl root // PullSpaceResponse is a response with header and acl root
message PullSpaceResponse { message PullSpaceResponse {
SpacePayload payload = 1;
}
message SpacePayload {
RawSpaceHeaderWithId spaceHeader = 1; RawSpaceHeaderWithId spaceHeader = 1;
bytes aclPayload = 2; bytes aclPayload = 2;
string aclPayloadId = 3; string aclPayloadId = 3;
bytes spaceSettingsPayload = 4;
string spaceSettingsPayloadId = 5;
} }
// SpaceHeader is a header for a space // SpaceHeader is a header for a space
@ -102,3 +106,23 @@ message RawSpaceHeaderWithId {
bytes rawHeader = 1; bytes rawHeader = 1;
string id = 2; string id = 2;
} }
message SpaceSettingsContent {
oneof value {
ObjectDelete objectDelete = 1;
}
}
message ObjectDelete {
string id = 1;
}
message SpaceSettingsSnapshot {
repeated string deletedIds = 1;
}
message SettingsData {
repeated SpaceSettingsContent content = 1;
SpaceSettingsSnapshot snapshot = 2;
}

File diff suppressed because it is too large Load Diff

View File

@ -176,6 +176,20 @@ func (mr *MockSpaceStorageMockRecorder) Id() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockSpaceStorage)(nil).Id)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockSpaceStorage)(nil).Id))
} }
// SetTreeDeletedStatus mocks base method.
func (m *MockSpaceStorage) SetTreeDeletedStatus(arg0, arg1 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetTreeDeletedStatus", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// SetTreeDeletedStatus indicates an expected call of SetTreeDeletedStatus.
func (mr *MockSpaceStorageMockRecorder) SetTreeDeletedStatus(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTreeDeletedStatus", reflect.TypeOf((*MockSpaceStorage)(nil).SetTreeDeletedStatus), arg0, arg1)
}
// SpaceHeader mocks base method. // SpaceHeader mocks base method.
func (m *MockSpaceStorage) SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error) { func (m *MockSpaceStorage) SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -191,6 +205,20 @@ func (mr *MockSpaceStorageMockRecorder) SpaceHeader() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceHeader", reflect.TypeOf((*MockSpaceStorage)(nil).SpaceHeader)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceHeader", reflect.TypeOf((*MockSpaceStorage)(nil).SpaceHeader))
} }
// SpaceSettingsId mocks base method.
func (m *MockSpaceStorage) SpaceSettingsId() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SpaceSettingsId")
ret0, _ := ret[0].(string)
return ret0
}
// SpaceSettingsId indicates an expected call of SpaceSettingsId.
func (mr *MockSpaceStorageMockRecorder) SpaceSettingsId() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SpaceSettingsId", reflect.TypeOf((*MockSpaceStorage)(nil).SpaceSettingsId))
}
// StoredIds mocks base method. // StoredIds mocks base method.
func (m *MockSpaceStorage) StoredIds() ([]string, error) { func (m *MockSpaceStorage) StoredIds() ([]string, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -206,6 +234,21 @@ func (mr *MockSpaceStorageMockRecorder) StoredIds() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoredIds", reflect.TypeOf((*MockSpaceStorage)(nil).StoredIds)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StoredIds", reflect.TypeOf((*MockSpaceStorage)(nil).StoredIds))
} }
// TreeDeletedStatus mocks base method.
func (m *MockSpaceStorage) TreeDeletedStatus(arg0 string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TreeDeletedStatus", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// TreeDeletedStatus indicates an expected call of TreeDeletedStatus.
func (mr *MockSpaceStorageMockRecorder) TreeDeletedStatus(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TreeDeletedStatus", reflect.TypeOf((*MockSpaceStorage)(nil).TreeDeletedStatus), arg0)
}
// TreeStorage mocks base method. // TreeStorage mocks base method.
func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage0.TreeStorage, error) { func (m *MockSpaceStorage) TreeStorage(arg0 string) (storage0.TreeStorage, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -7,16 +7,29 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/aclrecordproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
) )
const CName = "commonspace.storage" const CName = "commonspace.storage"
var ErrSpaceStorageExists = errors.New("space storage exists") var (
var ErrSpaceStorageMissing = errors.New("space storage missing") ErrSpaceStorageExists = errors.New("space storage exists")
ErrSpaceStorageMissing = errors.New("space storage missing")
ErrTreeStorageAlreadyDeleted = errors.New("tree storage already deleted")
)
const (
TreeDeletedStatusQueued = "queued"
TreeDeletedStatusDeleted = "deleted"
)
type SpaceStorage interface { type SpaceStorage interface {
storage.Provider storage.Provider
Id() string Id() string
SetTreeDeletedStatus(id, state string) error
TreeDeletedStatus(id string) (string, error)
SpaceSettingsId() string
ACLStorage() (storage.ListStorage, error) ACLStorage() (storage.ListStorage, error)
SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error) SpaceHeader() (*spacesyncproto.RawSpaceHeaderWithId, error)
StoredIds() ([]string, error) StoredIds() ([]string, error)
@ -24,8 +37,9 @@ type SpaceStorage interface {
} }
type SpaceStorageCreatePayload struct { type SpaceStorageCreatePayload struct {
RecWithId *aclrecordproto.RawACLRecordWithId AclWithId *aclrecordproto.RawACLRecordWithId
SpaceHeaderWithId *spacesyncproto.RawSpaceHeaderWithId SpaceHeaderWithId *spacesyncproto.RawSpaceHeaderWithId
SpaceSettingsWithId *treechangeproto.RawTreeChangeWithId
} }
type SpaceStorageProvider interface { type SpaceStorageProvider interface {
@ -33,3 +47,8 @@ type SpaceStorageProvider interface {
SpaceStorage(id string) (SpaceStorage, error) SpaceStorage(id string) (SpaceStorage, error)
CreateSpaceStorage(payload SpaceStorageCreatePayload) (SpaceStorage, error) CreateSpaceStorage(payload SpaceStorageCreatePayload) (SpaceStorage, error)
} }
func ValidateSpaceStorageCreatePayload(payload SpaceStorageCreatePayload) (err error) {
// TODO: add proper validation
return nil
}

View File

@ -9,6 +9,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/rpcerr"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/ocache"
"go.uber.org/zap"
"time" "time"
) )
@ -36,6 +37,7 @@ type syncService struct {
stopStreamLoop context.CancelFunc stopStreamLoop context.CancelFunc
connector nodeconf.ConfConnector connector nodeconf.ConfConnector
streamLoopDone chan struct{} streamLoopDone chan struct{}
log *zap.SugaredLogger // TODO: change to logger
} }
func NewSyncService( func NewSyncService(
@ -62,6 +64,7 @@ func newSyncService(
connector: connector, connector: connector,
clientFactory: clientFactory, clientFactory: clientFactory,
spaceId: spaceId, spaceId: spaceId,
log: log.With(zap.String("id", spaceId)),
streamLoopDone: make(chan struct{}), streamLoopDone: make(chan struct{}),
} }
} }
@ -83,6 +86,7 @@ func (s *syncService) LastUsage() time.Time {
} }
func (s *syncService) HandleMessage(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) { func (s *syncService) HandleMessage(ctx context.Context, senderId string, message *spacesyncproto.ObjectSyncMessage) (err error) {
s.log.With(zap.String("peerId", senderId), zap.String("objectId", message.ObjectId)).Debug("handling message")
obj, err := s.objectGetter.GetObject(ctx, message.ObjectId) obj, err := s.objectGetter.GetObject(ctx, message.ObjectId)
if err != nil { if err != nil {
return return
@ -93,18 +97,28 @@ func (s *syncService) HandleMessage(ctx context.Context, senderId string, messag
func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) { func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
defer close(s.streamLoopDone) defer close(s.streamLoopDone)
checkResponsiblePeers := func() { checkResponsiblePeers := func() {
respPeers, err := s.connector.DialResponsiblePeers(ctx, s.spaceId) var (
if err != nil { activeNodeIds []string
return configuration = s.connector.Configuration()
} )
for _, p := range respPeers { for _, nodeId := range configuration.NodeIds(s.spaceId) {
if s.streamPool.HasActiveStream(p.Id()) { if s.streamPool.HasActiveStream(nodeId) {
s.log.Debug("has active stream for", zap.String("id", nodeId))
activeNodeIds = append(activeNodeIds, nodeId)
continue continue
} }
}
newPeers, err := s.connector.DialInactiveResponsiblePeers(ctx, s.spaceId, activeNodeIds)
if err != nil {
s.log.Error("failed to dial peers", zap.Error(err))
return
}
for _, p := range newPeers {
stream, err := s.clientFactory.Client(p).Stream(ctx) stream, err := s.clientFactory.Client(p).Stream(ctx)
if err != nil { if err != nil {
err = rpcerr.Unwrap(err) err = rpcerr.Unwrap(err)
log.With("spaceId", s.spaceId).Errorf("failed to open stream: %v", err) s.log.Errorf("failed to open stream: %v", err)
// so here probably the request is failed because there is no such space, // so here probably the request is failed because there is no such space,
// but diffService should handle such cases by sending pushSpace // but diffService should handle such cases by sending pushSpace
continue continue
@ -113,9 +127,10 @@ func (s *syncService) responsibleStreamCheckLoop(ctx context.Context) {
err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId}) err = stream.Send(&spacesyncproto.ObjectSyncMessage{SpaceId: s.spaceId})
if err != nil { if err != nil {
err = rpcerr.Unwrap(err) err = rpcerr.Unwrap(err)
log.With("spaceId", s.spaceId).Errorf("failed to send first message to stream: %v", err) s.log.Errorf("failed to send first message to stream: %v", err)
continue continue
} }
s.log.Debug("reading stream for", zap.String("id", p.Id()))
s.streamPool.AddAndReadStreamAsync(stream) s.streamPool.AddAndReadStreamAsync(stream)
} }
} }

View File

@ -1,12 +1,15 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree (interfaces: SyncClient) // Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree (interfaces: SyncClient,SyncTree)
// Package mock_synctree is a generated GoMock package. // Package mock_synctree is a generated GoMock package.
package mock_synctree package mock_synctree
import ( import (
context "context"
reflect "reflect" reflect "reflect"
spacesyncproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
storage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree" tree "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/tree"
treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" treechangeproto "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
@ -134,3 +137,325 @@ func (mr *MockSyncClientMockRecorder) SendAsync(arg0, arg1, arg2 interface{}) *g
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1, arg2) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendAsync", reflect.TypeOf((*MockSyncClient)(nil).SendAsync), arg0, arg1, arg2)
} }
// MockSyncTree is a mock of SyncTree interface.
type MockSyncTree struct {
ctrl *gomock.Controller
recorder *MockSyncTreeMockRecorder
}
// MockSyncTreeMockRecorder is the mock recorder for MockSyncTree.
type MockSyncTreeMockRecorder struct {
mock *MockSyncTree
}
// NewMockSyncTree creates a new mock instance.
func NewMockSyncTree(ctrl *gomock.Controller) *MockSyncTree {
mock := &MockSyncTree{ctrl: ctrl}
mock.recorder = &MockSyncTreeMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSyncTree) EXPECT() *MockSyncTreeMockRecorder {
return m.recorder
}
// AddContent mocks base method.
func (m *MockSyncTree) AddContent(arg0 context.Context, arg1 tree.SignableChangeContent) (tree.AddResult, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddContent", arg0, arg1)
ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddContent indicates an expected call of AddContent.
func (mr *MockSyncTreeMockRecorder) AddContent(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddContent", reflect.TypeOf((*MockSyncTree)(nil).AddContent), arg0, arg1)
}
// AddRawChanges mocks base method.
func (m *MockSyncTree) AddRawChanges(arg0 context.Context, arg1 ...*treechangeproto.RawTreeChangeWithId) (tree.AddResult, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddRawChanges", varargs...)
ret0, _ := ret[0].(tree.AddResult)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddRawChanges indicates an expected call of AddRawChanges.
func (mr *MockSyncTreeMockRecorder) AddRawChanges(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChanges", reflect.TypeOf((*MockSyncTree)(nil).AddRawChanges), varargs...)
}
// ChangesAfterCommonSnapshot mocks base method.
func (m *MockSyncTree) ChangesAfterCommonSnapshot(arg0, arg1 []string) ([]*treechangeproto.RawTreeChangeWithId, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ChangesAfterCommonSnapshot", arg0, arg1)
ret0, _ := ret[0].([]*treechangeproto.RawTreeChangeWithId)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ChangesAfterCommonSnapshot indicates an expected call of ChangesAfterCommonSnapshot.
func (mr *MockSyncTreeMockRecorder) ChangesAfterCommonSnapshot(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangesAfterCommonSnapshot", reflect.TypeOf((*MockSyncTree)(nil).ChangesAfterCommonSnapshot), arg0, arg1)
}
// Close mocks base method.
func (m *MockSyncTree) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockSyncTreeMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSyncTree)(nil).Close))
}
// DebugDump mocks base method.
func (m *MockSyncTree) DebugDump() (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DebugDump")
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DebugDump indicates an expected call of DebugDump.
func (mr *MockSyncTreeMockRecorder) DebugDump() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockSyncTree)(nil).DebugDump))
}
// Delete mocks base method.
func (m *MockSyncTree) Delete() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete")
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockSyncTreeMockRecorder) Delete() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockSyncTree)(nil).Delete))
}
// HandleMessage mocks base method.
func (m *MockSyncTree) HandleMessage(arg0 context.Context, arg1 string, arg2 *spacesyncproto.ObjectSyncMessage) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "HandleMessage", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// HandleMessage indicates an expected call of HandleMessage.
func (mr *MockSyncTreeMockRecorder) HandleMessage(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleMessage", reflect.TypeOf((*MockSyncTree)(nil).HandleMessage), arg0, arg1, arg2)
}
// HasChanges mocks base method.
func (m *MockSyncTree) HasChanges(arg0 ...string) bool {
m.ctrl.T.Helper()
varargs := []interface{}{}
for _, a := range arg0 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "HasChanges", varargs...)
ret0, _ := ret[0].(bool)
return ret0
}
// HasChanges indicates an expected call of HasChanges.
func (mr *MockSyncTreeMockRecorder) HasChanges(arg0 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasChanges", reflect.TypeOf((*MockSyncTree)(nil).HasChanges), arg0...)
}
// Header mocks base method.
func (m *MockSyncTree) Header() *treechangeproto.RawTreeChangeWithId {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Header")
ret0, _ := ret[0].(*treechangeproto.RawTreeChangeWithId)
return ret0
}
// Header indicates an expected call of Header.
func (mr *MockSyncTreeMockRecorder) Header() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockSyncTree)(nil).Header))
}
// Heads mocks base method.
func (m *MockSyncTree) Heads() []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Heads")
ret0, _ := ret[0].([]string)
return ret0
}
// Heads indicates an expected call of Heads.
func (mr *MockSyncTreeMockRecorder) Heads() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Heads", reflect.TypeOf((*MockSyncTree)(nil).Heads))
}
// ID mocks base method.
func (m *MockSyncTree) ID() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ID")
ret0, _ := ret[0].(string)
return ret0
}
// ID indicates an expected call of ID.
func (mr *MockSyncTreeMockRecorder) ID() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockSyncTree)(nil).ID))
}
// Iterate mocks base method.
func (m *MockSyncTree) Iterate(arg0 func([]byte) (interface{}, error), arg1 func(*tree.Change) bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Iterate", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// Iterate indicates an expected call of Iterate.
func (mr *MockSyncTreeMockRecorder) Iterate(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockSyncTree)(nil).Iterate), arg0, arg1)
}
// IterateFrom mocks base method.
func (m *MockSyncTree) IterateFrom(arg0 string, arg1 func([]byte) (interface{}, error), arg2 func(*tree.Change) bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IterateFrom", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// IterateFrom indicates an expected call of IterateFrom.
func (mr *MockSyncTreeMockRecorder) IterateFrom(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockSyncTree)(nil).IterateFrom), arg0, arg1, arg2)
}
// Lock mocks base method.
func (m *MockSyncTree) Lock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Lock")
}
// Lock indicates an expected call of Lock.
func (mr *MockSyncTreeMockRecorder) Lock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lock", reflect.TypeOf((*MockSyncTree)(nil).Lock))
}
// Ping mocks base method.
func (m *MockSyncTree) Ping() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Ping")
ret0, _ := ret[0].(error)
return ret0
}
// Ping indicates an expected call of Ping.
func (mr *MockSyncTreeMockRecorder) Ping() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockSyncTree)(nil).Ping))
}
// RLock mocks base method.
func (m *MockSyncTree) RLock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RLock")
}
// RLock indicates an expected call of RLock.
func (mr *MockSyncTreeMockRecorder) RLock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RLock", reflect.TypeOf((*MockSyncTree)(nil).RLock))
}
// RUnlock mocks base method.
func (m *MockSyncTree) RUnlock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RUnlock")
}
// RUnlock indicates an expected call of RUnlock.
func (mr *MockSyncTreeMockRecorder) RUnlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RUnlock", reflect.TypeOf((*MockSyncTree)(nil).RUnlock))
}
// Root mocks base method.
func (m *MockSyncTree) Root() *tree.Change {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Root")
ret0, _ := ret[0].(*tree.Change)
return ret0
}
// Root indicates an expected call of Root.
func (mr *MockSyncTreeMockRecorder) Root() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Root", reflect.TypeOf((*MockSyncTree)(nil).Root))
}
// SnapshotPath mocks base method.
func (m *MockSyncTree) SnapshotPath() []string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SnapshotPath")
ret0, _ := ret[0].([]string)
return ret0
}
// SnapshotPath indicates an expected call of SnapshotPath.
func (mr *MockSyncTreeMockRecorder) SnapshotPath() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SnapshotPath", reflect.TypeOf((*MockSyncTree)(nil).SnapshotPath))
}
// Storage mocks base method.
func (m *MockSyncTree) Storage() storage.TreeStorage {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Storage")
ret0, _ := ret[0].(storage.TreeStorage)
return ret0
}
// Storage indicates an expected call of Storage.
func (mr *MockSyncTreeMockRecorder) Storage() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Storage", reflect.TypeOf((*MockSyncTree)(nil).Storage))
}
// Unlock mocks base method.
func (m *MockSyncTree) Unlock() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Unlock")
}
// Unlock indicates an expected call of Unlock.
func (mr *MockSyncTreeMockRecorder) Unlock() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockSyncTree)(nil).Unlock))
}

View File

@ -1,8 +1,7 @@
//go:generate mockgen -destination mock_synctree/mock_synctree.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree SyncClient //go:generate mockgen -destination mock_synctree/mock_synctree.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree SyncClient,SyncTree
package synctree package synctree
import ( import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/spacesyncproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
@ -20,27 +19,23 @@ type syncClient struct {
syncservice.StreamPool syncservice.StreamPool
RequestFactory RequestFactory
spaceId string spaceId string
notifiable diffservice.HeadNotifiable
configuration nodeconf.Configuration configuration nodeconf.Configuration
} }
func newSyncClient( func newSyncClient(
spaceId string, spaceId string,
pool syncservice.StreamPool, pool syncservice.StreamPool,
notifiable diffservice.HeadNotifiable,
factory RequestFactory, factory RequestFactory,
configuration nodeconf.Configuration) SyncClient { configuration nodeconf.Configuration) SyncClient {
return &syncClient{ return &syncClient{
StreamPool: pool, StreamPool: pool,
RequestFactory: factory, RequestFactory: factory,
notifiable: notifiable,
configuration: configuration, configuration: configuration,
spaceId: spaceId, spaceId: spaceId,
} }
} }
func (s *syncClient) BroadcastAsync(message *treechangeproto.TreeSyncMessage) (err error) { func (s *syncClient) BroadcastAsync(message *treechangeproto.TreeSyncMessage) (err error) {
s.notifyIfNeeded(message)
objMsg, err := marshallTreeMessage(message, message.RootChange.Id, "") objMsg, err := marshallTreeMessage(message, message.RootChange.Id, "")
if err != nil { if err != nil {
return return
@ -57,7 +52,6 @@ func (s *syncClient) SendAsync(peerId string, message *treechangeproto.TreeSyncM
} }
func (s *syncClient) BroadcastAsyncOrSendResponsible(message *treechangeproto.TreeSyncMessage) (err error) { func (s *syncClient) BroadcastAsyncOrSendResponsible(message *treechangeproto.TreeSyncMessage) (err error) {
s.notifyIfNeeded(message)
objMsg, err := marshallTreeMessage(message, message.RootChange.Id, "") objMsg, err := marshallTreeMessage(message, message.RootChange.Id, "")
if err != nil { if err != nil {
return return
@ -68,13 +62,6 @@ func (s *syncClient) BroadcastAsyncOrSendResponsible(message *treechangeproto.Tr
return s.BroadcastAsync(message) return s.BroadcastAsync(message)
} }
func (s *syncClient) notifyIfNeeded(message *treechangeproto.TreeSyncMessage) {
if message.GetContent().GetHeadUpdate() != nil {
update := message.GetContent().GetHeadUpdate()
s.notifiable.UpdateHeads(message.RootChange.Id, update.Heads)
}
}
func marshallTreeMessage(message *treechangeproto.TreeSyncMessage, id, replyId string) (objMsg *spacesyncproto.ObjectSyncMessage, err error) { func marshallTreeMessage(message *treechangeproto.TreeSyncMessage, id, replyId string) (objMsg *spacesyncproto.ObjectSyncMessage, err error) {
payload, err := message.Marshal() payload, err := message.Marshal()
if err != nil { if err != nil {

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice"
spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage" spacestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice/synchandler"
@ -18,17 +17,34 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
"go.uber.org/zap" "go.uber.org/zap"
"sync/atomic"
) )
var ErrSyncTreeClosed = errors.New("sync tree is closed") var (
ErrSyncTreeClosed = errors.New("sync tree is closed")
ErrSyncTreeDeleted = errors.New("sync tree is deleted")
)
type HeadNotifiable interface {
UpdateHeads(id string, heads []string)
}
type SyncTree interface {
tree.ObjectTree
synchandler.SyncHandler
Ping() (err error)
}
// SyncTree sends head updates to sync service and also sends new changes to update listener // SyncTree sends head updates to sync service and also sends new changes to update listener
type SyncTree struct { type syncTree struct {
tree.ObjectTree tree.ObjectTree
synchandler.SyncHandler synchandler.SyncHandler
syncClient SyncClient syncClient SyncClient
notifiable HeadNotifiable
listener updatelistener.UpdateListener listener updatelistener.UpdateListener
treeUsage *atomic.Int32
isClosed bool isClosed bool
isDeleted bool
} }
var log = logger.NewNamed("commonspace.synctree").Sugar() var log = logger.NewNamed("commonspace.synctree").Sugar()
@ -39,78 +55,62 @@ var buildObjectTree = tree.BuildObjectTree
var createSyncClient = newSyncClient var createSyncClient = newSyncClient
type CreateDeps struct { type CreateDeps struct {
SpaceId string SpaceId string
Payload tree.ObjectTreeCreatePayload Payload tree.ObjectTreeCreatePayload
Configuration nodeconf.Configuration Configuration nodeconf.Configuration
HeadNotifiable diffservice.HeadNotifiable StreamPool syncservice.StreamPool
StreamPool syncservice.StreamPool AclList list.ACLList
Listener updatelistener.UpdateListener SpaceStorage spacestorage.SpaceStorage
AclList list.ACLList
CreateStorage storage.TreeStorageCreatorFunc
} }
type BuildDeps struct { type BuildDeps struct {
SpaceId string SpaceId string
StreamPool syncservice.StreamPool StreamPool syncservice.StreamPool
Configuration nodeconf.Configuration Configuration nodeconf.Configuration
HeadNotifiable diffservice.HeadNotifiable HeadNotifiable HeadNotifiable
Listener updatelistener.UpdateListener Listener updatelistener.UpdateListener
AclList list.ACLList AclList list.ACLList
SpaceStorage spacestorage.SpaceStorage SpaceStorage spacestorage.SpaceStorage
TreeStorage storage.TreeStorage TreeStorage storage.TreeStorage
TreeUsage *atomic.Int32
} }
func DeriveSyncTree(ctx context.Context, deps CreateDeps) (t tree.ObjectTree, err error) { func DeriveSyncTree(ctx context.Context, deps CreateDeps) (id string, err error) {
t, err = createDerivedObjectTree(deps.Payload, deps.AclList, deps.CreateStorage) objTree, err := createDerivedObjectTree(deps.Payload, deps.AclList, deps.SpaceStorage.CreateTreeStorage)
if err != nil { if err != nil {
return return
} }
syncClient := createSyncClient( syncClient := createSyncClient(
deps.SpaceId, deps.SpaceId,
deps.StreamPool, deps.StreamPool,
deps.HeadNotifiable,
sharedFactory, sharedFactory,
deps.Configuration) deps.Configuration)
syncTree := &SyncTree{
ObjectTree: t,
syncClient: syncClient,
listener: deps.Listener,
}
syncHandler := newSyncTreeHandler(syncTree, syncClient)
syncTree.SyncHandler = syncHandler
t = syncTree
headUpdate := syncClient.CreateHeadUpdate(t, nil) headUpdate := syncClient.CreateHeadUpdate(objTree, nil)
err = syncClient.BroadcastAsync(headUpdate) syncClient.BroadcastAsync(headUpdate)
id = objTree.ID()
return return
} }
func CreateSyncTree(ctx context.Context, deps CreateDeps) (t tree.ObjectTree, err error) { func CreateSyncTree(ctx context.Context, deps CreateDeps) (id string, err error) {
t, err = createObjectTree(deps.Payload, deps.AclList, deps.CreateStorage) objTree, err := createObjectTree(deps.Payload, deps.AclList, deps.SpaceStorage.CreateTreeStorage)
if err != nil { if err != nil {
return return
} }
syncClient := createSyncClient( syncClient := createSyncClient(
deps.SpaceId, deps.SpaceId,
deps.StreamPool, deps.StreamPool,
deps.HeadNotifiable,
GetRequestFactory(), GetRequestFactory(),
deps.Configuration) deps.Configuration)
syncTree := &SyncTree{
ObjectTree: t,
syncClient: syncClient,
listener: deps.Listener,
}
syncHandler := newSyncTreeHandler(syncTree, syncClient)
syncTree.SyncHandler = syncHandler
t = syncTree
headUpdate := syncClient.CreateHeadUpdate(t, nil) headUpdate := syncClient.CreateHeadUpdate(objTree, nil)
err = syncClient.BroadcastAsync(headUpdate) syncClient.BroadcastAsync(headUpdate)
id = objTree.ID()
return return
} }
func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t tree.ObjectTree, err error) { func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t SyncTree, err error) {
getTreeRemote := func() (msg *treechangeproto.TreeSyncMessage, err error) { getTreeRemote := func() (msg *treechangeproto.TreeSyncMessage, err error) {
peerId, err := peer.CtxPeerId(ctx) peerId, err := peer.CtxPeerId(ctx)
if err != nil { if err != nil {
@ -140,6 +140,15 @@ func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t
return return
} }
status, err := deps.SpaceStorage.TreeDeletedStatus(id)
if err != nil {
return
}
if status != "" {
err = spacestorage.ErrTreeStorageAlreadyDeleted
return
}
resp, err := getTreeRemote() resp, err := getTreeRemote()
if err != nil { if err != nil {
return return
@ -170,56 +179,71 @@ func BuildSyncTreeOrGetRemote(ctx context.Context, id string, deps BuildDeps) (t
return buildSyncTree(ctx, true, deps) return buildSyncTree(ctx, true, deps)
} }
func buildSyncTree(ctx context.Context, isFirstBuild bool, deps BuildDeps) (t tree.ObjectTree, err error) { func buildSyncTree(ctx context.Context, isFirstBuild bool, deps BuildDeps) (t SyncTree, err error) {
objTree, err := buildObjectTree(deps.TreeStorage, deps.AclList)
t, err = buildObjectTree(deps.TreeStorage, deps.AclList)
if err != nil { if err != nil {
return return
} }
syncClient := createSyncClient( syncClient := createSyncClient(
deps.SpaceId, deps.SpaceId,
deps.StreamPool, deps.StreamPool,
deps.HeadNotifiable,
GetRequestFactory(), GetRequestFactory(),
deps.Configuration) deps.Configuration)
syncTree := &SyncTree{ syncTree := &syncTree{
ObjectTree: t, ObjectTree: objTree,
syncClient: syncClient, syncClient: syncClient,
notifiable: deps.HeadNotifiable,
treeUsage: deps.TreeUsage,
listener: deps.Listener, listener: deps.Listener,
} }
syncHandler := newSyncTreeHandler(syncTree, syncClient) syncHandler := newSyncTreeHandler(syncTree, syncClient)
syncTree.SyncHandler = syncHandler syncTree.SyncHandler = syncHandler
t = syncTree t = syncTree
syncTree.Lock()
defer syncTree.Unlock()
syncTree.afterBuild()
headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil) headUpdate := syncTree.syncClient.CreateHeadUpdate(t, nil)
// here we will have different behaviour based on who is sending this update // here we will have different behaviour based on who is sending this update
if isFirstBuild { if isFirstBuild {
// send to everybody, because everybody should know that the node or client got new tree // send to everybody, because everybody should know that the node or client got new tree
err = syncTree.syncClient.BroadcastAsync(headUpdate) err = syncTree.syncClient.BroadcastAsync(headUpdate)
} else {
// send either to everybody if client or to replica set if node
err = syncTree.syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
} }
return return
} }
func (s *SyncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) { func (s *syncTree) IterateFrom(id string, convert tree.ChangeConvertFunc, iterate tree.ChangeIterateFunc) (err error) {
if s.isClosed { if err = s.checkAlive(); err != nil {
err = ErrSyncTreeClosed return
}
return s.ObjectTree.IterateFrom(id, convert, iterate)
}
func (s *syncTree) Iterate(convert tree.ChangeConvertFunc, iterate tree.ChangeIterateFunc) (err error) {
if err = s.checkAlive(); err != nil {
return
}
return s.ObjectTree.Iterate(convert, iterate)
}
func (s *syncTree) AddContent(ctx context.Context, content tree.SignableChangeContent) (res tree.AddResult, err error) {
if err = s.checkAlive(); err != nil {
return return
} }
res, err = s.ObjectTree.AddContent(ctx, content) res, err = s.ObjectTree.AddContent(ctx, content)
if err != nil { if err != nil {
return return
} }
if s.notifiable != nil {
s.notifiable.UpdateHeads(s.ID(), res.Heads)
}
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added) headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
err = s.syncClient.BroadcastAsync(headUpdate) err = s.syncClient.BroadcastAsync(headUpdate)
return return
} }
func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) { func (s *syncTree) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (res tree.AddResult, err error) {
if s.isClosed { if err = s.checkAlive(); err != nil {
err = ErrSyncTreeClosed
return return
} }
res, err = s.ObjectTree.AddRawChanges(ctx, changes...) res, err = s.ObjectTree.AddRawChanges(ctx, changes...)
@ -236,22 +260,64 @@ func (s *SyncTree) AddRawChanges(ctx context.Context, changes ...*treechangeprot
s.listener.Rebuild(s) s.listener.Rebuild(s)
} }
} }
//if res.Mode != tree.Nothing { if res.Mode != tree.Nothing {
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added) if s.notifiable != nil {
err = s.syncClient.BroadcastAsync(headUpdate) s.notifiable.UpdateHeads(s.ID(), res.Heads)
//} }
headUpdate := s.syncClient.CreateHeadUpdate(s, res.Added)
err = s.syncClient.BroadcastAsync(headUpdate)
}
return return
} }
func (s *SyncTree) Close() (err error) { func (s *syncTree) Delete() (err error) {
log.With("id", s.ID()).Debug("deleting sync tree")
s.Lock()
defer s.Unlock()
if err = s.checkAlive(); err != nil {
return
}
err = s.ObjectTree.Delete()
if err != nil {
return
}
s.isDeleted = true
return
}
func (s *syncTree) Close() (err error) {
log.With("id", s.ID()).Debug("closing sync tree") log.With("id", s.ID()).Debug("closing sync tree")
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
log.With("id", s.ID()).Debug("taken lock on sync tree")
if s.isClosed { if s.isClosed {
err = ErrSyncTreeClosed return ErrSyncTreeClosed
return
} }
s.treeUsage.Add(-1)
s.isClosed = true s.isClosed = true
return return
} }
func (s *syncTree) checkAlive() (err error) {
if s.isClosed {
err = ErrSyncTreeClosed
}
if s.isDeleted {
err = ErrSyncTreeDeleted
}
return
}
func (s *syncTree) Ping() (err error) {
headUpdate := s.syncClient.CreateHeadUpdate(s, nil)
return s.syncClient.BroadcastAsyncOrSendResponsible(headUpdate)
}
func (s *syncTree) afterBuild() {
if s.listener != nil {
s.listener.Rebuild(s)
}
s.treeUsage.Add(1)
if s.notifiable != nil {
s.notifiable.UpdateHeads(s.ID(), s.Heads())
}
}

View File

@ -2,7 +2,7 @@ package synctree
import ( import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/storage/mock_storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/syncservice"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/mock_synctree"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/synctree/updatelistener"
@ -26,7 +26,7 @@ type syncTreeMatcher struct {
} }
func (s syncTreeMatcher) Matches(x interface{}) bool { func (s syncTreeMatcher) Matches(x interface{}) bool {
t, ok := x.(*SyncTree) t, ok := x.(*syncTree)
if !ok { if !ok {
return false return false
} }
@ -42,10 +42,10 @@ func Test_DeriveSyncTree(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_synctree.NewMockSyncClient(ctrl) syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl) aclListMock := mock_list.NewMockACLList(ctrl)
objTreeMock := mock_tree.NewMockObjectTree(ctrl) objTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
spaceStorageMock := mock_storage.NewMockSpaceStorage(ctrl)
spaceId := "spaceId" spaceId := "spaceId"
expectedPayload := tree.ObjectTreeCreatePayload{SpaceId: spaceId} expectedPayload := tree.ObjectTreeCreatePayload{SpaceId: spaceId}
createDerivedObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) { createDerivedObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
@ -53,13 +53,18 @@ func Test_DeriveSyncTree(t *testing.T) {
require.Equal(t, expectedPayload, payload) require.Equal(t, expectedPayload, payload)
return objTreeMock, nil return objTreeMock, nil
} }
createSyncClient = func(spaceId string, pool syncservice.StreamPool, notifiable diffservice.HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient { createSyncClient = func(spaceId string, pool syncservice.StreamPool, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
return syncClientMock return syncClientMock
} }
headUpdate := &treechangeproto.TreeSyncMessage{} headUpdate := &treechangeproto.TreeSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate) syncClientMock.EXPECT().CreateHeadUpdate(gomock.Any(), gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
deps := CreateDeps{AclList: aclListMock, SpaceId: spaceId, Payload: expectedPayload, Listener: updateListenerMock} deps := CreateDeps{
AclList: aclListMock,
SpaceId: spaceId,
Payload: expectedPayload,
SpaceStorage: spaceStorageMock,
}
_, err := DeriveSyncTree(ctx, deps) _, err := DeriveSyncTree(ctx, deps)
require.NoError(t, err) require.NoError(t, err)
@ -70,10 +75,10 @@ func Test_CreateSyncTree(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_synctree.NewMockSyncClient(ctrl) syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
aclListMock := mock_list.NewMockACLList(ctrl) aclListMock := mock_list.NewMockACLList(ctrl)
objTreeMock := mock_tree.NewMockObjectTree(ctrl) objTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
spaceStorageMock := mock_storage.NewMockSpaceStorage(ctrl)
spaceId := "spaceId" spaceId := "spaceId"
expectedPayload := tree.ObjectTreeCreatePayload{SpaceId: spaceId} expectedPayload := tree.ObjectTreeCreatePayload{SpaceId: spaceId}
createObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) { createObjectTree = func(payload tree.ObjectTreeCreatePayload, l list.ACLList, create storage2.TreeStorageCreatorFunc) (objTree tree.ObjectTree, err error) {
@ -81,13 +86,18 @@ func Test_CreateSyncTree(t *testing.T) {
require.Equal(t, expectedPayload, payload) require.Equal(t, expectedPayload, payload)
return objTreeMock, nil return objTreeMock, nil
} }
createSyncClient = func(spaceId string, pool syncservice.StreamPool, notifiable diffservice.HeadNotifiable, factory RequestFactory, configuration nodeconf.Configuration) SyncClient { createSyncClient = func(spaceId string, pool syncservice.StreamPool, factory RequestFactory, configuration nodeconf.Configuration) SyncClient {
return syncClientMock return syncClientMock
} }
headUpdate := &treechangeproto.TreeSyncMessage{} headUpdate := &treechangeproto.TreeSyncMessage{}
syncClientMock.EXPECT().CreateHeadUpdate(syncTreeMatcher{objTreeMock, syncClientMock, updateListenerMock}, gomock.Nil()).Return(headUpdate) syncClientMock.EXPECT().CreateHeadUpdate(gomock.Any(), gomock.Nil()).Return(headUpdate)
syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil) syncClientMock.EXPECT().BroadcastAsync(gomock.Eq(headUpdate)).Return(nil)
deps := CreateDeps{AclList: aclListMock, SpaceId: spaceId, Payload: expectedPayload, Listener: updateListenerMock} deps := CreateDeps{
AclList: aclListMock,
SpaceId: spaceId,
Payload: expectedPayload,
SpaceStorage: spaceStorageMock,
}
_, err := CreateSyncTree(ctx, deps) _, err := CreateSyncTree(ctx, deps)
require.NoError(t, err) require.NoError(t, err)
@ -100,8 +110,8 @@ func Test_BuildSyncTree(t *testing.T) {
updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl) updateListenerMock := mock_updatelistener.NewMockUpdateListener(ctrl)
syncClientMock := mock_synctree.NewMockSyncClient(ctrl) syncClientMock := mock_synctree.NewMockSyncClient(ctrl)
objTreeMock := mock_tree.NewMockObjectTree(ctrl) objTreeMock := newTestObjMock(mock_tree.NewMockObjectTree(ctrl))
tr := &SyncTree{ tr := &syncTree{
ObjectTree: objTreeMock, ObjectTree: objTreeMock,
SyncHandler: nil, SyncHandler: nil,
syncClient: syncClientMock, syncClient: syncClientMock,

View File

@ -50,6 +50,20 @@ func (mr *MockTreeGetterMockRecorder) Close(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeGetter)(nil).Close), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockTreeGetter)(nil).Close), arg0)
} }
// DeleteTree mocks base method.
func (m *MockTreeGetter) DeleteTree(arg0 context.Context, arg1, arg2 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteTree", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteTree indicates an expected call of DeleteTree.
func (mr *MockTreeGetterMockRecorder) DeleteTree(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTree", reflect.TypeOf((*MockTreeGetter)(nil).DeleteTree), arg0, arg1, arg2)
}
// GetTree mocks base method. // GetTree mocks base method.
func (m *MockTreeGetter) GetTree(arg0 context.Context, arg1, arg2 string) (tree.ObjectTree, error) { func (m *MockTreeGetter) GetTree(arg0 context.Context, arg1, arg2 string) (tree.ObjectTree, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -15,4 +15,5 @@ var ErrSpaceNotFound = errors.New("space not found")
type TreeGetter interface { type TreeGetter interface {
app.ComponentRunnable app.ComponentRunnable
GetTree(ctx context.Context, spaceId, treeId string) (tree.ObjectTree, error) GetTree(ctx context.Context, spaceId, treeId string) (tree.ObjectTree, error)
DeleteTree(ctx context.Context, spaceId, treeId string) error
} }

View File

@ -26,7 +26,7 @@ type Config struct {
Anytype Anytype `yaml:"anytype"` Anytype Anytype `yaml:"anytype"`
GrpcServer GrpcServer `yaml:"grpcServer"` GrpcServer GrpcServer `yaml:"grpcServer"`
Account Account `yaml:"account"` Account Account `yaml:"account"`
APIServer APIServer `yaml:"apiServer"` APIServer GrpcServer `yaml:"apiServer"`
Nodes []Node `yaml:"nodes"` Nodes []Node `yaml:"nodes"`
Space Space `yaml:"space"` Space Space `yaml:"space"`
Storage Storage `yaml:"storage"` Storage Storage `yaml:"storage"`

View File

@ -0,0 +1,102 @@
package server
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
"github.com/zeebo/errs"
"go.uber.org/zap"
"io"
"net"
"storj.io/drpc"
"storj.io/drpc/drpcmux"
"storj.io/drpc/drpcserver"
"time"
)
type BaseDrpcServer struct {
drpcServer *drpcserver.Server
transport secure.Service
listeners []secure.ContextListener
cancel func()
*drpcmux.Mux
}
type DRPCHandlerWrapper func(handler drpc.Handler) drpc.Handler
type ListenerConverter func(listener net.Listener) secure.ContextListener
func NewBaseDrpcServer() *BaseDrpcServer {
return &BaseDrpcServer{Mux: drpcmux.New()}
}
func (s *BaseDrpcServer) Run(ctx context.Context, listenAddrs []string, wrapper DRPCHandlerWrapper, converter ListenerConverter) (err error) {
s.drpcServer = drpcserver.New(wrapper(s.Mux))
ctx, s.cancel = context.WithCancel(ctx)
for _, addr := range listenAddrs {
tcpList, err := net.Listen("tcp", addr)
if err != nil {
return err
}
tlsList := converter(tcpList)
go s.serve(ctx, tlsList)
}
return
}
func (s *BaseDrpcServer) serve(ctx context.Context, lis secure.ContextListener) {
l := log.With(zap.String("localAddr", lis.Addr().String()))
l.Info("drpc listener started")
defer func() {
l.Debug("drpc listener stopped")
}()
for {
select {
case <-ctx.Done():
return
default:
}
ctx, conn, err := lis.Accept(ctx)
if err != nil {
if isTemporary(err) {
l.Debug("listener temporary accept error", zap.Error(err))
t := time.NewTimer(500 * time.Millisecond)
select {
case <-t.C:
case <-ctx.Done():
return
}
continue
}
if _, ok := err.(secure.HandshakeError); ok {
l.Warn("listener handshake error", zap.Error(err))
continue
}
l.Error("listener accept error", zap.Error(err))
return
}
go s.serveConn(ctx, conn)
}
}
func (s *BaseDrpcServer) serveConn(ctx context.Context, conn net.Conn) {
l := log.With(zap.String("remoteAddr", conn.RemoteAddr().String())).With(zap.String("localAddr", conn.LocalAddr().String()))
l.Debug("connection opened")
if err := s.drpcServer.ServeOne(ctx, conn); err != nil {
if errs.Is(err, context.Canceled) || errs.Is(err, io.EOF) {
l.Debug("connection closed")
} else {
l.Warn("serve connection error", zap.Error(err))
}
}
}
func (s *BaseDrpcServer) Close(ctx context.Context) (err error) {
if s.cancel != nil {
s.cancel()
}
for _, l := range s.listeners {
if e := l.Close(); e != nil {
log.Warn("close listener error", zap.Error(e))
}
}
return
}

View File

@ -8,14 +8,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/metric" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/metric"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/zeebo/errs"
"go.uber.org/zap"
"io"
"net"
"storj.io/drpc" "storj.io/drpc"
"storj.io/drpc/drpcmux"
"storj.io/drpc/drpcserver"
"time"
) )
const CName = "common.net.drpcserver" const CName = "common.net.drpcserver"
@ -23,7 +16,7 @@ const CName = "common.net.drpcserver"
var log = logger.NewNamed(CName) var log = logger.NewNamed(CName)
func New() DRPCServer { func New() DRPCServer {
return &drpcServer{Mux: drpcmux.New()} return &drpcServer{BaseDrpcServer: NewBaseDrpcServer()}
} }
type DRPCServer interface { type DRPCServer interface {
@ -36,19 +29,16 @@ type configGetter interface {
} }
type drpcServer struct { type drpcServer struct {
config config.GrpcServer config config.GrpcServer
drpcServer *drpcserver.Server metric metric.Metric
transport secure.Service transport secure.Service
listeners []secure.ContextListener *BaseDrpcServer
metric metric.Metric
cancel func()
*drpcmux.Mux
} }
func (s *drpcServer) Init(a *app.App) (err error) { func (s *drpcServer) Init(a *app.App) (err error) {
s.config = a.MustComponent(config.CName).(configGetter).GetGRPCServer() s.config = a.MustComponent(config.CName).(configGetter).GetGRPCServer()
s.transport = a.MustComponent(secure.CName).(secure.Service)
s.metric = a.MustComponent(metric.CName).(metric.Metric) s.metric = a.MustComponent(metric.CName).(metric.Metric)
s.transport = a.MustComponent(secure.CName).(secure.Service)
return nil return nil
} }
@ -68,80 +58,21 @@ func (s *drpcServer) Run(ctx context.Context) (err error) {
0.99: 0.0001, 0.99: 0.0001,
}, },
}, []string{"rpc"}) }, []string{"rpc"})
s.drpcServer = drpcserver.New(&metric.PrometheusDRPC{
Handler: s.Mux,
SummaryVec: histVec,
})
if err = s.metric.Registry().Register(histVec); err != nil { if err = s.metric.Registry().Register(histVec); err != nil {
return return
} }
ctx, s.cancel = context.WithCancel(ctx) return s.BaseDrpcServer.Run(
for _, addr := range s.config.ListenAddrs { ctx,
tcpList, err := net.Listen("tcp", addr) s.config.ListenAddrs,
if err != nil { func(handler drpc.Handler) drpc.Handler {
return err return &metric.PrometheusDRPC{
} Handler: handler,
tlsList := s.transport.TLSListener(tcpList) SummaryVec: histVec,
go s.serve(ctx, tlsList)
}
return
}
func (s *drpcServer) serve(ctx context.Context, lis secure.ContextListener) {
l := log.With(zap.String("localAddr", lis.Addr().String()))
l.Info("drpc listener started")
defer func() {
l.Debug("drpc listener stopped")
}()
for {
select {
case <-ctx.Done():
return
default:
}
ctx, conn, err := lis.Accept(ctx)
if err != nil {
if isTemporary(err) {
l.Debug("listener temporary accept error", zap.Error(err))
t := time.NewTimer(500 * time.Millisecond)
select {
case <-t.C:
case <-ctx.Done():
return
}
continue
} }
if _, ok := err.(secure.HandshakeError); ok { },
l.Warn("listener handshake error", zap.Error(err)) s.transport.TLSListener)
continue
}
l.Error("listener accept error", zap.Error(err))
return
}
go s.serveConn(ctx, conn)
}
}
func (s *drpcServer) serveConn(ctx context.Context, conn net.Conn) {
l := log.With(zap.String("remoteAddr", conn.RemoteAddr().String())).With(zap.String("localAddr", conn.LocalAddr().String()))
l.Debug("connection opened")
if err := s.drpcServer.ServeOne(ctx, conn); err != nil {
if errs.Is(err, context.Canceled) || errs.Is(err, io.EOF) {
l.Debug("connection closed")
} else {
l.Warn("serve connection error", zap.Error(err))
}
}
} }
func (s *drpcServer) Close(ctx context.Context) (err error) { func (s *drpcServer) Close(ctx context.Context) (err error) {
if s.cancel != nil { return s.BaseDrpcServer.Close(ctx)
s.cancel()
}
for _, l := range s.listeners {
if e := l.Close(); e != nil {
log.Warn("close listener error", zap.Error(e))
}
}
return
} }

View File

@ -0,0 +1,19 @@
package secure
import (
"context"
"net"
)
type basicListener struct {
net.Listener
}
func newBasicListener(listener net.Listener) ContextListener {
return &basicListener{listener}
}
func (b *basicListener) Accept(ctx context.Context) (context.Context, net.Conn, error) {
conn, err := b.Listener.Accept()
return ctx, conn, err
}

View File

@ -26,6 +26,7 @@ func New() Service {
type Service interface { type Service interface {
TLSListener(lis net.Listener) ContextListener TLSListener(lis net.Listener) ContextListener
BasicListener(lis net.Listener) ContextListener
TLSConn(ctx context.Context, conn net.Conn) (sec.SecureConn, error) TLSConn(ctx context.Context, conn net.Conn) (sec.SecureConn, error)
app.Component app.Component
} }
@ -57,6 +58,10 @@ func (s *service) TLSListener(lis net.Listener) ContextListener {
return newTLSListener(s.key, lis) return newTLSListener(s.key, lis)
} }
func (s *service) BasicListener(lis net.Listener) ContextListener {
return newBasicListener(lis)
}
func (s *service) TLSConn(ctx context.Context, conn net.Conn) (sec.SecureConn, error) { func (s *service) TLSConn(ctx context.Context, conn net.Conn) (sec.SecureConn, error) {
tr, err := libp2ptls.New(s.key) tr, err := libp2ptls.New(s.key)
if err != nil { if err != nil {

View File

@ -4,11 +4,13 @@ import (
"context" "context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/peer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/slice"
) )
type ConfConnector interface { type ConfConnector interface {
Configuration() Configuration
GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error)
DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) DialInactiveResponsiblePeers(ctx context.Context, spaceId string, activeNodeIds []string) ([]peer.Peer, error)
} }
type confConnector struct { type confConnector struct {
@ -20,21 +22,36 @@ func NewConfConnector(conf Configuration, pool pool.Pool) ConfConnector {
return &confConnector{conf: conf, pool: pool} return &confConnector{conf: conf, pool: pool}
} }
func (s *confConnector) GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) { func (s *confConnector) Configuration() Configuration {
return s.connectOneOrMany(ctx, spaceId, s.pool.Get, s.pool.GetOneOf) return s.conf
} }
func (s *confConnector) DialResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) { func (s *confConnector) GetResponsiblePeers(ctx context.Context, spaceId string) ([]peer.Peer, error) {
return s.connectOneOrMany(ctx, spaceId, s.pool.Dial, s.pool.DialOneOf) return s.connectOneOrMany(ctx, spaceId, nil, s.pool.Get, s.pool.GetOneOf)
}
func (s *confConnector) DialInactiveResponsiblePeers(ctx context.Context, spaceId string, activeNodeIds []string) ([]peer.Peer, error) {
return s.connectOneOrMany(ctx, spaceId, activeNodeIds, s.pool.Dial, s.pool.DialOneOf)
} }
func (s *confConnector) connectOneOrMany( func (s *confConnector) connectOneOrMany(
ctx context.Context, spaceId string, ctx context.Context,
spaceId string,
activeNodeIds []string,
connectOne func(context.Context, string) (peer.Peer, error), connectOne func(context.Context, string) (peer.Peer, error),
connectOneOf func(context.Context, []string) (peer.Peer, error)) (peers []peer.Peer, err error) { connectOneOf func(context.Context, []string) (peer.Peer, error)) (peers []peer.Peer, err error) {
allNodes := s.conf.NodeIds(spaceId) var (
inactiveNodeIds []string
allNodes = s.conf.NodeIds(spaceId)
)
for _, id := range allNodes {
if slice.FindPos(activeNodeIds, id) == -1 {
inactiveNodeIds = append(inactiveNodeIds, id)
}
}
if s.conf.IsResponsible(spaceId) { if s.conf.IsResponsible(spaceId) {
for _, id := range allNodes { for _, id := range inactiveNodeIds {
var p peer.Peer var p peer.Peer
p, err = connectOne(ctx, id) p, err = connectOne(ctx, id)
if err != nil { if err != nil {
@ -42,7 +59,8 @@ func (s *confConnector) connectOneOrMany(
} }
peers = append(peers, p) peers = append(peers, p)
} }
} else { } else if len(activeNodeIds) == 0 {
// that means that all connected ids
var p peer.Peer var p peer.Peer
p, err = connectOneOf(ctx, allNodes) p, err = connectOneOf(ctx, allNodes)
if err != nil { if err != nil {

View File

@ -209,19 +209,33 @@ func (m *MockConfConnector) EXPECT() *MockConfConnectorMockRecorder {
return m.recorder return m.recorder
} }
// DialResponsiblePeers mocks base method. // Configuration mocks base method.
func (m *MockConfConnector) DialResponsiblePeers(arg0 context.Context, arg1 string) ([]peer.Peer, error) { func (m *MockConfConnector) Configuration() nodeconf.Configuration {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DialResponsiblePeers", arg0, arg1) ret := m.ctrl.Call(m, "Configuration")
ret0, _ := ret[0].(nodeconf.Configuration)
return ret0
}
// Configuration indicates an expected call of Configuration.
func (mr *MockConfConnectorMockRecorder) Configuration() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Configuration", reflect.TypeOf((*MockConfConnector)(nil).Configuration))
}
// DialInactiveResponsiblePeers mocks base method.
func (m *MockConfConnector) DialInactiveResponsiblePeers(arg0 context.Context, arg1 string, arg2 []string) ([]peer.Peer, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DialInactiveResponsiblePeers", arg0, arg1, arg2)
ret0, _ := ret[0].([]peer.Peer) ret0, _ := ret[0].([]peer.Peer)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// DialResponsiblePeers indicates an expected call of DialResponsiblePeers. // DialInactiveResponsiblePeers indicates an expected call of DialInactiveResponsiblePeers.
func (mr *MockConfConnectorMockRecorder) DialResponsiblePeers(arg0, arg1 interface{}) *gomock.Call { func (mr *MockConfConnectorMockRecorder) DialInactiveResponsiblePeers(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).DialResponsiblePeers), arg0, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialInactiveResponsiblePeers", reflect.TypeOf((*MockConfConnector)(nil).DialInactiveResponsiblePeers), arg0, arg1, arg2)
} }
// GetResponsiblePeers mocks base method. // GetResponsiblePeers mocks base method.

View File

@ -157,6 +157,10 @@ func (t *inMemoryTreeStorage) GetRawChange(ctx context.Context, changeId string)
return nil, fmt.Errorf("could not get change with id: %s", changeId) return nil, fmt.Errorf("could not get change with id: %s", changeId)
} }
func (t *inMemoryTreeStorage) Delete() error {
return nil
}
type inMemoryStorageProvider struct { type inMemoryStorageProvider struct {
objects map[string]TreeStorage objects map[string]TreeStorage
sync.RWMutex sync.RWMutex

View File

@ -160,6 +160,20 @@ func (mr *MockTreeStorageMockRecorder) AddRawChange(arg0 interface{}) *gomock.Ca
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChange", reflect.TypeOf((*MockTreeStorage)(nil).AddRawChange), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRawChange", reflect.TypeOf((*MockTreeStorage)(nil).AddRawChange), arg0)
} }
// Delete mocks base method.
func (m *MockTreeStorage) Delete() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete")
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockTreeStorageMockRecorder) Delete() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockTreeStorage)(nil).Delete))
}
// GetRawChange mocks base method. // GetRawChange mocks base method.
func (m *MockTreeStorage) GetRawChange(arg0 context.Context, arg1 string) (*treechangeproto.RawTreeChangeWithId, error) { func (m *MockTreeStorage) GetRawChange(arg0 context.Context, arg1 string) (*treechangeproto.RawTreeChangeWithId, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -5,9 +5,11 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
) )
var ErrUnknownTreeId = errors.New("tree does not exist") var (
var ErrTreeExists = errors.New("tree already exists") ErrUnknownTreeId = errors.New("tree does not exist")
var ErrUnkownChange = errors.New("change doesn't exist") ErrTreeExists = errors.New("tree already exists")
ErrUnknownChange = errors.New("change doesn't exist")
)
type TreeStorageCreatePayload struct { type TreeStorageCreatePayload struct {
RootRawChange *treechangeproto.RawTreeChangeWithId RootRawChange *treechangeproto.RawTreeChangeWithId

View File

@ -14,6 +14,7 @@ type TreeStorage interface {
AddRawChange(change *treechangeproto.RawTreeChangeWithId) error AddRawChange(change *treechangeproto.RawTreeChangeWithId) error
GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error)
HasChange(ctx context.Context, id string) (bool, error) HasChange(ctx context.Context, id string) (bool, error)
Delete() error
} }
type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error) type TreeStorageCreatorFunc = func(payload TreeStorageCreatePayload) (TreeStorage, error)

View File

@ -48,7 +48,7 @@ type changeBuilder struct {
keys *common.Keychain keys *common.Keychain
} }
func newChangeBuilder(keys *common.Keychain, rootChange *treechangeproto.RawTreeChangeWithId) ChangeBuilder { func NewChangeBuilder(keys *common.Keychain, rootChange *treechangeproto.RawTreeChangeWithId) ChangeBuilder {
return &changeBuilder{keys: keys, rootChange: rootChange} return &changeBuilder{keys: keys, rootChange: rootChange}
} }
@ -155,12 +155,16 @@ func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdC
Identity: payload.Identity, Identity: payload.Identity,
IsSnapshot: payload.IsSnapshot, IsSnapshot: payload.IsSnapshot,
} }
if payload.ReadKey != nil {
encrypted, err := payload.ReadKey.Encrypt(payload.Content) var encrypted []byte
if err != nil { encrypted, err = payload.ReadKey.Encrypt(payload.Content)
return if err != nil {
return
}
change.ChangesData = encrypted
} else {
change.ChangesData = payload.Content
} }
change.ChangesData = encrypted
marshalledChange, err := proto.Marshal(change) marshalledChange, err := proto.Marshal(change)
if err != nil { if err != nil {
@ -188,7 +192,6 @@ func (c *changeBuilder) BuildContent(payload BuilderContent) (ch *Change, rawIdC
} }
ch = NewChange(id, change, signature) ch = NewChange(id, change, signature)
ch.Model = payload.Content
rawIdChange = &treechangeproto.RawTreeChangeWithId{ rawIdChange = &treechangeproto.RawTreeChangeWithId{
RawChange: marshalledRawChange, RawChange: marshalledRawChange,

View File

@ -116,6 +116,20 @@ func (mr *MockObjectTreeMockRecorder) DebugDump() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump)) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DebugDump", reflect.TypeOf((*MockObjectTree)(nil).DebugDump))
} }
// Delete mocks base method.
func (m *MockObjectTree) Delete() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete")
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockObjectTreeMockRecorder) Delete() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockObjectTree)(nil).Delete))
}
// HasChanges mocks base method. // HasChanges mocks base method.
func (m *MockObjectTree) HasChanges(arg0 ...string) bool { func (m *MockObjectTree) HasChanges(arg0 ...string) bool {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -5,7 +5,7 @@ import (
"context" "context"
"errors" "errors"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/common"
list2 "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list" list "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/list"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/pkg/acl/treechangeproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/keys/symmetric"
@ -57,6 +57,7 @@ type ObjectTree interface {
AddContent(ctx context.Context, content SignableChangeContent) (AddResult, error) AddContent(ctx context.Context, content SignableChangeContent) (AddResult, error)
AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (AddResult, error) AddRawChanges(ctx context.Context, changes ...*treechangeproto.RawTreeChangeWithId) (AddResult, error)
Delete() error
Close() error Close() error
} }
@ -66,7 +67,7 @@ type objectTree struct {
validator ObjectTreeValidator validator ObjectTreeValidator
rawChangeLoader *rawChangeLoader rawChangeLoader *rawChangeLoader
treeBuilder *treeBuilder treeBuilder *treeBuilder
aclList list2.ACLList aclList list.ACLList
id string id string
root *treechangeproto.RawTreeChangeWithId root *treechangeproto.RawTreeChangeWithId
@ -91,16 +92,16 @@ type objectTreeDeps struct {
treeStorage storage.TreeStorage treeStorage storage.TreeStorage
validator ObjectTreeValidator validator ObjectTreeValidator
rawChangeLoader *rawChangeLoader rawChangeLoader *rawChangeLoader
aclList list2.ACLList aclList list.ACLList
} }
func defaultObjectTreeDeps( func defaultObjectTreeDeps(
rootChange *treechangeproto.RawTreeChangeWithId, rootChange *treechangeproto.RawTreeChangeWithId,
treeStorage storage.TreeStorage, treeStorage storage.TreeStorage,
aclList list2.ACLList) objectTreeDeps { aclList list.ACLList) objectTreeDeps {
keychain := common.NewKeychain() keychain := common.NewKeychain()
changeBuilder := newChangeBuilder(keychain, rootChange) changeBuilder := NewChangeBuilder(keychain, rootChange)
treeBuilder := newTreeBuilder(treeStorage, changeBuilder) treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
return objectTreeDeps{ return objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,
@ -186,16 +187,23 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
ot.aclList.RLock() ot.aclList.RLock()
defer ot.aclList.RUnlock() defer ot.aclList.RUnlock()
state := ot.aclList.ACLState() // special method for own keys var (
readKey, err := state.CurrentReadKey() state = ot.aclList.ACLState() // special method for own keys
if err != nil { readKey *symmetric.Key
return readKeyHash uint64
)
if content.IsEncrypted {
readKeyHash = state.CurrentReadKeyHash()
readKey, err = state.CurrentReadKey()
if err != nil {
return
}
} }
cnt = BuilderContent{ cnt = BuilderContent{
TreeHeadIds: ot.tree.Heads(), TreeHeadIds: ot.tree.Heads(),
AclHeadId: ot.aclList.Head().Id, AclHeadId: ot.aclList.Head().Id,
SnapshotBaseId: ot.tree.RootId(), SnapshotBaseId: ot.tree.RootId(),
CurrentReadKeyHash: state.CurrentReadKeyHash(), CurrentReadKeyHash: readKeyHash,
Identity: content.Identity, Identity: content.Identity,
IsSnapshot: content.IsSnapshot, IsSnapshot: content.IsSnapshot,
SigningKey: content.Key, SigningKey: content.Key,
@ -439,9 +447,25 @@ func (ot *objectTree) IterateFrom(id string, convert ChangeConvertFunc, iterate
ot.tree.Iterate(id, iterate) ot.tree.Iterate(id, iterate)
return return
} }
decrypt := func(c *Change) (decrypted []byte, err error) {
// the change is not encrypted
if c.ReadKeyHash == 0 {
decrypted = c.Data
return
}
readKey, exists := ot.keys[c.ReadKeyHash]
if !exists {
err = list.ErrNoReadKey
return
}
ot.tree.Iterate(ot.tree.RootId(), func(c *Change) (isContinue bool) { decrypted, err = readKey.Decrypt(c.Data)
return
}
ot.tree.Iterate(id, func(c *Change) (isContinue bool) {
var model any var model any
// if already saved as a model
if c.Model != nil { if c.Model != nil {
return iterate(c) return iterate(c)
} }
@ -449,14 +473,9 @@ func (ot *objectTree) IterateFrom(id string, convert ChangeConvertFunc, iterate
if c.Id == ot.id { if c.Id == ot.id {
return iterate(c) return iterate(c)
} }
readKey, exists := ot.keys[c.ReadKeyHash]
if !exists {
err = list2.ErrNoReadKey
return false
}
var decrypted []byte var decrypted []byte
decrypted, err = readKey.Decrypt(c.Data) decrypted, err = decrypt(c)
if err != nil { if err != nil {
return false return false
} }
@ -508,6 +527,10 @@ func (ot *objectTree) Close() error {
return nil return nil
} }
func (ot *objectTree) Delete() error {
return ot.treeStorage.Delete()
}
func (ot *objectTree) SnapshotPath() []string { func (ot *objectTree) SnapshotPath() []string {
// TODO: Add error as return parameter // TODO: Add error as return parameter
if ot.snapshotPathIsActual() { if ot.snapshotPathIsActual() {

View File

@ -116,7 +116,7 @@ func prepareTreeContext(t *testing.T, aclList list.ACLList) testTreeContext {
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id) treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
root, _ := treeStorage.Root() root, _ := treeStorage.Root()
changeBuilder := &mockChangeBuilder{ changeBuilder := &mockChangeBuilder{
originalBuilder: newChangeBuilder(nil, root), originalBuilder: NewChangeBuilder(nil, root),
} }
deps := objectTreeDeps{ deps := objectTreeDeps{
changeBuilder: changeBuilder, changeBuilder: changeBuilder,

View File

@ -14,10 +14,11 @@ import (
) )
type ObjectTreeCreatePayload struct { type ObjectTreeCreatePayload struct {
SignKey signingkey.PrivKey SignKey signingkey.PrivKey
ChangeType string ChangeType string
SpaceId string SpaceId string
Identity []byte Identity []byte
IsEncrypted bool
} }
func BuildObjectTree(treeStorage storage.TreeStorage, aclList list.ACLList) (ObjectTree, error) { func BuildObjectTree(treeStorage storage.TreeStorage, aclList list.ACLList) (ObjectTree, error) {
@ -71,7 +72,7 @@ func createObjectTree(
Seed: seed, Seed: seed,
} }
_, raw, err := newChangeBuilder(common.NewKeychain(), nil).BuildInitialContent(cnt) _, raw, err := NewChangeBuilder(common.NewKeychain(), nil).BuildInitialContent(cnt)
if err != nil { if err != nil {
return return
} }

View File

@ -137,23 +137,27 @@ func (r *rawChangeLoader) LoadFromStorage(commonSnapshot string, heads, breakpoi
if !shouldVisit(entry.position, exists) { if !shouldVisit(entry.position, exists) {
continue continue
} }
if id == commonSnapshot {
commonSnapshotVisited = true
continue
}
if !exists { if !exists {
entry, err = r.loadEntry(id) entry, err = r.loadEntry(id)
if err != nil { if err != nil {
continue continue
} }
} }
// setting the counter when we visit // setting the counter when we visit
r.cache[id] = visit(entry) entry = visit(entry)
r.cache[id] = entry
for _, prev := range entry.change.PreviousIds { for _, prev := range entry.change.PreviousIds {
if prev == commonSnapshot { if prev == commonSnapshot {
commonSnapshotVisited = true commonSnapshotVisited = true
break break
} }
entry, exists = r.cache[prev] prevEntry, exists := r.cache[prev]
if !shouldVisit(entry.position, exists) { if !shouldVisit(prevEntry.position, exists) {
continue continue
} }
r.idStack = append(r.idStack, prev) r.idStack = append(r.idStack, prev)

View File

@ -5,8 +5,9 @@ import (
) )
type SignableChangeContent struct { type SignableChangeContent struct {
Data []byte Data []byte
Key signingkey.PrivKey Key signingkey.PrivKey
Identity []byte Identity []byte
IsSnapshot bool IsSnapshot bool
IsEncrypted bool
} }

View File

@ -336,8 +336,9 @@ func (t *Tree) dfsPrev(stack []*Change, breakpoints []string, visit func(ch *Cha
t.visitedBuf = append(t.visitedBuf, ch) t.visitedBuf = append(t.visitedBuf, ch)
for _, prevId := range ch.PreviousIds { for _, prevId := range ch.PreviousIds {
prevCh := t.attached[prevId] prevCh, exists := t.attached[prevId]
if !prevCh.visited { // here the only time it wouldn't exist if we are at the tree root
if exists && !prevCh.visited {
stack = append(stack, prevCh) stack = append(stack, prevCh)
} }
} }

View File

@ -0,0 +1,58 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/periodicsync (interfaces: PeriodicSync)
// Package mock_periodicsync is a generated GoMock package.
package mock_periodicsync
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// MockPeriodicSync is a mock of PeriodicSync interface.
type MockPeriodicSync struct {
ctrl *gomock.Controller
recorder *MockPeriodicSyncMockRecorder
}
// MockPeriodicSyncMockRecorder is the mock recorder for MockPeriodicSync.
type MockPeriodicSyncMockRecorder struct {
mock *MockPeriodicSync
}
// NewMockPeriodicSync creates a new mock instance.
func NewMockPeriodicSync(ctrl *gomock.Controller) *MockPeriodicSync {
mock := &MockPeriodicSync{ctrl: ctrl}
mock.recorder = &MockPeriodicSyncMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockPeriodicSync) EXPECT() *MockPeriodicSyncMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockPeriodicSync) Close() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Close")
}
// Close indicates an expected call of Close.
func (mr *MockPeriodicSyncMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPeriodicSync)(nil).Close))
}
// Run mocks base method.
func (m *MockPeriodicSync) Run() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Run")
}
// Run indicates an expected call of Run.
func (mr *MockPeriodicSyncMockRecorder) Run() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockPeriodicSync)(nil).Run))
}

View File

@ -1,4 +1,5 @@
package diffservice //go:generate mockgen -destination mock_periodicsync/mock_periodicsync.go github.com/anytypeio/go-anytype-infrastructure-experiments/common/util/periodicsync PeriodicSync
package periodicsync
import ( import (
"context" "context"
@ -11,7 +12,9 @@ type PeriodicSync interface {
Close() Close()
} }
func newPeriodicSync(periodSeconds int, syncer DiffSyncer, l *zap.Logger) *periodicSync { type SyncerFunc func(ctx context.Context) error
func NewPeriodicSync(periodSeconds int, syncer SyncerFunc, l *zap.Logger) PeriodicSync {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
return &periodicSync{ return &periodicSync{
syncer: syncer, syncer: syncer,
@ -25,7 +28,7 @@ func newPeriodicSync(periodSeconds int, syncer DiffSyncer, l *zap.Logger) *perio
type periodicSync struct { type periodicSync struct {
log *zap.Logger log *zap.Logger
syncer DiffSyncer syncer SyncerFunc
syncCtx context.Context syncCtx context.Context
syncCancel context.CancelFunc syncCancel context.CancelFunc
syncLoopDone chan struct{} syncLoopDone chan struct{}
@ -42,7 +45,7 @@ func (p *periodicSync) syncLoop(periodSeconds int) {
doSync := func() { doSync := func() {
ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute) ctx, cancel := context.WithTimeout(p.syncCtx, time.Minute)
defer cancel() defer cancel()
if err := p.syncer.Sync(ctx); err != nil { if err := p.syncer(ctx); err != nil {
p.log.Warn("periodic sync error", zap.Error(err)) p.log.Warn("periodic sync error", zap.Error(err))
} }
} }

View File

@ -1,9 +1,10 @@
package diffservice package periodicsync
import ( import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/diffservice/mock_diffservice"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing" "testing"
"time" "time"
) )
@ -14,25 +15,34 @@ func TestPeriodicSync_Run(t *testing.T) {
defer ctrl.Finish() defer ctrl.Finish()
l := logger.NewNamed("sync") l := logger.NewNamed("sync")
diffSyncer := mock_diffservice.NewMockDiffSyncer(ctrl)
t.Run("diff syncer 1 time", func(t *testing.T) { t.Run("diff syncer 1 time", func(t *testing.T) {
secs := 0 secs := 0
pSync := newPeriodicSync(secs, diffSyncer, l) times := 0
diffSyncer := func(ctx context.Context) (err error) {
diffSyncer.EXPECT().Sync(gomock.Any()).Times(1).Return(nil) times += 1
return nil
}
pSync := NewPeriodicSync(secs, diffSyncer, l)
pSync.Run() pSync.Run()
pSync.Close() pSync.Close()
require.Equal(t, 1, times)
}) })
t.Run("diff syncer 2 times", func(t *testing.T) { t.Run("diff syncer 2 times", func(t *testing.T) {
secs := 1 secs := 1
pSync := newPeriodicSync(secs, diffSyncer, l) times := 0
diffSyncer.EXPECT().Sync(gomock.Any()).Times(2).Return(nil) diffSyncer := func(ctx context.Context) (err error) {
times += 1
return nil
}
pSync := NewPeriodicSync(secs, diffSyncer, l)
pSync.Run() pSync.Run()
time.Sleep(time.Second * time.Duration(secs)) time.Sleep(time.Second * time.Duration(secs))
pSync.Close() pSync.Close()
require.Equal(t, 2, times)
}) })
} }

View File

@ -1,28 +0,0 @@
records:
- identity: A
aclChanges:
- userAdd:
identity: A
permission: admin
encryptionKey: key.Enc.A
encryptedReadKeys: [key.Read.1]
- userAdd:
identity: B
permission: admin
encryptionKey: key.Enc.B
encryptedReadKeys: [key.Read.1]
readKey: key.Read.1
keys:
Enc:
- name: A
value: JgG4CcCbae1qEpe7mKpBzsHjZhXUmDSNVNX2B1gxFZsJyMX4V6kBQUott9zRWyeXaW1ZmpzuxDXnwSQpAnNurhXyGa9iQaAPqzY9A9VWBPD33Yy1eW7TRuVemzToh8jJQKQKnZNbF8ucTWV9qahusKzyvN8uyhrqoW2tAPfA9S3E3ognCuqbLSW6yjE2rBKayvyS1BVwzjSd6FZK4DDyjfU3pbEVjut3wytGEAn9af6sNMmyCnf2MX5vLovWs9rU8av61wD4z7HTsXyGFx4K75N4Go249Hpe9SKAT6HxhRc3yvj63krPLiQV5yMuH2UeMUXBDekUQyNmBEdn9wrur7mLqB67Bc6tcc2PP8XApBCdWJHvHjN4FktSpaG5vbCqoZbLD1oCbk36q2x9s6XM8pydVqD1J9P3nTbfgMb5pJCTFjNtgKeuKv6wjfJeA9jF1VhcJQisfsahgv9MvZ9M8FJpZTq1zKUhYDCRnZxUkraoMS5yNNVdDzaUckKEDthqik7BMWCWT79vq7uVgMwEvGwGi76gtoMg1159bbPMLZ4bdPVfhH2S9QjPrzQfwZSrzB2YeVPjWpaXDeLDity5H8n1NK2oniAQR6gE71n81neSptsuhV6o6QpQ89AU8y57XmEsou4VEryn8vUxBHhULLxrLNUouxyWamCeFiDjk5cSN6koQsf9BYKSNTPFTrwjTKForDokMhcPdMtFktKwjv7u9UEGcY4MKvNzZZkc77gHiP8bqVtdNNoLpTFUC5SZ9i7bKdHvK12HpSy7yzzPeMXJ9UwhLxkok1g81ngTbN1yxRhvYXyHZFtguCR9kvGojDjka91MTBtk551qDw9eCn2xZT9U8jqzBCjdpvSg3mRWKMPnYAGB7m7u1ye165wyGFvzcHAx3vtXjxAqLUeKYZCjv2m6V9D2Y4qH1TQNddWqH14T1JVMis971UCH9Ddpj6a3387oUnufD1P6HZN2ieJCvptrmbGVvxJYYSvmVf1dkwbtqurDRNWD7TJ7gf6iqSP549C9bxP4GpLt3ygjHmMtcuUzstBuztvunJUnQhfnJxqU6LjRdsFzm53wGWgXNxab7ZvQcPyLwsevn1b98FGPnVpS5iY4LjmqW4ugrC6HgrbsjrXiKzR1yZKhLQkCbLzPoaHb8iB5iBnCr7d4yf5CtfpFRqgoqMFdK5LNZYmDX4HzUKN6A7wC3gGiSRFTLcgGZeSMkB5Pa61CZBU7WCQgFxykycE9HRA7PiQa496GWDCV15teToCpFRsAa6jDmR1MGXPeLRqQgve49VXnQN5FL7c1VuEv5SWjeTuCnMB47DJKBaP7eKJNKgLwETALzSCMF3nRiRgeb15kfoS4BbrJ5yupjrvwmbmvNg1AYFFS5sYNWft7K8v87wQvBakRtGP71Kp8NX77XFtu6xdB7sR6jpfC6qJPyB9akWNXgCrWy9kE4ih42gwAZdUugNZ9YtEsgRM3pwb6qJhkAPyEJtrxrja859PCAgqPSQiPQN33PaMkgQ6HJknu8CrjKRiXAycZ16KLUkHV64TNhEjPTcX1a7rqpD131AYMWX8d7CCdc9Ys7RUb6BwguuNSh8rJK3x4AkMDSUsaE8ynKvpC7RXZpJ9Nxfhd
- name: B
value: JgG4CcCbae1qEpe7mKXzp7m5hNc56SSyZd9DwUaEStKJrq7RToAC2Vgd3i6hKRwa58zCWeN6Wjc3o6qrdKPEPRvcyEPysamajVo5mdQiUgWAmr97pGEsyjuRjQoC2GY2LvLiEQxEgwFgJxKGMHMiaWMtDfxCDUaDEm4bu5RdMhqRZekAWho6c3WoEeruSr14iX1TrocFNfBkBY7CjEw8kcywXCTNgtvhb2Qiwgj5AxEF4wyw4bzaNA9ctXb1hoHPFVMu6C51pkFY7jUD9zwyH3ukgnAewkGAcPNbKmaTAtMosKRVaAN97mAwXh2VRt1hWmRvVk7r76EjnVKhD4vbsKZc56RVcHTVWRVdhU7FGyPsiE5rSQAz1JQGYzxnZpX7EG77CyrmUGyfueVfRHhwY2oq8A4uQCRaQxSaJHYLowjXSxh8DQ2V6MTqyzti32C27utBYdHzLVCJSGkmdzGwrFcHqsq7nLDxmvJVErPvyReixEe8kFmqopJ3e6LLm8WdYw9K6JYBjXnEfwPzm7Von9sf3dcaGDUHYfttMyeke7fAXJkvPRje69hYVyzdQGAauuojzGkkvQWCSMK1KCMNMznRaPDCNvofrQhYrub24WhmwpKhorufdfW8Cb4T6reBDCtaWVsbuinjtL6F6Sui5aYHJFLJ6e4pPewr1P4EuZYRbMBZwN5KvDLhTGLBuBnaTqUUdF6bj2U22NoRYMogiHiftqKqiexKNDXX1Zg9RQEvxgjuVo6SBW42mVEA8agrLhruRqCmiduJxVrfqLNGeYXHXrcmMEgW7uosJbPXvTcfRvdFWS1ov7oSALvj6vhDQ28Yi9D2ETNdNsfVWAFQuwvPpW7CHQGXTitprVbqH8JYxNZuGygcLmr5efbB22Vzu4ntd1HoraQpG12qeDEUA7tXYUpoYyuSdWwKPjSAMtaQcCSfVrhKQHQuKJargrVrez8vjWuwLfvSucV7ZHe7gjqvYgULdE1ubRCRSd7DuLjEN2Vd6obzV2c3MRet7ZSf4Sp88WM5AuTyW7BjArBc4S3gUQ8rYaiZ8Tu7NCxkEzbFwWRaemZkwfvcsX3XxqjyF37tFSGkEqE5kuBvpZW72675LkDffj7kH1zA8yE6dVujJjWsNYVFJWndUtz5Vy2KCdZAbBgq19q4AtsxWPodU2N3yZXzFAFAzTrxS6V4P7Scpdau1avgRvHLcBQPunA37xaYMy8YMifJwtmRY25mnAQwZAk3eANk7tXwZd58SDnciLNvARJvwKzTQBXcshkwyy52SX8XmXDJsPnRLaHmiYBJ63Yzr5XpZuuAtxb9qrWG2NHCNxfomHokWacV1hjZPPd6ZxT1FuRozB6Qt2NLcyqY7bnTcQJb1jPUaTAGXXCR8WVmmmYo2fDQe8CdBmgyPvbzNTEJUyScBz4RdycB5PZap4SurJCWtHbuMyQbQUB6jJgURDstfXS5Akfe4oruNq9rnYcNtnsDJPtrhXHBqzDizmf1BDxR5FB2RCxzCgeAfg8WQ1Ug9PVAGTzob6ZqCrGXzWXEUniZnf1vjr7QhGKBYXEX9SWDoSMUpP4FreVDTnx15ijRZTV3p8xG5fE9e36TnugRVvTyq7XzmyPBjW2r66f1bior
Sign:
- name: A
value: 3id6ddLcoNoe9rDgGM88ET8T6TnvHm5GFqFdN6kBzn7Q8d6VUGgjeT59CNWFiaofdeRnHBvX2A5ZacMXvfwaYEFuCbug
- name: B
value: 3iiLPj6wMUQpPwTBNZcUgkbXub1jumg4AEV9LfMyFHZVc84GLyAjVbVvH6EAGhcNrxRxL82aW4BimhDZCpLsRCqx5vwj
Read:
- name: 1
value: bamccoi5jdypwnjkiuuogkawvhkbowha4qg756uhnbkecr5vt3h4q

View File

@ -1,37 +1,39 @@
anytype: anytype:
swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec
grpcServer: grpcServer:
listenAddrs: listenAddrs:
- 127.0.0.1:4630 - 127.0.0.1:4630
tls: false tls: false
account: account:
peerId: 12D3KooWFqDLPcSZi74A1vVpDc8baTkGU6bd21AXcNxH8CFPMqp6 peerId: 12D3KooWFgtCbkf47HhFyQW2cEdAkvaofpokCiaa24Phnz7hpepG
peerKey: s6PUCRVry6ymxhyytNQcqSQVd2ECGyWNMIJB0FkyMUFZXbbOYSBb2yYPeQXrA9jdFdZDXyUSxtvzasvpSMpa6w== peerKey: 4nWcqWOZxv1iXWYuW35eJlF9nxownm38bZjQ27pmFgVXO26vobKLx70TnNTQzZQdoW/dZtxyE9PO37R74vfPQQ==
signingKey: +UF/Do2KPeBLA0joKvnJj43jiH975JcHGjkLIkLR0p7FCFHnR1r/w4xLSa4RTjhEAQ3sDefjktShOJpalXnGvg== signingKey: ULbtmmyFjkJ6Z+54FI1OJWfu0QdIeoCckwcrBZDLGhw2o2cXTFH5KGxQuAruNTbREz9eAVGmhGoBZtKVi6/6ng==
encryptionKey: MIIEpQIBAAKCAQEA7NiHF065o9BfTTAWtAItg3KLqvFnRN2WVQMkjMZ/BukIj4UAd196ppexh2tnDvvqW53qVxFtXcW8oFqX9GmDJx61nnN/ce2FhXNB3aPMa7g3AchlVVB9RHyS8Z49HTkn3DVRi8I8EnbpWer35BjnpGOQ257O/kFpD1P5FzvxyTQ2gF50SyiwoDzibyT2VxgQqaDErr9BfFQKBZb8SEBeLACOlzjb2u0mCv7NeoZNfzl2KsqBC8tiCyfNahhauGfU9ZB7PtHMC1pJKTtPhXhNhQI8Rp39dd+Fr3kiTJl3Fe1f4bg4GDI7LbqCARVBbtCjsLEMi1BMzMS63bFPrPL9ewIDAQABAoIBAQCA261j+Oj3Pz8ad7diaGzqvz9N2dkdlpFb30HbdYNW9yI5M1t1lvTb/lwQGVcQx+5RujDs/gZKpnJhq+hQibdZaVPWyW/lRB0I5hRHyf5F/QuwZJ79M7VztXMdEcKeS6JsJHYhW6PjR97dlQEZkJM21RTS6CwmGOBX/o/fHDYICNxIqt4x7x1Hu+A9Qcs3LWvWq0qAkO48jSYBDeIFJ56BdXZacfIv9A7aCGWoVvih2vFIFEwdn+3z69FHmcW8JzVDK+WdkegtOlvuPcFGgDjS8cHq4zuKyEckur9EVm2Wer+GRdY2v7i9ypxiy/Ej4qJCqJLIa5rtWHmB9Dz7IyFBAoGBAPlIMpu9vAhAhJUeO48vsuEDdCn2ztyq2h4GwYcuNmfZUAnFdKRHHAfb48P7nR1uVCEEvnJYF9uUFkot8zljkDCoqc3J30sOd54PT2Jqn2vPhSWpjNJGW4Ku3CmZq/vfCH15z+bcr7whtlEswshE31bykbZlzCOSyW1tgfz2I+ydAoGBAPM6iEV6M74X+M4GoVCwUn9JMFRUX/JONOu4nfNT+1jDeABeXzVS3gzLSMJ/Vk/+1a/g6NFm73bt5PYHR8jG/jrT3xcTBPUiFj038w1MAM5Fsj2jSnIFRYFxwH8q0RfejWvKJRyWKUyTt7m43VRY9P01+YDfgt+VoLs94rV0PNr3AoGAahmWoL8S5xg+1hE2HG2a3zbPHIVV6oo1qA4MFPNQaMcPz/jg+oLhpV6sBOB1MO+ikyMnxBdGoEjZa90+5rA/0NYY3+QKTDHuK7IsgaEMFaEP9MXDkEQt8uNmBbbIgr2dKXrNSF+p1JMsvEQm64KU5Lb92fpd9s4lOZQgfYBuLekCgYEAwNvPg6+S6Y7edJZjQLSepVjmHmfMsDd81M/NRkx4Bvju5PPvcDul3+UsazRGvyVkUJH4aVnCVL3rB33cWIIYwZKP2R72llyR37bGXOu/088FtsQMWn59j1cf+HV91/xajHZ7mMAkPRj/3B6OOLxUfZZXoO0ZO6nMCcvXQGPLgR8CgYEA2W644EHrSwb4qsDsUmIEeKnjSejS8Vej4S5/g1YOyVzfWEr/5rtejw09Fv4U92SeYhp7Xp3C0UnRCduZKrpXIZJVPO8KgWLDtPi9KvHqDPzpQNRHMNrsXLpOLLv+bnnymWXjcyG8fRecU4sggaH4r1C/QyLPr+s/fLDyVUt7bC8= encryptionKey: MIIEowIBAAKCAQEAuGAvw/JQuivjoFIhV9RGkoCjO60jNkQpVPWK52eUtEvKHT2EzufhCRwxhAreajoyzk0PsyJ75FWrrvYs2tkSVHFOSiBkZIsldn5gPg1cnvnJOZ9VKDFp8h85d/4cPQ5tX78043nYTgLje2EmbB83inIr4oiZgxDrtLkozJHleAyWuOLIvlWO1l4Uplf6+uooL/5+WeUCuSGUM0wgXfpn+I2IuRhVDVZiChfp51Q6D6brTdOzNcWq1dw6Vld67u8aCLF1EVZ+xM/rnLLBC7MFvIw44LqHvmvGs/lpE9nMNx5L2KfpbpHSBI0IH3FkLQe2Qz8OMZpIa+aga/DzrBpEdwIDAQABAoIBACudXU898AjKPxN6ujZ7maIoWfTQ9SZuI1TcrNomr4+i6hHWrqb/RUWRbMkuhQSd9czFf/RBMQuHlJBT3bJ7bRGaqAly9iyumdMY/A1RvdpBfm9qGIvkfIpxBngzHVz4H7lpkspI1XlGx6c1CRDEpa/TaDwzUhUmGIvszRDvZlfqQvjPjyYSV5Hdc4ywh5zjuSFlxOD/9gsPRE5v4M4FGrGv8cm859P1u95Wxxo3pWincpzjvWw2LpsUGctyU34MhErxh86vNhP9v+nR4VkdojVKkHQTYnPKUlaKj6F+IUSj8syxuTJb8bs0GBuvcXW9AKp/K0xq/GBC8Cu/XN7Ln7kCgYEAwZoqLnU9OuwkcN5AHYW7XsxmVCEnxOsncrUbIzEKPvy4wELdOCVVrX66zmIjb+1+mhaz+mGMGEpkVMBld3wdDfmGgo0CAPlF4efH1ppMzUm2aZ+HYQR8KMH1XOT9qjbGEnLeWcANQT0vZPpe77PQLNwLJ1zv6EtXMMrEH0s4ijUCgYEA88zCNsBtB07ayFr9r+RCfHx/X9wFkT59t2K+axIfZE02f62WWqJCZYMlZu9XAbYEQ94H43/NAL9wfA8dgnF7mKSL8stJKt0g2iPa3MluF4Gq5Y2XYEVf/EDEhP2jh8p1l+xs18rVzsQQ6b3CEU9ytmBJWvkWnwVXf+ZnsCFECXsCgYBM3YyJzXp1/nOpbFRAZGw0AytNk6xafpK29DjGDB5pS6V+kA2M0SXnMD2y2zv+oGh3fTQP4NLigga7r3eZrOlMNxm0k4+MG2wneQLarYB4sR9/aBsz5bf15qwoKbKc9gpGIN0u/RVGJai/irhOqzGn3eV/x2Jo9CC1+otLcW4NUQKBgQCOOHlnZTN1GuwICwSIkhiy9BF+AyUASLsfuquoXEcRxPUw4DugnZ0sCKhN9vsDlYHBcYmajhgyAnuE83BcgwT906eMOEhzh9G9T0NCnwLpFYxzIvkWgQHwbnv1tNyrv1CAEryf2cSGPNw87qSCYp1hhKPmPP6UP5J+mxMLrSw6dwKBgHHFweDS2tw4TNxJQjhfQOp5t9VQbQffFZAqpXGFTc4vf7XePlxIGoIpOg4ShHCKKHSy0PtsLe7QjLrdbMkyYh8oGqgNe5CYTzFFDeK6Im1DoiqNWT+YUWF/gzVRUSpo0QW+4J1hfChG2URp9KbnditXKsJ5Vh+QayHPoZwN7Kgl
apiServer: apiServer:
port: "8090" listenAddrs:
- 127.0.0.1:8090
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:
addr: "" addr: ""
log: log:
production: false production: false
defaultLevel: "" defaultLevel: ""
namedLevels: {} namedLevels: {}

View File

@ -1,37 +1,39 @@
anytype: anytype:
swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec swarmKey: /key/swarm/psk/1.0.0/base16/209992e611c27d5dce8fbd2e7389f6b51da9bee980992ef60739460b536139ec
grpcServer: grpcServer:
listenAddrs: listenAddrs:
- 127.0.0.1:4430 - 127.0.0.1:4430
tls: false tls: false
account: account:
peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
peerKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== peerKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
apiServer: apiServer:
port: "8084" listenAddrs:
- 127.0.0.1:8080
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:
addr: "" addr: ""
log: log:
production: false production: false
defaultLevel: "" defaultLevel: ""
namedLevels: {} namedLevels: {}

View File

@ -5,31 +5,33 @@ grpcServer:
- 127.0.0.1:4630 - 127.0.0.1:4630
tls: false tls: false
account: account:
peerId: 12D3KooWFqDLPcSZi74A1vVpDc8baTkGU6bd21AXcNxH8CFPMqp6 peerId: 12D3KooWFgtCbkf47HhFyQW2cEdAkvaofpokCiaa24Phnz7hpepG
peerKey: s6PUCRVry6ymxhyytNQcqSQVd2ECGyWNMIJB0FkyMUFZXbbOYSBb2yYPeQXrA9jdFdZDXyUSxtvzasvpSMpa6w== peerKey: 4nWcqWOZxv1iXWYuW35eJlF9nxownm38bZjQ27pmFgVXO26vobKLx70TnNTQzZQdoW/dZtxyE9PO37R74vfPQQ==
signingKey: +UF/Do2KPeBLA0joKvnJj43jiH975JcHGjkLIkLR0p7FCFHnR1r/w4xLSa4RTjhEAQ3sDefjktShOJpalXnGvg== signingKey: ULbtmmyFjkJ6Z+54FI1OJWfu0QdIeoCckwcrBZDLGhw2o2cXTFH5KGxQuAruNTbREz9eAVGmhGoBZtKVi6/6ng==
encryptionKey: MIIEpQIBAAKCAQEA7NiHF065o9BfTTAWtAItg3KLqvFnRN2WVQMkjMZ/BukIj4UAd196ppexh2tnDvvqW53qVxFtXcW8oFqX9GmDJx61nnN/ce2FhXNB3aPMa7g3AchlVVB9RHyS8Z49HTkn3DVRi8I8EnbpWer35BjnpGOQ257O/kFpD1P5FzvxyTQ2gF50SyiwoDzibyT2VxgQqaDErr9BfFQKBZb8SEBeLACOlzjb2u0mCv7NeoZNfzl2KsqBC8tiCyfNahhauGfU9ZB7PtHMC1pJKTtPhXhNhQI8Rp39dd+Fr3kiTJl3Fe1f4bg4GDI7LbqCARVBbtCjsLEMi1BMzMS63bFPrPL9ewIDAQABAoIBAQCA261j+Oj3Pz8ad7diaGzqvz9N2dkdlpFb30HbdYNW9yI5M1t1lvTb/lwQGVcQx+5RujDs/gZKpnJhq+hQibdZaVPWyW/lRB0I5hRHyf5F/QuwZJ79M7VztXMdEcKeS6JsJHYhW6PjR97dlQEZkJM21RTS6CwmGOBX/o/fHDYICNxIqt4x7x1Hu+A9Qcs3LWvWq0qAkO48jSYBDeIFJ56BdXZacfIv9A7aCGWoVvih2vFIFEwdn+3z69FHmcW8JzVDK+WdkegtOlvuPcFGgDjS8cHq4zuKyEckur9EVm2Wer+GRdY2v7i9ypxiy/Ej4qJCqJLIa5rtWHmB9Dz7IyFBAoGBAPlIMpu9vAhAhJUeO48vsuEDdCn2ztyq2h4GwYcuNmfZUAnFdKRHHAfb48P7nR1uVCEEvnJYF9uUFkot8zljkDCoqc3J30sOd54PT2Jqn2vPhSWpjNJGW4Ku3CmZq/vfCH15z+bcr7whtlEswshE31bykbZlzCOSyW1tgfz2I+ydAoGBAPM6iEV6M74X+M4GoVCwUn9JMFRUX/JONOu4nfNT+1jDeABeXzVS3gzLSMJ/Vk/+1a/g6NFm73bt5PYHR8jG/jrT3xcTBPUiFj038w1MAM5Fsj2jSnIFRYFxwH8q0RfejWvKJRyWKUyTt7m43VRY9P01+YDfgt+VoLs94rV0PNr3AoGAahmWoL8S5xg+1hE2HG2a3zbPHIVV6oo1qA4MFPNQaMcPz/jg+oLhpV6sBOB1MO+ikyMnxBdGoEjZa90+5rA/0NYY3+QKTDHuK7IsgaEMFaEP9MXDkEQt8uNmBbbIgr2dKXrNSF+p1JMsvEQm64KU5Lb92fpd9s4lOZQgfYBuLekCgYEAwNvPg6+S6Y7edJZjQLSepVjmHmfMsDd81M/NRkx4Bvju5PPvcDul3+UsazRGvyVkUJH4aVnCVL3rB33cWIIYwZKP2R72llyR37bGXOu/088FtsQMWn59j1cf+HV91/xajHZ7mMAkPRj/3B6OOLxUfZZXoO0ZO6nMCcvXQGPLgR8CgYEA2W644EHrSwb4qsDsUmIEeKnjSejS8Vej4S5/g1YOyVzfWEr/5rtejw09Fv4U92SeYhp7Xp3C0UnRCduZKrpXIZJVPO8KgWLDtPi9KvHqDPzpQNRHMNrsXLpOLLv+bnnymWXjcyG8fRecU4sggaH4r1C/QyLPr+s/fLDyVUt7bC8= encryptionKey: MIIEowIBAAKCAQEAuGAvw/JQuivjoFIhV9RGkoCjO60jNkQpVPWK52eUtEvKHT2EzufhCRwxhAreajoyzk0PsyJ75FWrrvYs2tkSVHFOSiBkZIsldn5gPg1cnvnJOZ9VKDFp8h85d/4cPQ5tX78043nYTgLje2EmbB83inIr4oiZgxDrtLkozJHleAyWuOLIvlWO1l4Uplf6+uooL/5+WeUCuSGUM0wgXfpn+I2IuRhVDVZiChfp51Q6D6brTdOzNcWq1dw6Vld67u8aCLF1EVZ+xM/rnLLBC7MFvIw44LqHvmvGs/lpE9nMNx5L2KfpbpHSBI0IH3FkLQe2Qz8OMZpIa+aga/DzrBpEdwIDAQABAoIBACudXU898AjKPxN6ujZ7maIoWfTQ9SZuI1TcrNomr4+i6hHWrqb/RUWRbMkuhQSd9czFf/RBMQuHlJBT3bJ7bRGaqAly9iyumdMY/A1RvdpBfm9qGIvkfIpxBngzHVz4H7lpkspI1XlGx6c1CRDEpa/TaDwzUhUmGIvszRDvZlfqQvjPjyYSV5Hdc4ywh5zjuSFlxOD/9gsPRE5v4M4FGrGv8cm859P1u95Wxxo3pWincpzjvWw2LpsUGctyU34MhErxh86vNhP9v+nR4VkdojVKkHQTYnPKUlaKj6F+IUSj8syxuTJb8bs0GBuvcXW9AKp/K0xq/GBC8Cu/XN7Ln7kCgYEAwZoqLnU9OuwkcN5AHYW7XsxmVCEnxOsncrUbIzEKPvy4wELdOCVVrX66zmIjb+1+mhaz+mGMGEpkVMBld3wdDfmGgo0CAPlF4efH1ppMzUm2aZ+HYQR8KMH1XOT9qjbGEnLeWcANQT0vZPpe77PQLNwLJ1zv6EtXMMrEH0s4ijUCgYEA88zCNsBtB07ayFr9r+RCfHx/X9wFkT59t2K+axIfZE02f62WWqJCZYMlZu9XAbYEQ94H43/NAL9wfA8dgnF7mKSL8stJKt0g2iPa3MluF4Gq5Y2XYEVf/EDEhP2jh8p1l+xs18rVzsQQ6b3CEU9ytmBJWvkWnwVXf+ZnsCFECXsCgYBM3YyJzXp1/nOpbFRAZGw0AytNk6xafpK29DjGDB5pS6V+kA2M0SXnMD2y2zv+oGh3fTQP4NLigga7r3eZrOlMNxm0k4+MG2wneQLarYB4sR9/aBsz5bf15qwoKbKc9gpGIN0u/RVGJai/irhOqzGn3eV/x2Jo9CC1+otLcW4NUQKBgQCOOHlnZTN1GuwICwSIkhiy9BF+AyUASLsfuquoXEcRxPUw4DugnZ0sCKhN9vsDlYHBcYmajhgyAnuE83BcgwT906eMOEhzh9G9T0NCnwLpFYxzIvkWgQHwbnv1tNyrv1CAEryf2cSGPNw87qSCYp1hhKPmPP6UP5J+mxMLrSw6dwKBgHHFweDS2tw4TNxJQjhfQOp5t9VQbQffFZAqpXGFTc4vf7XePlxIGoIpOg4ShHCKKHSy0PtsLe7QjLrdbMkyYh8oGqgNe5CYTzFFDeK6Im1DoiqNWT+YUWF/gzVRUSpo0QW+4J1hfChG2URp9KbnditXKsJ5Vh+QayHPoZwN7Kgl
apiServer: apiServer:
port: "8090" listenAddrs:
- 127.0.0.1:8090
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw==
types : ["tree", "file"] types : ["tree", "file"]
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:

View File

@ -5,31 +5,33 @@ grpcServer:
- 127.0.0.1:4631 - 127.0.0.1:4631
tls: false tls: false
account: account:
peerId: 12D3KooWA7AHfBCyNPQaMnffj8S7Z9kZzKG6X1apLgtyP1CgpXiJ peerId: 12D3KooWQuD9ShSHt4nb7bXefg8ndpDXCDzwrm9pjHsnDY2khbRi
peerKey: +KIj+xVyg241tP2So4JmRNGFFIgtzK1PWUo8El0e5x0ETXCrCksPkLsA8s6Xww0DJy92dyISwoBoMQ7XhLbdOw== peerKey: fp/Q18I7TNM4kgKXbbOBQJbJonlrQqAlZwTF6Rx/sKXgHQGZ1dBcS45oXGbTb15Bi2r7sOX+d6HJaaQE29MisQ==
signingKey: +UF/Do2KPeBLA0joKvnJj43jiH975JcHGjkLIkLR0p7FCFHnR1r/w4xLSa4RTjhEAQ3sDefjktShOJpalXnGvg== signingKey: ULbtmmyFjkJ6Z+54FI1OJWfu0QdIeoCckwcrBZDLGhw2o2cXTFH5KGxQuAruNTbREz9eAVGmhGoBZtKVi6/6ng==
encryptionKey: MIIEpQIBAAKCAQEA7NiHF065o9BfTTAWtAItg3KLqvFnRN2WVQMkjMZ/BukIj4UAd196ppexh2tnDvvqW53qVxFtXcW8oFqX9GmDJx61nnN/ce2FhXNB3aPMa7g3AchlVVB9RHyS8Z49HTkn3DVRi8I8EnbpWer35BjnpGOQ257O/kFpD1P5FzvxyTQ2gF50SyiwoDzibyT2VxgQqaDErr9BfFQKBZb8SEBeLACOlzjb2u0mCv7NeoZNfzl2KsqBC8tiCyfNahhauGfU9ZB7PtHMC1pJKTtPhXhNhQI8Rp39dd+Fr3kiTJl3Fe1f4bg4GDI7LbqCARVBbtCjsLEMi1BMzMS63bFPrPL9ewIDAQABAoIBAQCA261j+Oj3Pz8ad7diaGzqvz9N2dkdlpFb30HbdYNW9yI5M1t1lvTb/lwQGVcQx+5RujDs/gZKpnJhq+hQibdZaVPWyW/lRB0I5hRHyf5F/QuwZJ79M7VztXMdEcKeS6JsJHYhW6PjR97dlQEZkJM21RTS6CwmGOBX/o/fHDYICNxIqt4x7x1Hu+A9Qcs3LWvWq0qAkO48jSYBDeIFJ56BdXZacfIv9A7aCGWoVvih2vFIFEwdn+3z69FHmcW8JzVDK+WdkegtOlvuPcFGgDjS8cHq4zuKyEckur9EVm2Wer+GRdY2v7i9ypxiy/Ej4qJCqJLIa5rtWHmB9Dz7IyFBAoGBAPlIMpu9vAhAhJUeO48vsuEDdCn2ztyq2h4GwYcuNmfZUAnFdKRHHAfb48P7nR1uVCEEvnJYF9uUFkot8zljkDCoqc3J30sOd54PT2Jqn2vPhSWpjNJGW4Ku3CmZq/vfCH15z+bcr7whtlEswshE31bykbZlzCOSyW1tgfz2I+ydAoGBAPM6iEV6M74X+M4GoVCwUn9JMFRUX/JONOu4nfNT+1jDeABeXzVS3gzLSMJ/Vk/+1a/g6NFm73bt5PYHR8jG/jrT3xcTBPUiFj038w1MAM5Fsj2jSnIFRYFxwH8q0RfejWvKJRyWKUyTt7m43VRY9P01+YDfgt+VoLs94rV0PNr3AoGAahmWoL8S5xg+1hE2HG2a3zbPHIVV6oo1qA4MFPNQaMcPz/jg+oLhpV6sBOB1MO+ikyMnxBdGoEjZa90+5rA/0NYY3+QKTDHuK7IsgaEMFaEP9MXDkEQt8uNmBbbIgr2dKXrNSF+p1JMsvEQm64KU5Lb92fpd9s4lOZQgfYBuLekCgYEAwNvPg6+S6Y7edJZjQLSepVjmHmfMsDd81M/NRkx4Bvju5PPvcDul3+UsazRGvyVkUJH4aVnCVL3rB33cWIIYwZKP2R72llyR37bGXOu/088FtsQMWn59j1cf+HV91/xajHZ7mMAkPRj/3B6OOLxUfZZXoO0ZO6nMCcvXQGPLgR8CgYEA2W644EHrSwb4qsDsUmIEeKnjSejS8Vej4S5/g1YOyVzfWEr/5rtejw09Fv4U92SeYhp7Xp3C0UnRCduZKrpXIZJVPO8KgWLDtPi9KvHqDPzpQNRHMNrsXLpOLLv+bnnymWXjcyG8fRecU4sggaH4r1C/QyLPr+s/fLDyVUt7bC8= encryptionKey: MIIEowIBAAKCAQEAuGAvw/JQuivjoFIhV9RGkoCjO60jNkQpVPWK52eUtEvKHT2EzufhCRwxhAreajoyzk0PsyJ75FWrrvYs2tkSVHFOSiBkZIsldn5gPg1cnvnJOZ9VKDFp8h85d/4cPQ5tX78043nYTgLje2EmbB83inIr4oiZgxDrtLkozJHleAyWuOLIvlWO1l4Uplf6+uooL/5+WeUCuSGUM0wgXfpn+I2IuRhVDVZiChfp51Q6D6brTdOzNcWq1dw6Vld67u8aCLF1EVZ+xM/rnLLBC7MFvIw44LqHvmvGs/lpE9nMNx5L2KfpbpHSBI0IH3FkLQe2Qz8OMZpIa+aga/DzrBpEdwIDAQABAoIBACudXU898AjKPxN6ujZ7maIoWfTQ9SZuI1TcrNomr4+i6hHWrqb/RUWRbMkuhQSd9czFf/RBMQuHlJBT3bJ7bRGaqAly9iyumdMY/A1RvdpBfm9qGIvkfIpxBngzHVz4H7lpkspI1XlGx6c1CRDEpa/TaDwzUhUmGIvszRDvZlfqQvjPjyYSV5Hdc4ywh5zjuSFlxOD/9gsPRE5v4M4FGrGv8cm859P1u95Wxxo3pWincpzjvWw2LpsUGctyU34MhErxh86vNhP9v+nR4VkdojVKkHQTYnPKUlaKj6F+IUSj8syxuTJb8bs0GBuvcXW9AKp/K0xq/GBC8Cu/XN7Ln7kCgYEAwZoqLnU9OuwkcN5AHYW7XsxmVCEnxOsncrUbIzEKPvy4wELdOCVVrX66zmIjb+1+mhaz+mGMGEpkVMBld3wdDfmGgo0CAPlF4efH1ppMzUm2aZ+HYQR8KMH1XOT9qjbGEnLeWcANQT0vZPpe77PQLNwLJ1zv6EtXMMrEH0s4ijUCgYEA88zCNsBtB07ayFr9r+RCfHx/X9wFkT59t2K+axIfZE02f62WWqJCZYMlZu9XAbYEQ94H43/NAL9wfA8dgnF7mKSL8stJKt0g2iPa3MluF4Gq5Y2XYEVf/EDEhP2jh8p1l+xs18rVzsQQ6b3CEU9ytmBJWvkWnwVXf+ZnsCFECXsCgYBM3YyJzXp1/nOpbFRAZGw0AytNk6xafpK29DjGDB5pS6V+kA2M0SXnMD2y2zv+oGh3fTQP4NLigga7r3eZrOlMNxm0k4+MG2wneQLarYB4sR9/aBsz5bf15qwoKbKc9gpGIN0u/RVGJai/irhOqzGn3eV/x2Jo9CC1+otLcW4NUQKBgQCOOHlnZTN1GuwICwSIkhiy9BF+AyUASLsfuquoXEcRxPUw4DugnZ0sCKhN9vsDlYHBcYmajhgyAnuE83BcgwT906eMOEhzh9G9T0NCnwLpFYxzIvkWgQHwbnv1tNyrv1CAEryf2cSGPNw87qSCYp1hhKPmPP6UP5J+mxMLrSw6dwKBgHHFweDS2tw4TNxJQjhfQOp5t9VQbQffFZAqpXGFTc4vf7XePlxIGoIpOg4ShHCKKHSy0PtsLe7QjLrdbMkyYh8oGqgNe5CYTzFFDeK6Im1DoiqNWT+YUWF/gzVRUSpo0QW+4J1hfChG2URp9KbnditXKsJ5Vh+QayHPoZwN7Kgl
apiServer: apiServer:
port: "8091" listenAddrs:
- 127.0.0.1:8091
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw==
types : ["tree", "file"] types : ["tree", "file"]
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:

View File

@ -3,10 +3,10 @@ grpcServer:
- 127.0.0.1:4530 - 127.0.0.1:4530
tls: false tls: false
account: account:
peerId: 12D3KooWA1MZaN1U8NHDnkvbN5wsacRGvbn7dd341S4pAzXofSng peerId: 12D3KooWPHN8pCMgVaNfjzuXhHjsacrryW7DCyicurH3uKHXCyE5
peerKey: rLHblNZKOvJxnAKrwIlxkWy70J3aXDiCYVr8iV+PyQAC0LQLKUjXGJzqOdS4tMU0UUPGNo0VQx8q4YHqqt3KLQ== peerKey: yHyVKOM1zEIbaHgwIAcBD/s9TmYQj6dU3dSzs5OHyBTIEpMC+jaTKKmS/5QCzgLzJFBnvayFtXwR/dH9G49M7g==
signingKey: rLHblNZKOvJxnAKrwIlxkWy70J3aXDiCYVr8iV+PyQAC0LQLKUjXGJzqOdS4tMU0UUPGNo0VQx8q4YHqqt3KLQ== signingKey: yHyVKOM1zEIbaHgwIAcBD/s9TmYQj6dU3dSzs5OHyBTIEpMC+jaTKKmS/5QCzgLzJFBnvayFtXwR/dH9G49M7g==
encryptionKey: MIIEowIBAAKCAQEAyzE3C3bWEdKCJ4HbBfP0psg34ZsdmiZcflOu55aLLnl2ctzWv17SO6dU6C8XEoVtJA4V+tvfsnQTro6sIy7DDcDpGMnA7HmLHzK9GFKQyC/9EzEFg6s9F4A6ZkW/hyQNNfE7NQBokJj+uvSXzw7wb1b535hvg+o+ZPdeQQfcKFIqZKQWMXOHHSseVV4JH2kJ7BNgvmRU1EEkZ/l9FmrdvDDSUv+SgLz0ogESQv3yR/bwwa07BVaMCAdwAMZAcD04KUjEGpEmHfsDERYRNGvOJ5bnJSHTI9QEow1P53CtOMVQ9Ak3YhqyycGtvaVmrY/CfnFJzUbb8IDmvgW6jw/rrQIDAQABAoIBAD38mJdFvI6ZUp1szv1k6/jJUcrggEpbc5ISQ2RhF7qo0Uq/NkARVD9gj9V5MCe1TpNWPLxXwUl2gd6Zpcfh5x1WAYZPXiyF87wjxW4bGhIIGcN2DAGcBroZozc6BfDbPbB8FBzaMAwUsHkmTv2ayByfQwFERpjOqBQzJqzeEfq2cxFovcQdyhHk3WmfH1+zrGENs4IVVmfmIG1LzXehaXJ7jHqlryyKyKpUmXOmymEtSB5It60pl+9RNNlaez9OzreWgE4bQaeQU09I8105YdIISmvZWGZ6PsBo3ma+Rj+si7zYGLF5CsbGxT+U9olpiO/DW+UbfrDHy0bAArlDOD0CgYEA5dI1b1GDwAifd4fR6Zv64AMFAFMo5hWW1EHsUtXVo1UD0IgheI0oxg4aqs93SkL7uMVrM5rKjfstFcpWfaSfzy38+8mneRsbsI4d17RR5g0F4D+2/uLRYRRU74m4ThQjfP6wf+eDAM1+rdmT86cyQab5y1VU9hqd159xCderu+8CgYEA4lZ77Ygdy2mHmfdzFyQ6eJJhsC5FoapJWnaw7LISEiJgnAun+qeIl1r3yFbuNK1Wx55qfdvz4v7X0KJV8HwFgpxzT7CoUybT3SncItWPwi80tq/lxklZvq6LUeOiNQrpGvECCUrPQ3Wdl0lcmOiUw1GXliAQEVdzBOT+0hGMZiMCgYEAtZ76O47f39LwszXS3hs2l/HK8gbGO460M+olKRF0VC/LY/ExAmQL5Pkgefya+UUWSV866P1bNflaF+5fi8udv81IMHOctkiGCXFGhEEst/Fyw1WW+LenYGEA/oyH6qxfn1hng60iCnBbvGhGVDe9r8SVg+tbyWIfe1e1rWGThmECgYBltGkBpn2E7wmw5OGBj5T6owRkj5ZYe9V0YgtEgQvfvDTfSdmUp32YTZc0HePyJcXt80B1B8ZCxTMjHB8z7fbn5vdl4sLwgm0HX4z81ixAHMg6IzZD8Kf0KCiQhpJX9Wwj4BKDLGuQK6TB24RRbYmTbvGH0yaFNF+J3oCm0p3dMwKBgA1TTXLpbL5lnBaAaWAHYSV9rtqvBkyVfcnB9/Ez9MNSBOQIbk82w9Pb892qjcNhTAfgRNrYTd6JZl8Sov98T0OJW0uMHFV04NSqo+RLQTaGjMfrWQ2ZWfSM4tFkoWA2mFh+R8VblzTJObdu1zDyuVYscfTv3sFnV/QX+zJWJipB encryptionKey: MIIEowIBAAKCAQEAu7C6g3bFuQb113lDuKJKa2zzeZNQxdjEQTcC5NVZkt5Qbz1cV4o1Rav0+nrMYT0mRFz6HPElUM7D1o+e/FIxrCsVnoCm4hinORhpilrR/DBXpnSTMmRyBIocaBK0T8shY4zNMYztQ0eiwkGZnxJSqi3Jk+oa7B871YIVDxzgD3AkOkTcRnFR+5SE+B+2G9qzhvRVj+LvjdEbkgnqMImZOPGsa9sSCfDrC928aSAokick4u8JqCfDnl9lYLlBYaVxGipiMayIg8TgXvUhiNWKrCoNyONHDtAKsmrTDj9DWEWtdX/h01uHrWBGq1/AVUpJ1w/5zHUYKF7kopTEskTYwQIDAQABAoIBAHhmiW817OahwWkFQF0btrOtA48U4nbYdCUFnhSfjEN724tQiIEbhsr34UIhLiSeroKiRkv0oaRxzw0/upRQQc8ZIFg6XVOizvsAXwvC8PtfI4sDMz3bU4z37/sPLJ4XR4bt1t+XcMh9FrqYjGyPu3mxv6LkRXr9Gkv/k3TLaCxd/88AlxLNquCYw5HKzZIN7XxzvYRHgn6YULSE48BewpqPPhSS5APItFyFoE9esafSBAcr54LSlwJ4X0Vee3QCxy1WZl17PzUE3M+lGvQ/gdsm+WrY5zUP0MTz4z95urknrPIP8WDXrfK+SzEXwrBvP1XVk1Sl/KKBJaAf+NMS7cECgYEAw/LEz+TuazDlsSAe1/fx9UNHQOAy5hrNIHd37uWaBUC3DszZEDqenJ6WZhtJD4DHfXwqtvXuj9Ju76YfGInFxxucg8AS4cD4+J+KfZ3p2JmYz9d+f/wPXtvG01HubV/KAPVdpDrN9QF/U+YC3W3QAw30V40X1nzgoZWMcPwjITkCgYEA9TYTh9U1oV23meaXUE8ux2ubufxy+Y/J4x57Zp77ttEU8xRTCKHAPdgm5PbMwhXTsUJEoFrH06iTkbwy9yIjJom4sl00E+p9//fEdCg8sEvpSJms6TwB6CkPsWgkwqNJDYwU5XLXd8EP16WZ83vyewZvCz5ssn7UXq0nKEtk28kCgYEAwHogSfafHDwT5EGhCpRL4JgNzfRtCwsYo+O2s7xl5vMC3k7qib6LP12obvQueEQPsXvemYpKpIwY3N9ZfEkZNdQxklmCMq/T4KUW7P3JTzLRoJgVcrKuhodsbvf0NQv66aYcLc51sU2fPVKbTdcolVeHxNibqd1Q6mh0ZCfIekECgYAsRxl7u5o1izCuD59fFw1BYUL7cIRqX/Z6lnR98VNOja6UviTIODz4beGIErCik0JojajKs9nFdHlBJZSmX3mtacz6GC5hMkSSRfEpcGKVCwAS5fz9GKLXgyKcTEvnAYkdcyAK1pPlwezUacjE2KrOYDkI9Lq3+ILsnaOmeQa7UQKBgGvHLrUvRsi04mB+TVQYwrlwRA0NNsxQTMek1UvFlpx/KN8oaDn7Aylao9zxutXP1jBH3kYmhn56/9lJpluDWJAKtBVXl9a4dh/ppC3WTAloU3+4u0aC0Mk49Hg9730S5LVozqH+q8VWiFh3qbxkrlE/4yocWvm18X5C6+kejKOh
mongo: mongo:
connect: mongodb://localhost:27017/?w=majority connect: mongodb://localhost:27017/?w=majority
database: consensus database: consensus

View File

@ -3,10 +3,10 @@ grpcServer:
- 127.0.0.1:4531 - 127.0.0.1:4531
tls: false tls: false
account: account:
peerId: 12D3KooWKyYmekF5ongQGMwBgx4ZsPDQiyFjHtd5ZfKGsoXTYY7h peerId: 12D3KooWA5veToUAwEVVXV6PoR4dFH91HQZA339NZzqeT3C6mMS7
peerKey: jRWkSxzPtg8SF3rJ7oqhby6UvS6fnWGOO2GlAePHqkWW7xWHE1XC2R8Wt0E/4sFVhpam5OKqyIm9aDsWiILHmA== peerKey: gGwpn8J8b1WXK3Lhaq3NnQMix+qQsHNRxAH/DUalvM0D/G9dc/GRiAu+NDtGKRc9z2YAw6HKJ5GJAfzWTMDREA==
signingKey: jRWkSxzPtg8SF3rJ7oqhby6UvS6fnWGOO2GlAePHqkWW7xWHE1XC2R8Wt0E/4sFVhpam5OKqyIm9aDsWiILHmA== signingKey: gGwpn8J8b1WXK3Lhaq3NnQMix+qQsHNRxAH/DUalvM0D/G9dc/GRiAu+NDtGKRc9z2YAw6HKJ5GJAfzWTMDREA==
encryptionKey: MIIEpAIBAAKCAQEAy3UBKE5OifVxeU60KbYUQ9OFob6uixxauUVn8cn24ZX9C2qPAMLQGTYBcWp0GKILqRMgcDmDV1DXF4dNzSYQE4qFDvQ0C5ltoV9vDBAxhyDEN6nftD4K2vvn+fBVYYAXJp//I/2YcdZpOzu7KFHPst74tnFZB1+7LX0oGToGzevFKgqmvoQ1LUj7OqWnINBz4jA61h2WMp11j6/BO71kEeMdeMJyhmO+w6oFlLhd3b6Vsqd/nIc4SKh0yS3jdn+OchgQEMHvNL0KrvExPwdnzQGtU9E2nrf193loeFoCZayX29x+aDgTah2V8JlcN2do40q9h3dJJ6FCgJkk5gBz8wIDAQABAoIBADy0Ym4GP0TGaN8K7pJrc0xxdjO2UxnKkf8piEQKQJE6UU/wsU5G0hRTmsaePpmC7/u4aztQzbFlu2eXxUzqiG1sLRszHbxAQQefE+EDi+OHkUQSeV6sDE0eUC6w2KjIsR+jKVsxtSRyFt/HiKYVEuWJxaeZ1jhvBcgiya4NNC6IG/wS4JYG5iPs8QZZPDT+geR2y1jVQdttchVGxKbthMxDBPfSlG05QFhb/8frCfS+jqBHla1e3UhBfdlA6elZW+IxOoxoKvLLZtMrI5+3D162ZBsfoIGXuME3YqovMBdISnRQBbQ9gsSZlYQsosWofSd2JPxVOm7YdOmOIo4sEcECgYEA3F2W2vQLdxtJ+RaLPrGICtNTXwkP3Fi5KGT/QFGCguJpGo1Z3sGgL6dvD0iKBBCTcmyDj3eBGYW80B/2J+tRiAt/0ME413Pfa6txl7LgKNDlFgAb4/ycth0TocQQE2oL1OawHBr+BiE2b5IbIOyi8wsaQNdtORYzRLS9clieWKMCgYEA7Ft1H2/HAQMBOLeyyn2LMaPkewe5TM/6K+CoDA9orcoRmZ+B3ht2iBkcJE3Efa0c2YDDbL3GENfUzzntF91auyC/aKI3A8MxBZg/6QEiTytgcvbCSeXkwZUCJeNr+BAFLiWOE26sg8P2cJPT5JfjgPkqA4dLWvqwvMFe9LcInHECgYEArVoGSToAJvNVrthYM7puva1egX1cd8dn6OoCjjNQyuuXKOcXUo/ZFoPNbyVuRSJRC4tntx2Ydl5pmQP7nY2VdsMtCihmMb8ae9XDp0V050blX/g3+JKJKQ4YmoHk75DVu+a5lXJ6cJICA6TZKH5e9Xi/b1DIwEbBkAPqoCAseKcCgYEAxSTj5HzPeMCQ3EYdE1j0KUuS4CvpG3C+MqsIgEa6AXtygrjREfnGPG71UjKrmkgysBj+6EzCUHo2P0MJx8YST9NY1GW5jaHZ2djMNgWEIJUFtd6s4Aapb+5iBEhVXmu+ZmdcwkimDKH/hJdJPnqSgJlTue23pQNFN6vzEBs7S4ECgYBhY2YJL22+btVAYR6g/pOkn+50h8S/TtEH+NUL0SKnv8N96WvoBjUJapgNNrWPzzUgmGzS+uSweSTGM5LFeidNU4tEHZ1yNt7nrlnaJP2anGgVp3JcvNQiy1Ffwvs1efo0c8Tc+fORj9V4fhdctpSAoISETDtoGcZbQjUtB/aqYQ== encryptionKey: MIIEowIBAAKCAQEAw4BsTVcK6Rnt3kYtvMZ7HU3EmD6uQzjn0bqoCsFKFNOMh0x+GE4aDox6j8rEzbeNWFwkn7RI6kPuByuSxe5RPG9QP3mxoIgWc737IKx6X0K9vBc8rLTgbr/OCctQs5zfsvEYZa4sKG+mfXPh5oxNsLfAO87OiPsTEPXLYTrEGZ4GZ71HLO7EBsI8N4JvNWZVQq3bbv+S7kiXtXpI1kdfE1Nu5XZIVw3dSEWoP3X9Tp9zavLM/obwoN8IXFGqAbEKOZE9zZkqvwIVymFxqEn7bcqtkfhbvvyTpg/VSeRAQhJkhmx92QDgz8mt7d2ADan3hgqFO68qHK+VlH7D0eaMOQIDAQABAoIBAQCOG42d8kV2B2kGhxC8BbJ8LIlY+UcGihjINNvtZW8KEHQ37PxDgpIiPS7h0syXlHLj5aahiBTwZIxjHeNEiOT3/xnf6f+Z5xIa89/VckpJcGQmkuWBzMDPABEuwWFaDg/1LJdFYgOrKO1mh5OPWDEo4YiUcNFkdMz5KRG7DVJ6I0NNm2x4sRJf8KVfLiOBDX9CKEUpmXZCciUlA3PnXAiJwpYxHoTSktqMrVj7YWgUuaYB0ZQdaXTG5jPZAL7zdVP3Ub1h5Oc9i56UgP0qAo6uXhQR+Xr7wKptnQk9g27zddx7ofa8NtnDpgzMOfXvJjWsMBB8ego0rQjydUihsvLhAoGBAMree7cd/NgqXgDc8V2zusb1gZ0Ao1uvCcYmp/w7v/tUF/UOuvjYuFkHosvHEOjy3gHNrnFYcj1US3K8OFIRkp7b8TKkEL/ho01SVI9PMfczEws5K6ufBZQ+33hJ7+drOlirRQxW8lIZspL3im/CLxm9K2zSfj/oMreO0ZY5jM4dAoGBAPaz/DJOLSKzeu9LBzFjfDMhYN5N3dLHIG0dPIDYDJYyquXYIARZrOD5wWh3WahX1YyCC5bBgugRi3SG0/IaKZQg2+/X70RdLXNK5sZHxR2ZildGFFaA9ERLYy9Gq75hAGTA0dt4CA4iM90jy0Prwoya32SF+zywoMcGV3LLX0vNAoGAPQya2k5R6pNFWqkikXomuPzklmS8xDh2joTPhJ5Odcmms/5M0doWD+S2XvB27EM5//zvg/iD2GTnl42AvWHAZ8H0YbLxv2ydggVGoSHJ/YQHNRdtRuZB/Yy2HzLQ2Slxk4Fm9AGuRnqpPIT1yg/7sJk22ja1+3Fa4dY+yCBleRkCgYAU9L8Eiu18mCBmOUpYIKpJMZmn6JdiMzYG7sfX7gJLs+wecBhwJinwRmbud8zu5t8l+1n+qVt0WSEuedGBLEXB5nSoUABsHzogJAmsaCZPWF6PAU3y9ytIrdq0Bl3KYzUEWfi5mt2cTb14GHVIxLsW9ITrZhIsWpidr2U4RBxJNQKBgFl5qZd8wFwm1kv8j1BtiGMN3e9cIJlfuIm97SOuaEFSwo/QWnhLQ5QBNwIijXDx+Rx3jPPedMO/fYd8IjFdG1x+1g4XVlnCV8PMCsGFwsu3/Q4Av9q2uflsZlAc+6vdjB9uEr4jhiKd+j7f5SWpPHKCUWyeem47WSjyq3dsM7HG
mongo: mongo:
connect: mongodb://localhost:27017/?w=majority connect: mongodb://localhost:27017/?w=majority
database: consensus database: consensus

View File

@ -3,10 +3,10 @@ grpcServer:
- 127.0.0.1:4532 - 127.0.0.1:4532
tls: false tls: false
account: account:
peerId: 12D3KooWLgWXJyeG869h3Awf9s7Jt7dw9ZnNg5ZFkMFKSHs6Bify peerId: 12D3KooWS9fMHSbogWfa2o2NLm2Y7o3SGXojn5anj5zPz1TeZDz7
peerKey: 6DyqyTRgR35/TNWpEbqVm8NbbmOULNuQDYEk6C+ltyyhbVs1bhOkA2nigRoE6JFip83k2yVjsa2r4ST85kW0OA== peerKey: UYx7nyuYqq2+j/t8kTZczAoXCNflp1FNW60tNUfkEtzyrHQg/MAHjYwYGhYxzQ00xsntqLsuA0FAuyR+YtVrsA==
signingKey: 6DyqyTRgR35/TNWpEbqVm8NbbmOULNuQDYEk6C+ltyyhbVs1bhOkA2nigRoE6JFip83k2yVjsa2r4ST85kW0OA== signingKey: UYx7nyuYqq2+j/t8kTZczAoXCNflp1FNW60tNUfkEtzyrHQg/MAHjYwYGhYxzQ00xsntqLsuA0FAuyR+YtVrsA==
encryptionKey: MIIEogIBAAKCAQEAqCZtyjHrM7jUZNyZNchUAgYIZb27YRRsfC6ca2xgdbtIjq0ts9af1+JQcmHMjGyxUTvLjx4I4IPJzDF5KYRwiGSWM4avhfxKxVToW0j8UlqQH+nbN7/TmmQfW8+L4CsgaXcf34uE+CfnyoUnwPoWLe/6SI1m5n/99PcWa9X8monNoTSMoeSOCm/csyK+BBGW9BTOMgo+2Ceyu44KcERl/pdkBGmba1xz3SogEq1m7cpG2Y0Hmd9dyHVJU2jSFczVJQkWF6RuifRoGcjdtbRrY5E8LsF2CM8HeeAZ/0g/q7yoR6D/nCrWaejszXObi+GNEo51EdJW+7gD8g2U6vUqkQIDAQABAoIBAG010FbjhxRntiLwF94Th2RtEKUrznil8DPTfipTEG9GvUBVf/puqhBn38H6fQSzT5MoF/STGEbhsX4an8v0RbaARgGfN375NoLlu6gWRjMiuLrRg1y5DTEYWDmkGf/1Yq68/QmOr0URff1N8Fzo0ODzHQZkOHH6rTGeDYTqTY78ZfU17yGXoNSmXycAqbTGczBP1RvyDRd4mIuBg11E/+A4GBxe8QaSZzJsyfvtBi7jUqKgdDDDI5Gz4x90NZ90L6jRFNvlhuosGETQ80oyNN1soa6tVSq7UhGI7+wcJDyaXQF32/TnqIXArScH5gRLxHiP+FfTDCHzl5iZG5m/D3UCgYEAzHe6oorAELbpcRaUJQayOkMJIAI7KP5EVI2IbP1fhBaW+5BYtzGlxKZOXWZA057E0pjwO99rmVNs2rW6mU0mCfw9hP3oWv4EgszU2DEx1+iHhNF6cy/zGDh3lgDNXgRPoBRR05IS1Ffs8uEgVfhiVjtiv4FyrVE9fY2cTH+7YXcCgYEA0od8pJLXOhcj1ap/1Y0phaHv//ulSqLBtKEQTy36zDw9DfcIozB8LCIK/Q/3nr4RHmd1YQVRDoTB9pX8eUuoJvM3Do9CJiH5/0PXFgIOZZsDXtl/TmL/1diHw2isttDCQF6I+q5lRYlbA+oqc8Vko2c5LQchXE24oz9670gFFjcCgYApDSjVlZH2SSMZZ3Ua8fs6o1bjrE8Abfx+FWR8rWpN9NMfct28+iTUFKfLLMp7MndF6Rriinrp78v9JVtviAPJIXGgj/HkwvdY45MgTNA7Dx6WVhCFq+zcwgmQfly9MZRjCXFcTwmkxHp4USbS2+mycn3jATRrA9KasKHe4g5XBQKBgH/xPtp1Mr9m2Kw9FbseMqG3rDcRI36cMsQnLdYwxz3fTetyuZkTGiNn/O2WCpI6SAUGMttnc78zBv1oYSsFw4cIP+llPnoWI+vxuoDxdvZgoke+PhPRLlEzai5jKrNfYu3jhbNy0LDVrK5QXMRGrcZwMNsgfjGuOgtbxMYuKok5AoGAImYTQ6e0fliVoHO5CjClQRpj3oKsTmB4hwtMofSZ+tFVPOakVM6P4K8UzMa2jcgz3+KgLAD8awpHv0ISO+qdSwG9MgnfIxhz8jxatgRBXdhICHrnqCqwZqyV0hrVmuUeg0uXPN5AisvfGEiGpkAPsQCo3bhAqMD+4QooKCgpz+Y= encryptionKey: MIIEpQIBAAKCAQEAvbd32m4jCtCVSPthnycxPmbKNnnLUn8tHNQZr5Sl2cH1MBaRBEo1DBhI9UXIqd0iprFCvTJjo6s6vWVdLAXgkGpKbuWvh1wdVuMOsq5kQ34m+XEWKXVpSkpNboUh8LdBTrk7NqvpMy9vC2aUt6bKY2zPDnRFQKFeRobfapwntWLoIhmAtBJJRbZuvc8OsFHUQRjcN4ZXLBziRcMqG0IBFPstpiXJNp4f7oB/bWGKg9yKM4vkgaIXEq5RXSvtPD+Zx1ovt4YF0vStWxxM9rEIAAK49HlCJ/aQ7+YYpFGjzjMQMVjLlH+8pcP0ZO75/DgJa1YZDiZ6ICPJ7YADTURKQwIDAQABAoIBAQCdAKRzZAoj/RJOX5sedvTNy4s1If4du5m97dmD8OSAHX+n2EUS48aax845DRNPX+45PSEaKgVDgYUPED/XGtYJLa2DsRleT+EH8shLHv9iy5e9ftT0YnJMRMln2U2JRF8Lo0dZq1NGRM8FBFO22JVNStLgB2D4Z5L5ksx6Edjaxh5wIWxs3ETihzNSZFWvh1bVXdUzC0VfxO6VuiiTN7IMAeL7DiM0/QVc8vk4BKG00XtV9KvtnGqnynpHYvWZ4xRU4GYYwDwLZFWDssLgU+3SNJCeucGrrckC1/73B5gjJ3Lq39dbr2maEdKvo6KdE8kOLQyZxTMHWdAVH6MKGmPhAoGBAOZGlR5V6P/cI8d594VHz8txEp72IsK3Y73acbdqkV4kmvQUq36oj3ObO6ZNhaH3/j+M9xw12eizh2KV512aDmywEHGXbs2FY9Flck6fMRAamOrEkGHUUDdACDyyCRtO3EQMMNndy00dPY/Q+nrwHKLfwYcfDcrJXsBVS6Zy+hFdAoGBANLo+sMU4grnp/XurIIB+3Zahzfoeo4xMiLNRDOy0nuwG23mgozZKaRnsiyxrtBQ3un3cjQS3+mggsa+N95mF6h+aNzM98ySqqByw7v7N8c7LQjon/BxonBXLi/bETLS5+cdRRXHD6QbvREtFVtD9oRZJAeLvS++BdtS1s8vOfAfAoGBANh7JHbnVusqXmyKKfsfXqcoPtQ4GsepNlhmQx+mTNEPYqjxwaOJ/Yo2NmaKXIW/KUM/V5QqwBf2puE0gdTKHqNpBZx0O5N0wjk5wLNPDwXPq1CRyBZgTaUTSmsdCFim04YZW9eFnjl5ssVANipbDuDDsCFCPWoV00DHLx5k2th1AoGBAJmwA+rb8MuZex8OyM4Du8XGufnXglbTKoGJqkUx7YcMETDIZCFWra2Lkp5W69gI1icPlTy09E0+FY3VVsjNBDhXxPoAsiF0TrmUZ2U37rFTQcHYIZQIeiH6pUFiFOpAHZSgE5OG9rLTM7asb3+Nyrkua77D6Rw9D+9+MeHPvBxpAoGAPD6fta40UAA/SB8lLmviQ4odWlbbN4AiUO/oIey6PswU2ZJllHEOY67snzhfafdT8y8pHCQQGDnPELfdB/2b/4x7Pi4+xQ6LepxMkIgBnW4zrbsokbvuZ64anCAvK8cfqqvcD4OFEdh/GlTQHGSzlQ/RGbOAuQ7GTAYlsQmb+So=
mongo: mongo:
connect: mongodb://localhost:27017/?w=majority connect: mongodb://localhost:27017/?w=majority
database: consensus database: consensus

View File

@ -5,31 +5,33 @@ grpcServer:
- 127.0.0.1:4430 - 127.0.0.1:4430
tls: false tls: false
account: account:
peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
peerKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== peerKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
apiServer: apiServer:
port: "8080" listenAddrs:
- 127.0.0.1:8080
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw==
types : ["tree", "file"] types : ["tree", "file"]
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:

View File

@ -5,31 +5,33 @@ grpcServer:
- 127.0.0.1:4431 - 127.0.0.1:4431
tls: false tls: false
account: account:
peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
peerKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== peerKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
apiServer: apiServer:
port: "8081" listenAddrs:
- 127.0.0.1:8081
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw==
types : ["tree", "file"] types : ["tree", "file"]
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:

View File

@ -5,31 +5,33 @@ grpcServer:
- 127.0.0.1:4432 - 127.0.0.1:4432
tls: false tls: false
account: account:
peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
peerKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== peerKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: /6+uYFwFf9nU6fvXQVtpHhjd8+v4dXc7esZzqkhjyfMJWlMiZOtQeb913FXofD5f20WksU0l6i22B09sFFYwDQ==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEogIBAAKCAQEAwCy84lzkxtzgn4ixGm0LSUTujOBpOh9m7XDoDPZnMTmExdOe9a5v/LXzdlCOCuBvK5u1T3ALBJMA3Zgvjv/jPRQUdiHprP3sbdfc6IgZPBFdLKFTc9yAA7GMbI4y7LhGMLGOMOqQXs+DOeImfmxEs3ykLXHKNas5ORnZPVnB6E9Qod8KH7UyMmBjQkOZYOOw10X4JZiU6xJp/E+VVWcmeXgNBbj5xOWMSzM+hhoA4wNOzBxACucaKDmqD6qugzebOqyUVSzFnEbquro+MYTWYdUDjZTXdvxgUUo80MGQ164gZhkFUKrmSpUvu3YErFySEGqAdFNwOZ6y/4X3s0BHvQIDAQABAoIBAAZiNhAK5+qXMbr67m8jSimv6YCyf6xXmLKwenTbxofDEl8D7ZbZqYyqeqDmgiFoXSkErhwqa6NGQtQZlxLX+zNvNFLMQ5fkg3MOpZ7vzm7JYN/3p+8EVxhIUJLWkmh8opBBhaioUg1kNUa59W9jp1CTBl0gF4h63JbB/g5kqeVOllUw7J1igAoaX36nOJGOwIynCWdizhDhgyjR4OcYfOLwcPDJueKTc5vM10g3LuMSK/sJmaD3TkJFPtDHw+RMW6wqyjsnkrg2D2oohXEyGWYYIXo2so4HCez0AB1I1JAxtVnRPvSIp7xLMm7+AkDoq12QYDHfxZtDTpfmvJg+Sn0CgYEAxCd+oribtdQW+JUctjsDbSQX5CeRISH5Ith3jveBx2jKIqQVnoVPz6URHOvnlIsqYYLANB8B3JHMWfR2UmkK11x0OcZecB06+oBoCZukvSXF+GqVHzLAQUxaoEBDCCPneskj5w+riMWBiiGDp32rUnkqv0nh7dnH+GfORcJ44L8CgYEA+s5s5EALj1jyU9w4+HVUyVsIrUitFnQg6qw/Td3Kj+8CXImKlS+rlmbQv0m1aOcvtFjQRIjjzZJAf/ausfAME+MayoNODgZsDk5RyDKuSWzMLvZLAa1LD52Uli5Pg8KtpzKVTn4xE1MbjsQcUNhFRAgrNEKNyuzXzdp4uXgGOoMCgYASXwiTQOsEepq0KXMI9jn57Nl3+uSyz7W/t7pq329+N6hG2ktUD3RMJE+X/9gup2IOw+owd377I4SaIDU8vq3PQc944cVShspRT9lunO8u7+y8uW7B/0TWWMpcG+irSIGTlGcSavtL0gOx5jWoaDK1hLemNss8NZtu/nnpOq+LjQKBgDisVozJMBOHPNLYS4NROAR77p0BdCNDwIBmxbM5r+EQWA9DAS6u4+4Lc5YV+MkonG37N6yU5iz4pFyGCHmqzX/c7JvgSc3/g4FED1TWpu1uiUD/ZHmPiAuSRxYchtk2L3k9g+GFwF8mg26iP+fAxv4VfnXDqDi3hhg9CtSWG4ozAoGAOWZXlFKqzGAfcucIe54FVQnweXG9sEuIPAvWvVRs4406ggNmL5eHccXpPHWTgetsr2TYMqPTDVMRmhBzSkyrYgk+b2tme79HPzTWs2Yg/pzjOfTgw7MBX/KlvOW5/J+dvrF3Gx8AHHZ9QQdYqi/MS1NKb2K3IbD0/m5gL5Pwi6A=
apiServer: apiServer:
port: "8082" listenAddrs:
- 127.0.0.1:8082
tls: false
nodes: nodes:
- peerId: 12D3KooWLn13hDrZ6YRGM517fHf2zS6qhPNRu18inLMpRqn1YGKu - peerId: 12D3KooWPuwdqpDQxWhD2Vh4yskx2T5VMrwdpTZLfACzgsGfQfNy
address: 127.0.0.1:4430 address: 127.0.0.1:4430
signingKey: 3mzfKBWtn7mitFEgq8u4eysWOJ6ySbUs49irfHwcuOmi1YMpobz9anoqd4yaT1owZiRPYXqx5k2Z4sNVRE3kXA== signingKey: yOEpD2+cPldXc2urGuU+szunm7fddRa8xew2uVjaxifRcVzNKhSERpOefjrXaky7PcKmSmTsH/5ZFtcrh1uzqg==
encryptionKey: MIIEpQIBAAKCAQEA3U7b4w9JTKE3TLM1WQ5iqdLbvUuozMp/hDEg7S15Gr6wrtLomMSBkfmVQ3Cu+CHdxAFqUFClItYlSFgtZWIFiSiQxCeaN2dmgczd9T4TlRAw6y6uJXtT9r7FIgizPP4B0/tnzPI6yYgpdwzCV2nRSjw3mMr5Nav3QYs18kYrJ1/Np2Wob5HOoRTUD++pPrToevTb7GNL/irrC8wXSE7oU6S7ix6Nh9vzEHg/V5FONBF/wWD/ri7Gy0j0qgUQ+gjxLWKr8xPDnRAve13zzo+54lGCyVvlm/rwCY9Jx378V1IuRx+S8F/GFuVozHD4XVaoSTtpCWPBQNSKDXgaIIKDowIDAQABAoIBACpMXj6ht1LMJXOldPbWhwkKYjFl+pdZxNGRSkfKvzDbbY2chhRcyp8J4vuG2ApY/rftxVIgd8+Wun1/TP3ppEE43aKAJzubqb35WBr9iGSfOZpZy7MiRUQN5kPBAfEQY20OyiIj0hSez74PVD283eGgbMfpU4Rsn8+JOgBaZPkbPViJLJY8PyHU6vwWw60dye1iJTz9yuBtoEqY0XKxnLaVXTQaWx0Te+VYU8twxDgXFWRaXtHuk7xnxOkCZDLrzIvuOYa5lsLoT8K62LDeXbyHBPhbdW0j4ZYzAOTsaUWpjuJzef9aj3JJdfyADiqb5iu6HHksvKzkZEau34zjilECgYEA/c8ZJm62uJMHNssTJYiLRw89l5hYwIZ/1TXdFRF8+xrTin5opYjpscSTO5bY2IYqLx2xuPiJCY1eGGB9L/RtkaVh51ySzq0d+4zpPIRKFcOOgdxHwlgoCgIhQECyfJZNMFGBUIlPXZ/phvXOXRvWFzDPhqThenVG2QzF+wLP0AUCgYEA3zfviQFJ1FOKJMozYO3tUZFmsIrAcO9hfuE7uuWz0Fw2m1XiwxjuOr1RbsSsh/lKke2h4tiGrlfiFhwCpIp91NkVTFrtFOQxbDxkYLkFiWkZDkOaK9YhKMa2cgEm3p+RGawokjbm51LKf+cbYN9xGaAe3y2WzIE4kNpfWE4SXYcCgYEAoagcrrvpqZoMCDxED63ud+4fHsUsEkQYe6Z5EAg5gH5PqnBlGrofjthTpqqnpxGdILFbFyNFtU3TVtduJPMcLp4Vw5TU9MqSxDu1+pOP1FjgFZpGImSf6+/7Wb9bb7sToujm4nLymAFYblt1exxVuiOeqnWuH58+5tQZ7YyW7DkCgYEAl7WuqZEkmpiEpWh/7vsGdo+6GXbUQG2R9+gg7m+7/HsP6hc/XZYOJAIT3JLzKB84nWHCyyiasNeuI5S5/xbZWtaH8TNDOxW0uXl6R3q41qGFk/pCSFTqiIo16dn6jwgoWCh4EpgZ61KLqs5p/zcd6Wq4ULrtaOTSizC/6IZ3WPUCgYEA6xCJy3+ICCgr8/c7hfd2Ylb3aOsXIffdgALhXjDcrNUCqgB4R+S3WReAwrABemQGl4tySQE/1f3Ru7SzMMciFogGyJ/YSXqSi6Y8oDD7MqlKPiWlN6WY1nSRMlLbkUOqpA5JaDM0kcmXjZpBBQr277GOnh9uKN8zUy5xoptctxI= encryptionKey: MIIEpAIBAAKCAQEAxnE9Htwto+2fVmonkG9/DxNre33n7kjfrZU73JcHmpKhPlRFirig5T8rs2MaTq1R72/8nGBJuSxsz1PnexI3die39pY1OFYfZCZ59LbT7uH/xHcvkVrK2n50Q41KbbGT9BEzyW+XPkKPDpTq3/igYP+yUQgoWLfMwxCCLKXDe6qUC0fuIxR80fvj3XvorB5dnAiQ01JkH4PtCV1OWT6ZpLGhzcYxsxTHozd6LdMOC7wgGhW26dOSa/vZ1t5avbewFVIz0qfqBncunb7tjO4xa3xVYaA5jBbixDQUYFjVzW7cksrrN4CFNBDBGJ8PLS80MuMg0OG0O+/Qi1mbGb2mUQIDAQABAoIBACODAD0VidVcILeGJ65hRYudHg7raSXrRJv7qMrA/EtdEh3lVsyMXb6on1lq0rphqdf/YmVZldfda1tu2G3dxK8QTIuENeHvB48Uk56HWUXWi77M1WZdqQ+QsZ2lGzymGqQCsBHMNnSd1Jv3alDKXWj+WRrHKvE1cx81RRZYU7M9cpurnF5YNjO7L+7sMxUA9uAQGbe3kDVzrygraicLYQpxSNHytName0A+k3ug0qer4I6PmZhhJykkz6MD3dz/n625HSS+X+TuTm52T2b87tL27xXmSnUK7eYWjZ1vQlP1fWmqnac6u5LApUZaRi0tTjtefSjRW4jr1q20RqOp1kECgYEA7Onh3zM9ejATsjW6WISGKiBPci0D7DUbIuGuJrdQRadlkZzmeQ/VOYAuxIQD4GnQDRhM1FyxsqiAWkJOyCLFiMmsgIEyW9/eRhF8NlCVU+DA/fxy9EagfBbVsgiSBwOex24hPXIVYlaHkLAloNoD4bpw0pQZSDWXr+xvMFNwoGsCgYEA1m3sWA/e8ZuXForaUOoJzBU9nwC79bXv2UNktsVvBlQ1o9pbjoYDcVoAPwuBVUL1UwqDNMzPdhDBKBjZmCyjS6zlYD5ZKjF2m8iTyc4QcaBCdM0iyQpSXTmrfMx+hK1aWwL1p8ssNcednp5ExSAaTyNNGVdbtddiQ6/KMPmhUzMCgYEAwDjLsUNr4BXeBTweo+9yw/9PNn5brm0wRU8C9BrMIJe/izPYs+UqxerBB2Vtl8mCqv1KaQuEika5TYJ7VVsRFvk641DwQScUu5k4RQGBB3tWWz1XL+eWEticLkVR5isDyyAKDEbiHtXCTJz/CtGZUK7rF5BeKv6AwpZ9aKJqwV0CgYEAqXDlQNURu+PR6TtBtoypvz3NmraO0GO7KvipPhAXYm3qkRa8IIxfbhPLfAYQZhpqFvuIoJFzIn2s1I2GbExhoSv3eSzrcn7xlbpSpjYSImeb/AYZhbmFSiuHCi/hjeAaNS7KhZPz1G9vaubvusFaaMyhYPP6AWA4QvpHEJpB06cCgYBqR6/7d2hQiq4MJUrBEzLwG4ijnPeq+UVLQjE598hVIj+8UhRZRRcNWVEJxfcIL1v6Bpo8XISDNVRb30T9bPGVnXvC1jutTUbXKUB1/8iXuyH3IVieobch+bGd4v7ehH/lI7vzB6hjJpFzHopfFUn4wacSQdcFi3tRAwUB/L0S/w==
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWLtuKtCPBYrFJV1NdejiCr2s614ppe9rmUXnkTHtAUD5U - peerId: 12D3KooWBgHmDqtXH9SrZfAmwCFsD8LZhTD5dg5wkhdbqFoS8GBN
address: 127.0.0.1:4431 address: 127.0.0.1:4431
signingKey: 07JMoW5cQUtGO9nNIGQo9e99b7Wf/4YvTtNEA0lt4gCkmhwB1EB9ay+kitxVJJgmdyGLxbUUlGqwXsAj0zlHWw== signingKey: l6LFiKqr4ZHgcPbL+DR7KwMbzImufQPFgpoHOJ/nvfUbpb76DCADHuT1I4gIs+XByglnY1KV8jbMfW64XRW5XQ==
encryptionKey: MIIEpAIBAAKCAQEA7cA6J/icl8wseeXkt8oJr5AeYadUAG5EdCOdHj4S/Z7ivff4MOIKAeQITpq+rqhmXxOePYXSpQXE20Y9PW9tuw4gzOuq1ylSG/MWMcLDH1eIxg66rnmUqUbdiW4GGJjVjc9jvN0Up+MfSrUF6fM0jWTFoXVJQIeQQGERCIYjFzjfBl1xYvPghdxNgei/K5ZGYRggT28143XdIH4KTXGtp51hAKoyY9eCqYMtm9wvjxazhPVxO2CsYaqMxBLshY3jfHNqJnx8u6+h4Bl4uUcdbLNUgMcEgk7ehbQp2K0CqNoKXxbCTI6V57UVcJHDIaO5B6FyR6BguzHHNPJ4yd3q9wIDAQABAoIBAQCm2Mf3VRlPzhFIWnVwJXE2q8Umcu8Yfkm712Jj3twk8GPfPS4H4Bl1yjmqMB6xI6zz/CiItGlnNe04lMpVWuV+6CNMq/ZwmKbuxmFE+pFEZYGuvJd16gzR3tGJqJTOnjMAGhK8b8oXJ+TF4NQNooe20ol/DXgiuQAargPuH3RwzjYmF3N8VI4KUc3LaG4TwVXn4LwPOxrQSnfwJlZwLml1HAKOV0qcG0mXX6ZXOpoVhEoRPdQyUHc8ZW+53Agbtind7bYh5TsMVDFUrcgNwnwTOsWjil049la1IJO2uMRluacKlrtyzEp6zqrW8ZJO7mYAO69x4WyGqf2ZgIdA6djBAoGBAPqRHWAIgPa80eXbwCYkRtUG/ONBsQGi7+wm6nyhkXvNXJeokgH2DCgLH2+fW2scfOJuZc9r5WftEjOBvNfr2LDcwdyTSTh21WYcPSZx9HDf2d5/SWTcjNcyU0b5qfWIUKi/Zm9UY7r3X7yMA5dUD/cvu1PBJ5NWFrK1Gm2ph44dAoGBAPLn+LkHweU0fbxQq/76T5yVVpMKUaE9xwrJlUxEDPAQGnLPbFg4JeUt/YPhsOV85W4c4oQE+uFZrF0uf+1fEnS6MOJ+sq668upzC2hBp1B5138wM7615v1rvXVVH6qXfFop67FdBzPHt1NAN43mEIBZHTQ5hSVXFlYSZp9mxuEjAoGBAKCzUVO2IIAeub/iIGpV+dfGk4ptJ0kVZyreCqXEObpdC3V496uqUkGcYJ0GZ2ta6f2PMFzHpmnw8it2mdchu+gyrWL6U4uTK2pB0jZF/7Ak4WaB3GCD0xBxhleO6CJBOvn/R4M/bHcNEKmsYuE7WMIAKvScfPVR0VzsKfcLM5VBAoGAVvWg32zdh1bBZLdku8WU1rPH6KAbFSRuq3f7UPBTyWWaclu7p+GB/4f1aE9V6vJJmKASn7zArAhUYo+REMOmcc9uTMea5F7dM/23qb1HTtIvycLR44ZviW4Wx3iP+5x70jOLw1VQjMME6HLm8I/afHhqshWdiv6ganPv9UTwEg0CgYBSDi2dqg8F7ij5CN+LMDLSn3b8GCw+7efGIt7imm/O2V/FlHD40IA6qGg6DXNQrnoZQt94nMb1cZEvm1dxi6rmQNrhCyoMogAaPqgFhZGq1OjmhVZiXFUWy4WAcjdzFc9wZd3/XtaofRKHLK+ngTFhhVApKypLk3Rg9bCAAjzyVg== encryptionKey: MIIEowIBAAKCAQEA4ltcn1AH048bMXcKOOW7/E0TZYPxL3OtcHXWHSAZjeeTA/rc45G2eaNgyY7Ji+feLtZERbXNWGFBdNp31NHDYZAYwbZmjEqTEgV4yVx7BQP3VBEzglTJaNLTf+XIJnVAEkoHS6ogjC0oXTM6paHu64EitoOCzF9zqL023swjE3HU0dm2xwsUdGnKeO5nPMso/6e3VMavkKnFmvB965ECCBujtediP4lVdIABNVtoMHCoeI5Sn+m7TKqJSyDOIEMhHT3orYUNZWVeAHE1YTM2cI5tSnDZP80CHZ674Z/bKL7Jaznmq87mVt1h9Use2EkxR07/dJuTGvFOos4jHoiR9QIDAQABAoIBAHAr8EluooI/j61CnYk2p6LPG0aaTQJD4/YwHuwOBTviP2OghKgthGzg/szDerNfMyaoveqBvoIGqCZdQTbwwE7v1qTgXA83wYwTtBitQLVqkr1RTOJQXAMbPv5Jg5czUY3+q4DejQSKOE9/XJfKGJkSRH6Hy2C2CJ3dLnzYUqWGO3t70RLT1/sC6p6w3lXdy3dKZGkoR2wva+HXQxVrP8X5HOResXgNZwgMHt9KF1QHVCcySKYiEAefEKTSdKD2fOd4FxLgp3zWpvH3jrX0zd/DqzTlFD5Ns6Ayp2sIfHVp3sn99DZZM6DauMepQKtoSCnXZ+qKhekAwNVJnsVQkSECgYEA4spY9araeFUSl4uXCUQOpCkSshYOPRYN6sBbHsx8tV2eQtCT+5SuNYmzur3c5bkiraGEab8rZfGdDL6fLxQyaqbOmN31Db5kNh/2X+sRnxkak8lsROUWQZRF9doH73FDv6ZlI3V/JicZlOUCfN5BYT+x74R4/c1YXfyuD1J9gr0CgYEA/4K4SDwZUY4bOVCmKQz0OM+RW4PAAH6LHKenTAZNTeDNFFxc2nqnzRGMEKZTDGy0kbT5mBhBHFgShXcAiKxc5/MGkpt8Jcq6Fr5KGU9aZtYKji6mwMTsUndPNQydh3vOt5pOmcuMM6ovanNTvI8k6Qo53OY1IpO5CfOROu0hm5kCgYBnWsYd92YnDsYxUEldzKlLgPhnNov4pNNk15LvP0vaL7cPRhUaw1B9T6scAKjp/GxkasZ4lsnFZM4o37qV7wNm/WwL2KN0Rv9Od1SFtBBMzFkDXvk7kJeK/XLAr0OMiLbSYZeYCFUQ4yLSa2et1nA/TJLf0CR/rhSGiMAedX6DlQKBgAx1137OT33GrFUzNacy1oYeuTv5RNfBVA9lrabrd8GggN/JUU3mRWCexnHZaptkgbnJVZKxPBuhv+V6VDBWF4HIPD3SD0/YfxK03PA3CnWRYppkdAValRvAbcBsiRIeW4pgoAyn/IJYfk92qFK9uFMVCJVZNKYnBhMSKbbx8X2hAoGBAKwvzyAImbNB+493q1R/lSayxzG76bRJ/EseiTqwIec9c4C+Bd/sVXR+Re+xZb0FI/va1bz5CrduTzLSKBmf/+0lzl0MJvWY2+SXfGYdbl4+TTyqgDDfwqW0Tj8pDimye2BneyTmXko1rF+2Sxen7kMXnJLwpqjwZ6TZJuoqeK8q
types : ["tree", "file"] types : ["tree", "file"]
- peerId: 12D3KooWDCypXSyN6ppuMZGxVnBd1ZQCMV4y7Bn187S4duYmf8rA - peerId: 12D3KooWASsipDzkridiMBmE7VSqp8yZvGWPY1VqySgMSZk6tsiL
address: 127.0.0.1:4432 address: 127.0.0.1:4432
signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw== signingKey: SGyNE0dFaQgtgNuzdcO7LB+TEz9VHAOtlQLk6WWkrkQyXiZV3casg8Q2/4PO1Oylc8Fu72RU001Hclj5JCbiLw==
encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw== encryptionKey: MIIEpAIBAAKCAQEA0k3mw4FyexRkLgLjHzYs4Ppeyv6r9ZrP00imNf15JTuM8ajMx5oJX7JQTm8KOLRJjUdZZAd5Gtp0ezfYAQK1ZjEWwCmfp8j8FBgJIDSLpjxl88SXMLgATXYfhklnQvKlQjs/X3Ka4zdTrav2tMH9IAo6TSNZhlPQNsUory1SGHs+KqHv4p0sG8oWuKYhfBj8rWHQdUVptkIBKgojFDeJJD04Tbf9kUakbK/8KuXB6zF5H4WN3p4rMMwkClyTGeYO4LDg5TzVn8NnUi3/b/vO/3us1G/TMoRe/6umUfpQxrwo+7S2T6A4YwetWRp6xALLhp+HfAWnn0lA/D8/w1WpKwIDAQABAoIBAQC5cdQxRa5rddm48PbSCPWeFWkNW3DLDI6CYyedqDvxZwer+QtKXzww1I4X+7ZptiC9odLjb+uMkGHyXZXtnjPTPyounQWZ8JLILUGu0mbqWYwVXp9raHVr2OOHiKaz1D+BnbkOM4L9JUZ2eJL9ZaoNXLd4WdmRp8qM4WI0xqQDzOANx2HhyL/+dJmQeIUND+pdeH+Z+fYowU3ho32txNvBnMXQhF1T5K9i1VO5W49RAjIRbENsT+paPGKbNubDHRt1j36ktK4eC4HSdgv8tccdsGyrEiIbAt1XsTZfM8ie4D3A8RhSxiTC6Fkgv6vIm+iFTLzBFZKesOBcd8sfKeyBAoGBAOts5PQQJhldPDzlbnqzxMOR98WHbkVZjCqWSkNA34vqyFuPcRuX0rHK/qpg23ilbUP0fGMDTGgFzTt51FZLL16SXyRfjNhzjdmryryeddQwbp92ta2GEgnU6t1FyCuSCtcLDKJd/D9A9dC5UI6z+ES4TOnbR3nakXK9t4cUOFthAoGBAOSu+wL+SEA5erR+m3LpOsELK68CCJQPxn3VpoVfJZawgF+fEoXVMLTERxJput1+ADomIEdNc9ex86TjKx9gJ4piNHscRPFeT/AgESOIGHLOc1gk2DPqNj6wBIarUJQ9t4KcHScboh1dTPJeqqv2NSwIiLQoqFUIhfKZLnrW3zwLAoGBAJh0hC+o5YM3ZXLqAIllMN6VACbidP5j5ukNOjojIKCzAdyJH24G+2I3WoNrBbUzK3b+NC7KTAhw+V6ynlbjiWFs2D/twH/LFOkI3tkWpKcsVfbeIPimAbhsMUvpjJ7qjCqF9UCQLHGp14W6+/ftg7C8yNIINlkquVXclaTb60MBAoGAPqmL8ogG+EJH00mWAujRxq/u6meePiQMedKfbJBj1mTK6GjIRI/kZsQZzXvXTnYGTejAk4kvov0KDDaLTG+mpg6+3rUiVxlGwj+nMptKR7s2dAK0k5UsBAVrWBN9YwF+VXW9r0etJmq4ePljvvcaHtS/0M4LQjGxsoYy7EoQpX0CgYAhnf0McB7F1MxSjB0soMNv/v5utVzVihS3re2yKNdkI/YUEMB+yU3Q4gh+OljjBM6Y5To3BsQBAx4l2CysMKFHjIE/5AtdbvIS+chZZqB3vcZXSayvX8P1Z1uFdw/saiO2cRDJmR+TxaOPa2C9SzDoNTACthwLErHfzvEvVroKmw==
types : ["tree", "file"] types : ["tree", "file"]
space: space:
gcTTL: 60 gcTTL: 60
syncPeriod: 10 syncPeriod: 11
storage: storage:
path: db path: db
metric: metric:

View File

@ -7,3 +7,7 @@ build:
test: test:
go test ./... --cover go test ./... --cover
proto:
@$(eval GOGO_START := GOGO_NO_UNDERSCORE=1 GOGO_EXPORT_ONEOF_INTERFACE=1)
$(GOGO_START) protoc --gogofaster_out=:. --go-drpc_out=protolib=github.com/gogo/protobuf:. api/apiproto/protos/*.proto

1865
node/api/apiproto/api.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,233 @@
// Code generated by protoc-gen-go-drpc. DO NOT EDIT.
// protoc-gen-go-drpc version: v0.0.32
// source: api/apiproto/protos/api.proto
package apiproto
import (
bytes "bytes"
context "context"
errors "errors"
jsonpb "github.com/gogo/protobuf/jsonpb"
proto "github.com/gogo/protobuf/proto"
drpc "storj.io/drpc"
drpcerr "storj.io/drpc/drpcerr"
)
type drpcEncoding_File_api_apiproto_protos_api_proto struct{}
func (drpcEncoding_File_api_apiproto_protos_api_proto) Marshal(msg drpc.Message) ([]byte, error) {
return proto.Marshal(msg.(proto.Message))
}
func (drpcEncoding_File_api_apiproto_protos_api_proto) Unmarshal(buf []byte, msg drpc.Message) error {
return proto.Unmarshal(buf, msg.(proto.Message))
}
func (drpcEncoding_File_api_apiproto_protos_api_proto) JSONMarshal(msg drpc.Message) ([]byte, error) {
var buf bytes.Buffer
err := new(jsonpb.Marshaler).Marshal(&buf, msg.(proto.Message))
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (drpcEncoding_File_api_apiproto_protos_api_proto) JSONUnmarshal(buf []byte, msg drpc.Message) error {
return jsonpb.Unmarshal(bytes.NewReader(buf), msg.(proto.Message))
}
type DRPCNodeApiClient interface {
DRPCConn() drpc.Conn
DumpTree(ctx context.Context, in *DumpTreeRequest) (*DumpTreeResponse, error)
TreeParams(ctx context.Context, in *TreeParamsRequest) (*TreeParamsResponse, error)
AllTrees(ctx context.Context, in *AllTreesRequest) (*AllTreesResponse, error)
AllSpaces(ctx context.Context, in *AllSpacesRequest) (*AllSpacesResponse, error)
}
type drpcNodeApiClient struct {
cc drpc.Conn
}
func NewDRPCNodeApiClient(cc drpc.Conn) DRPCNodeApiClient {
return &drpcNodeApiClient{cc}
}
func (c *drpcNodeApiClient) DRPCConn() drpc.Conn { return c.cc }
func (c *drpcNodeApiClient) DumpTree(ctx context.Context, in *DumpTreeRequest) (*DumpTreeResponse, error) {
out := new(DumpTreeResponse)
err := c.cc.Invoke(ctx, "/nodeapi.NodeApi/DumpTree", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcNodeApiClient) TreeParams(ctx context.Context, in *TreeParamsRequest) (*TreeParamsResponse, error) {
out := new(TreeParamsResponse)
err := c.cc.Invoke(ctx, "/nodeapi.NodeApi/TreeParams", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcNodeApiClient) AllTrees(ctx context.Context, in *AllTreesRequest) (*AllTreesResponse, error) {
out := new(AllTreesResponse)
err := c.cc.Invoke(ctx, "/nodeapi.NodeApi/AllTrees", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
func (c *drpcNodeApiClient) AllSpaces(ctx context.Context, in *AllSpacesRequest) (*AllSpacesResponse, error) {
out := new(AllSpacesResponse)
err := c.cc.Invoke(ctx, "/nodeapi.NodeApi/AllSpaces", drpcEncoding_File_api_apiproto_protos_api_proto{}, in, out)
if err != nil {
return nil, err
}
return out, nil
}
type DRPCNodeApiServer interface {
DumpTree(context.Context, *DumpTreeRequest) (*DumpTreeResponse, error)
TreeParams(context.Context, *TreeParamsRequest) (*TreeParamsResponse, error)
AllTrees(context.Context, *AllTreesRequest) (*AllTreesResponse, error)
AllSpaces(context.Context, *AllSpacesRequest) (*AllSpacesResponse, error)
}
type DRPCNodeApiUnimplementedServer struct{}
func (s *DRPCNodeApiUnimplementedServer) DumpTree(context.Context, *DumpTreeRequest) (*DumpTreeResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCNodeApiUnimplementedServer) TreeParams(context.Context, *TreeParamsRequest) (*TreeParamsResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCNodeApiUnimplementedServer) AllTrees(context.Context, *AllTreesRequest) (*AllTreesResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
func (s *DRPCNodeApiUnimplementedServer) AllSpaces(context.Context, *AllSpacesRequest) (*AllSpacesResponse, error) {
return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented)
}
type DRPCNodeApiDescription struct{}
func (DRPCNodeApiDescription) NumMethods() int { return 4 }
func (DRPCNodeApiDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) {
switch n {
case 0:
return "/nodeapi.NodeApi/DumpTree", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCNodeApiServer).
DumpTree(
ctx,
in1.(*DumpTreeRequest),
)
}, DRPCNodeApiServer.DumpTree, true
case 1:
return "/nodeapi.NodeApi/TreeParams", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCNodeApiServer).
TreeParams(
ctx,
in1.(*TreeParamsRequest),
)
}, DRPCNodeApiServer.TreeParams, true
case 2:
return "/nodeapi.NodeApi/AllTrees", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCNodeApiServer).
AllTrees(
ctx,
in1.(*AllTreesRequest),
)
}, DRPCNodeApiServer.AllTrees, true
case 3:
return "/nodeapi.NodeApi/AllSpaces", drpcEncoding_File_api_apiproto_protos_api_proto{},
func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) {
return srv.(DRPCNodeApiServer).
AllSpaces(
ctx,
in1.(*AllSpacesRequest),
)
}, DRPCNodeApiServer.AllSpaces, true
default:
return "", nil, nil, nil, false
}
}
func DRPCRegisterNodeApi(mux drpc.Mux, impl DRPCNodeApiServer) error {
return mux.Register(impl, DRPCNodeApiDescription{})
}
type DRPCNodeApi_DumpTreeStream interface {
drpc.Stream
SendAndClose(*DumpTreeResponse) error
}
type drpcNodeApi_DumpTreeStream struct {
drpc.Stream
}
func (x *drpcNodeApi_DumpTreeStream) SendAndClose(m *DumpTreeResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCNodeApi_TreeParamsStream interface {
drpc.Stream
SendAndClose(*TreeParamsResponse) error
}
type drpcNodeApi_TreeParamsStream struct {
drpc.Stream
}
func (x *drpcNodeApi_TreeParamsStream) SendAndClose(m *TreeParamsResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCNodeApi_AllTreesStream interface {
drpc.Stream
SendAndClose(*AllTreesResponse) error
}
type drpcNodeApi_AllTreesStream struct {
drpc.Stream
}
func (x *drpcNodeApi_AllTreesStream) SendAndClose(m *AllTreesResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}
type DRPCNodeApi_AllSpacesStream interface {
drpc.Stream
SendAndClose(*AllSpacesResponse) error
}
type drpcNodeApi_AllSpacesStream struct {
drpc.Stream
}
func (x *drpcNodeApi_AllSpacesStream) SendAndClose(m *AllSpacesResponse) error {
if err := x.MsgSend(m, drpcEncoding_File_api_apiproto_protos_api_proto{}); err != nil {
return err
}
return x.CloseSend()
}

View File

@ -0,0 +1,50 @@
syntax = "proto3";
package nodeapi;
option go_package = "api/apiproto";
service NodeApi {
rpc DumpTree(DumpTreeRequest) returns(DumpTreeResponse);
rpc TreeParams(TreeParamsRequest) returns(TreeParamsResponse);
rpc AllTrees(AllTreesRequest) returns(AllTreesResponse);
rpc AllSpaces(AllSpacesRequest) returns(AllSpacesResponse);
}
message DumpTreeRequest {
string spaceId = 1;
string documentId = 2;
}
message DumpTreeResponse {
string dump = 1;
}
message AllTreesRequest {
string spaceId = 1;
}
message Tree {
string id = 1;
repeated string heads = 2;
}
message AllTreesResponse {
repeated Tree trees = 1;
}
message AllSpacesRequest {
}
message AllSpacesResponse {
repeated string spaceIds = 1;
}
message TreeParamsRequest {
string spaceId = 1;
string documentId = 2;
}
message TreeParamsResponse {
string rootId = 1;
repeated string headIds = 2;
}

68
node/api/rpchandler.go Normal file
View File

@ -0,0 +1,68 @@
package api
import (
"context"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/api/apiproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/storage"
)
type rpcHandler struct {
treeCache treegetter.TreeGetter
spaceService nodespace.Service
storageService storage.NodeStorage
}
func (r *rpcHandler) DumpTree(ctx context.Context, request *apiproto.DumpTreeRequest) (resp *apiproto.DumpTreeResponse, err error) {
tree, err := r.treeCache.GetTree(context.Background(), request.SpaceId, request.DocumentId)
if err != nil {
return
}
dump, err := tree.DebugDump()
if err != nil {
return
}
resp = &apiproto.DumpTreeResponse{
Dump: dump,
}
return
}
func (r *rpcHandler) AllTrees(ctx context.Context, request *apiproto.AllTreesRequest) (resp *apiproto.AllTreesResponse, err error) {
space, err := r.spaceService.GetSpace(ctx, request.SpaceId)
if err != nil {
return
}
heads := space.DebugAllHeads()
var trees []*apiproto.Tree
for _, head := range heads {
trees = append(trees, &apiproto.Tree{
Id: head.Id,
Heads: head.Heads,
})
}
resp = &apiproto.AllTreesResponse{Trees: trees}
return
}
func (r *rpcHandler) AllSpaces(ctx context.Context, request *apiproto.AllSpacesRequest) (resp *apiproto.AllSpacesResponse, err error) {
ids, err := r.storageService.AllSpaceIds()
if err != nil {
return
}
resp = &apiproto.AllSpacesResponse{SpaceIds: ids}
return
}
func (r *rpcHandler) TreeParams(ctx context.Context, request *apiproto.TreeParamsRequest) (resp *apiproto.TreeParamsResponse, err error) {
tree, err := r.treeCache.GetTree(context.Background(), request.SpaceId, request.DocumentId)
if err != nil {
return
}
resp = &apiproto.TreeParamsResponse{
RootId: tree.Root().Id,
HeadIds: tree.Heads(),
}
return
}

69
node/api/service.go Normal file
View File

@ -0,0 +1,69 @@
package api
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/commonspace/storage"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/commonspace/treegetter"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/config"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/rpc/server"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/api/apiproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace"
nodestorage "github.com/anytypeio/go-anytype-infrastructure-experiments/node/storage"
"storj.io/drpc"
)
const CName = "api.service"
var log = logger.NewNamed(CName)
func New() Service {
return &service{BaseDrpcServer: server.NewBaseDrpcServer()}
}
type Service interface {
app.ComponentRunnable
drpc.Mux
}
type service struct {
transport secure.Service
cfg *config.Config
treeCache treegetter.TreeGetter
spaceService nodespace.Service
storageService nodestorage.NodeStorage
*server.BaseDrpcServer
}
func (s *service) Init(a *app.App) (err error) {
s.treeCache = a.MustComponent(treegetter.CName).(treegetter.TreeGetter)
s.spaceService = a.MustComponent(nodespace.CName).(nodespace.Service)
s.storageService = a.MustComponent(storage.CName).(nodestorage.NodeStorage)
s.cfg = a.MustComponent(config.CName).(*config.Config)
s.transport = a.MustComponent(secure.CName).(secure.Service)
return nil
}
func (s *service) Name() (name string) {
return CName
}
func (s *service) Run(ctx context.Context) (err error) {
err = s.BaseDrpcServer.Run(
ctx,
s.cfg.APIServer.ListenAddrs,
func(handler drpc.Handler) drpc.Handler {
return handler
},
s.transport.BasicListener)
if err != nil {
return
}
return apiproto.DRPCRegisterNodeApi(s, &rpcHandler{s.treeCache, s.spaceService, s.storageService})
}
func (s *service) Close(ctx context.Context) (err error) {
return s.BaseDrpcServer.Close(ctx)
}

View File

@ -15,6 +15,7 @@ import (
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/secure"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf" "github.com/anytypeio/go-anytype-infrastructure-experiments/common/nodeconf"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/account" "github.com/anytypeio/go-anytype-infrastructure-experiments/node/account"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/api"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace" "github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace/nodecache" "github.com/anytypeio/go-anytype-infrastructure-experiments/node/nodespace/nodecache"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/storage" "github.com/anytypeio/go-anytype-infrastructure-experiments/node/storage"
@ -101,5 +102,6 @@ func Bootstrap(a *app.App) {
Register(pool.New()). Register(pool.New()).
Register(nodespace.New()). Register(nodespace.New()).
Register(commonspace.New()). Register(commonspace.New()).
Register(server.New()) Register(server.New()).
Register(api.New())
} }

View File

@ -10,6 +10,9 @@ require (
github.com/akrylysov/pogreb v0.10.1 github.com/akrylysov/pogreb v0.10.1
github.com/anytypeio/go-anytype-infrastructure-experiments/common v0.0.0-00010101000000-000000000000 github.com/anytypeio/go-anytype-infrastructure-experiments/common v0.0.0-00010101000000-000000000000
github.com/anytypeio/go-anytype-infrastructure-experiments/consensus v0.0.0-00010101000000-000000000000 github.com/anytypeio/go-anytype-infrastructure-experiments/consensus v0.0.0-00010101000000-000000000000
github.com/golang/mock v1.6.0
github.com/ipfs/go-cid v0.3.2
github.com/stretchr/testify v1.8.0
go.uber.org/zap v1.23.0 go.uber.org/zap v1.23.0
) )
@ -19,6 +22,7 @@ require (
github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheggaaa/mb/v2 v2.0.1 // indirect github.com/cheggaaa/mb/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/fogleman/gg v1.3.0 // indirect github.com/fogleman/gg v1.3.0 // indirect
github.com/goccy/go-graphviz v0.0.9 // indirect github.com/goccy/go-graphviz v0.0.9 // indirect
@ -26,12 +30,10 @@ require (
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/huandu/skiplist v1.2.0 // indirect github.com/huandu/skiplist v1.2.0 // indirect
github.com/ipfs/go-cid v0.3.2 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/klauspost/cpuid/v2 v2.1.1 // indirect github.com/klauspost/cpuid/v2 v2.1.1 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.23.2 // indirect github.com/libp2p/go-libp2p v0.23.2 // indirect
github.com/libp2p/go-libp2p-core v0.20.1 // indirect
github.com/libp2p/go-openssl v0.1.0 // indirect github.com/libp2p/go-openssl v0.1.0 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-pointer v0.0.1 // indirect github.com/mattn/go-pointer v0.0.1 // indirect
@ -46,6 +48,7 @@ require (
github.com/multiformats/go-multihash v0.2.1 // indirect github.com/multiformats/go-multihash v0.2.1 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect github.com/multiformats/go-varint v0.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect

View File

@ -109,6 +109,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -191,8 +192,6 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE= github.com/libp2p/go-libp2p v0.23.2 h1:yqyTeKQJyofWXxEv/eEVUvOrGdt/9x+0PIQ4N1kaxmE=
github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI= github.com/libp2p/go-libp2p v0.23.2/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI=
github.com/libp2p/go-libp2p-core v0.20.1 h1:fQz4BJyIFmSZAiTbKV8qoYhEH5Dtv/cVhZbG3Ib/+Cw=
github.com/libp2p/go-libp2p-core v0.20.1/go.mod h1:6zR8H7CvQWgYLsbG4on6oLNSGcyKaYFSEYyDt51+bIY=
github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo=
github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
@ -271,11 +270,14 @@ github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0b
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -497,6 +499,7 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -70,3 +70,16 @@ func (c *treeCache) GetTree(ctx context.Context, spaceId, id string) (tr tree.Ob
tr = value.(tree.ObjectTree) tr = value.(tree.ObjectTree)
return return
} }
func (c *treeCache) DeleteTree(ctx context.Context, spaceId, treeId string) (err error) {
tr, err := c.GetTree(ctx, spaceId, treeId)
if err != nil {
return
}
err = tr.Delete()
if err != nil {
return
}
_, err = c.cache.Remove(treeId)
return
}

View File

@ -19,22 +19,34 @@ func (r *rpcHandler) PullSpace(ctx context.Context, request *spacesyncproto.Pull
return return
} }
description := sp.Description() spaceDesc, err := sp.Description()
if err != nil {
err = spacesyncproto.ErrUnexpected
return
}
resp = &spacesyncproto.PullSpaceResponse{ resp = &spacesyncproto.PullSpaceResponse{
SpaceHeader: description.SpaceHeader, Payload: &spacesyncproto.SpacePayload{
AclPayload: description.AclPayload, SpaceHeader: spaceDesc.SpaceHeader,
AclPayloadId: description.AclId, AclPayloadId: spaceDesc.AclId,
AclPayload: spaceDesc.AclPayload,
SpaceSettingsPayload: spaceDesc.SpaceSettingsPayload,
SpaceSettingsPayloadId: spaceDesc.SpaceSettingsId,
},
} }
return return
} }
func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpaceRequest) (resp *spacesyncproto.PushSpaceResponse, err error) { func (r *rpcHandler) PushSpace(ctx context.Context, req *spacesyncproto.PushSpaceRequest) (resp *spacesyncproto.PushSpaceResponse, err error) {
description := commonspace.SpaceDescription{ description := commonspace.SpaceDescription{
SpaceHeader: req.SpaceHeader, SpaceHeader: req.Payload.SpaceHeader,
AclId: req.AclPayloadId, AclId: req.Payload.AclPayloadId,
AclPayload: req.AclPayload, AclPayload: req.Payload.AclPayload,
SpaceSettingsPayload: req.Payload.SpaceSettingsPayload,
SpaceSettingsId: req.Payload.SpaceSettingsPayloadId,
} }
err = r.s.AddSpace(ctx, description) ctx = context.WithValue(ctx, commonspace.AddSpaceCtxKey, description)
_, err = r.s.GetSpace(ctx, description.SpaceHeader.GetId())
if err != nil { if err != nil {
return return
} }

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