1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-09 17:45:03 +09:00
any-sync/cmd/consensusnode/testclient/consensustestclient.go
2022-10-05 11:41:48 +03:00

260 lines
6.6 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app"
"github.com/anytypeio/go-anytype-infrastructure-experiments/app/logger"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/dialer"
"github.com/anytypeio/go-anytype-infrastructure-experiments/common/net/pool"
"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/config"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusclient"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto"
"github.com/anytypeio/go-anytype-infrastructure-experiments/consensus/consensusproto/consensuserrs"
"github.com/anytypeio/go-anytype-infrastructure-experiments/node/account"
"go.uber.org/zap"
"gopkg.in/mgo.v2/bson"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
"time"
)
var log = logger.NewNamed("main")
var (
flagConfigFile = flag.String("c", "etc/consensus-config.yml", "path to config file")
flagVersion = flag.Bool("v", false, "show version and exit")
flagHelp = flag.Bool("h", false, "show help and exit")
)
func main() {
flag.Parse()
if *flagVersion {
fmt.Println(app.VersionDescription())
return
}
if *flagHelp {
flag.PrintDefaults()
return
}
if debug, ok := os.LookupEnv("ANYPROF"); ok && debug != "" {
go func() {
http.ListenAndServe(debug, nil)
}()
}
// create app
ctx := context.Background()
a := new(app.App)
// open config file
conf, err := config.NewFromFile(*flagConfigFile)
if err != nil {
log.Fatal("can't open config file", zap.Error(err))
}
// bootstrap components
a.Register(conf)
Bootstrap(a)
// start app
if err := a.Start(ctx); err != nil {
log.Fatal("can't start app", zap.Error(err))
}
log.Info("app started", zap.String("version", a.Version()))
if err := testClient(a.MustComponent(consensusclient.CName).(consensusclient.Service)); err != nil {
log.Fatal("test error", zap.Error(err))
} else {
log.Info("test success!")
}
// wait exit signal
exit := make(chan os.Signal, 1)
signal.Notify(exit, os.Interrupt, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGQUIT)
sig := <-exit
log.Info("received exit signal, stop app...", zap.String("signal", fmt.Sprint(sig)))
// close app
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
if err := a.Close(ctx); err != nil {
log.Fatal("close error", zap.Error(err))
} else {
log.Info("goodbye!")
}
time.Sleep(time.Second / 3)
}
func Bootstrap(a *app.App) {
a.Register(account.New()).
Register(secure.New()).
Register(nodeconf.New()).
Register(dialer.New()).
Register(pool.New()).
Register(consensusclient.New())
}
func testClient(service consensusclient.Service) (err error) {
if err = testCreateLogAndRecord(service); err != nil {
return err
}
if err = testStream(service); err != nil {
return err
}
return
}
func testCreateLogAndRecord(service consensusclient.Service) (err error) {
ctx := context.Background()
// create log
newLogId := []byte(bson.NewObjectId())
st := time.Now()
lastRecId := []byte(bson.NewObjectId())
err = service.AddLog(ctx, &consensusproto.Log{
Id: newLogId,
Records: []*consensusproto.Record{
{
Id: lastRecId,
Payload: []byte("test"),
CreatedUnix: uint64(time.Now().Unix()),
},
},
})
if err != nil {
return err
}
log.Info("log created", zap.String("id", bson.ObjectId(newLogId).Hex()), zap.Duration("dur", time.Since(st)))
// create log with same id
st = time.Now()
err = service.AddLog(ctx, &consensusproto.Log{
Id: newLogId,
Records: []*consensusproto.Record{
{
Id: lastRecId,
Payload: []byte("test"),
CreatedUnix: uint64(time.Now().Unix()),
},
},
})
if err != consensuserrs.ErrLogExists {
return fmt.Errorf("unexpected error: '%v' want LogExists", zap.Error(err))
}
err = nil
log.Info("log duplicate checked", zap.Duration("dur", time.Since(st)))
// create record
st = time.Now()
recId := []byte(bson.NewObjectId())
err = service.AddRecord(ctx, newLogId, &consensusproto.Record{
Id: []byte(bson.NewObjectId()),
PrevId: lastRecId,
CreatedUnix: uint64(time.Now().Unix()),
})
if err != nil {
return err
}
lastRecId = recId
log.Info("record created", zap.String("id", bson.ObjectId(lastRecId).Hex()), zap.Duration("dur", time.Since(st)))
// record conflict
st = time.Now()
err = service.AddRecord(ctx, newLogId, &consensusproto.Record{
Id: []byte(bson.NewObjectId()),
PrevId: []byte(bson.NewObjectId()),
CreatedUnix: uint64(time.Now().Unix()),
})
if err != consensuserrs.ErrConflict {
return fmt.Errorf("unexpected error: '%v' want Conflict", zap.Error(err))
}
err = nil
log.Info("conflict record checked", zap.Duration("dur", time.Since(st)))
return
}
func testStream(service consensusclient.Service) (err error) {
ctx := context.Background()
// create log
newLogId := []byte(bson.NewObjectId())
st := time.Now()
lastRecId := []byte(bson.NewObjectId())
err = service.AddLog(ctx, &consensusproto.Log{
Id: newLogId,
Records: []*consensusproto.Record{
{
Id: lastRecId,
Payload: []byte("test"),
CreatedUnix: uint64(time.Now().Unix()),
},
},
})
if err != nil {
return err
}
log.Info("log created", zap.String("id", bson.ObjectId(newLogId).Hex()), zap.Duration("dur", time.Since(st)))
stream, err := service.WatchLog(ctx, newLogId)
if err != nil {
return err
}
defer stream.Close()
sr := readStream(stream)
for i := 0; i < 10; i++ {
st = time.Now()
recId := []byte(bson.NewObjectId())
err = service.AddRecord(ctx, newLogId, &consensusproto.Record{
Id: recId,
PrevId: lastRecId,
CreatedUnix: uint64(time.Now().Unix()),
})
if err != nil {
return err
}
lastRecId = recId
log.Info("record created", zap.String("id", bson.ObjectId(lastRecId).Hex()), zap.Duration("dur", time.Since(st)))
}
fmt.Println(sr.log.Records)
return nil
}
func readStream(stream consensusproto.DRPCConsensus_WatchLogClient) *streamReader {
sr := &streamReader{stream: stream}
go sr.read()
return sr
}
type streamReader struct {
stream consensusproto.DRPCConsensus_WatchLogClient
log *consensusproto.Log
}
func (sr *streamReader) read() {
for {
event, err := sr.stream.Recv()
if err != nil {
return
}
fmt.Println("received event", event)
if sr.log == nil {
sr.log = &consensusproto.Log{
Id: event.LogId,
Records: event.Records,
}
} else {
sr.log.Records = append(event.Records, sr.log.Records...)
}
}
}