github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tm-db/remotedb/grpcdb/server.go (about) 1 package grpcdb 2 3 import ( 4 "context" 5 "net" 6 "sync" 7 "time" 8 9 "google.golang.org/grpc" 10 "google.golang.org/grpc/credentials" 11 12 db "github.com/fibonacci-chain/fbc/libs/tm-db" 13 protodb "github.com/fibonacci-chain/fbc/libs/tm-db/remotedb/proto" 14 ) 15 16 // ListenAndServe is a blocking function that sets up a gRPC based 17 // server at the address supplied, with the gRPC options passed in. 18 // Normally in usage, invoke it in a goroutine like you would for http.ListenAndServe. 19 func ListenAndServe(addr, cert, key string, opts ...grpc.ServerOption) error { 20 ln, err := net.Listen("tcp", addr) 21 if err != nil { 22 return err 23 } 24 srv, err := NewServer(cert, key, opts...) 25 if err != nil { 26 return err 27 } 28 return srv.Serve(ln) 29 } 30 31 func NewServer(cert, key string, opts ...grpc.ServerOption) (*grpc.Server, error) { 32 creds, err := credentials.NewServerTLSFromFile(cert, key) 33 if err != nil { 34 return nil, err 35 } 36 opts = append(opts, grpc.Creds(creds)) 37 srv := grpc.NewServer(opts...) 38 protodb.RegisterDBServer(srv, new(server)) 39 return srv, nil 40 } 41 42 type server struct { 43 mu sync.Mutex 44 db db.DB 45 } 46 47 var _ protodb.DBServer = (*server)(nil) 48 49 // Init initializes the server's database. Only one type of database 50 // can be initialized per server. 51 // 52 // Dir is the directory on the file system in which the DB will be stored(if backed by disk) (TODO: remove) 53 // 54 // # Name is representative filesystem entry's basepath 55 // 56 // Type can be either one of: 57 // - cleveldb (if built with gcc enabled) 58 // - fsdb 59 // - memdB 60 // - goleveldb 61 // 62 // See https://godoc.org/github.com/tendermint/tendermint/libs/db#BackendType 63 func (s *server) Init(ctx context.Context, in *protodb.Init) (*protodb.Entity, error) { 64 s.mu.Lock() 65 defer s.mu.Unlock() 66 67 s.db = db.NewDB(in.Name, db.BackendType(in.Type), in.Dir) 68 return &protodb.Entity{CreatedAt: time.Now().Unix()}, nil 69 } 70 71 func (s *server) Delete(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 72 err := s.db.Delete(in.Key) 73 if err != nil { 74 return nil, err 75 } 76 return nothing, nil 77 } 78 79 var nothing = new(protodb.Nothing) 80 81 func (s *server) DeleteSync(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 82 err := s.db.DeleteSync(in.Key) 83 if err != nil { 84 return nil, err 85 } 86 return nothing, nil 87 } 88 89 func (s *server) Get(ctx context.Context, in *protodb.Entity) (*protodb.Entity, error) { 90 value, err := s.db.Get(in.Key) 91 if err != nil { 92 return nil, err 93 } 94 return &protodb.Entity{Value: value}, nil 95 } 96 97 func (s *server) GetStream(ds protodb.DB_GetStreamServer) error { 98 // Receive routine 99 responsesChan := make(chan *protodb.Entity) 100 go func() { 101 defer close(responsesChan) 102 ctx := context.Background() 103 for { 104 in, err := ds.Recv() 105 if err != nil { 106 responsesChan <- &protodb.Entity{Err: err.Error()} 107 return 108 } 109 out, err := s.Get(ctx, in) 110 if err != nil { 111 if out == nil { 112 out = new(protodb.Entity) 113 out.Key = in.Key 114 } 115 out.Err = err.Error() 116 responsesChan <- out 117 return 118 } 119 120 // Otherwise continue on 121 responsesChan <- out 122 } 123 }() 124 125 // Send routine, block until we return 126 for out := range responsesChan { 127 if err := ds.Send(out); err != nil { 128 return err 129 } 130 } 131 return nil 132 } 133 134 func (s *server) Has(ctx context.Context, in *protodb.Entity) (*protodb.Entity, error) { 135 exists, err := s.db.Has(in.Key) 136 if err != nil { 137 return nil, err 138 } 139 return &protodb.Entity{Exists: exists}, nil 140 } 141 142 func (s *server) Set(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 143 err := s.db.Set(in.Key, in.Value) 144 if err != nil { 145 return nil, err 146 } 147 return nothing, nil 148 } 149 150 func (s *server) SetSync(ctx context.Context, in *protodb.Entity) (*protodb.Nothing, error) { 151 err := s.db.SetSync(in.Key, in.Value) 152 if err != nil { 153 return nil, err 154 } 155 return nothing, nil 156 } 157 158 func (s *server) Iterator(query *protodb.Entity, dis protodb.DB_IteratorServer) error { 159 it, err := s.db.Iterator(query.Start, query.End) 160 if err != nil { 161 return err 162 } 163 defer it.Close() 164 return s.handleIterator(it, dis.Send) 165 } 166 167 func (s *server) handleIterator(it db.Iterator, sendFunc func(*protodb.Iterator) error) error { 168 for it.Valid() { 169 start, end := it.Domain() 170 key := it.Key() 171 value := it.Value() 172 173 out := &protodb.Iterator{ 174 Domain: &protodb.Domain{Start: start, End: end}, 175 Valid: it.Valid(), 176 Key: key, 177 Value: value, 178 } 179 if err := sendFunc(out); err != nil { 180 return err 181 } 182 183 // Finally move the iterator forward, 184 it.Next() 185 186 } 187 return nil 188 } 189 190 func (s *server) ReverseIterator(query *protodb.Entity, dis protodb.DB_ReverseIteratorServer) error { 191 it, err := s.db.ReverseIterator(query.Start, query.End) 192 if err != nil { 193 return err 194 } 195 defer it.Close() 196 return s.handleIterator(it, dis.Send) 197 } 198 199 func (s *server) Stats(context.Context, *protodb.Nothing) (*protodb.Stats, error) { 200 stats := s.db.Stats() 201 return &protodb.Stats{Data: stats, TimeAt: time.Now().Unix()}, nil 202 } 203 204 func (s *server) BatchWrite(c context.Context, b *protodb.Batch) (*protodb.Nothing, error) { 205 return s.batchWrite(c, b, false) 206 } 207 208 func (s *server) BatchWriteSync(c context.Context, b *protodb.Batch) (*protodb.Nothing, error) { 209 return s.batchWrite(c, b, true) 210 } 211 212 func (s *server) batchWrite(c context.Context, b *protodb.Batch, sync bool) (*protodb.Nothing, error) { 213 bat := s.db.NewBatch() 214 defer bat.Close() 215 for _, op := range b.Ops { 216 switch op.Type { 217 case protodb.Operation_SET: 218 bat.Set(op.Entity.Key, op.Entity.Value) 219 case protodb.Operation_DELETE: 220 bat.Delete(op.Entity.Key) 221 } 222 } 223 if sync { 224 err := bat.WriteSync() 225 if err != nil { 226 return nil, err 227 } 228 } else { 229 err := bat.Write() 230 if err != nil { 231 return nil, err 232 } 233 } 234 return nothing, nil 235 }