stasatdaglabs 05db135d23
[NOD-1124] Implement the Flow thread model and architecture (#791)
* [NOD-1124] Move Router to the router package.

* [NOD-1124] Implement SetOnRouteCapacityReachedHandler.

* [NOD-1124] Use Routes instead of bare channels.

* [NOD-1124] Fix merge errors.

* [NOD-1124] Connect the Router to the Connection.

* [NOD-1124] Fix merge errors.

* [NOD-1124] Move some variables around.

* [NOD-1124] Fix unreachable code.

* [NOD-1124] Fix a variable name.

* [NOD-1124] Rename AddRoute to AddIncomingRoute.

* [NOD-1124] Rename SetRouter to Start.

* [NOD-1124] Make AddIncomingRoute create a Route by itself.

* [NOD-1124] Replace IncomingRoute with EnqueueIncomingMessage.

* [NOD-1124] Make Enqueue and Dequeue return isOpen instead of err.

* [NOD-1124] Remove writeDuringDisconnectLock.

* [NOD-1124] In sendLoop, move outgoingRoute to outside the loop.

* [NOD-1124] Start the connection loops only when Start is called.

* [NOD-1124] Replace OnIDReceivedHandler with AssociateRouterID.

* [NOD-1124] Add isOpen to Enqueue and Dequeue.

* [NOD-1124] Protect errChan from writing during disconnect.
2020-07-13 16:51:13 +03:00

140 lines
3.5 KiB
Go

package grpcserver
import (
"context"
"fmt"
"net"
"google.golang.org/grpc/peer"
"github.com/kaspanet/kaspad/netadapter/server"
"github.com/kaspanet/kaspad/netadapter/server/grpcserver/protowire"
"github.com/kaspanet/kaspad/util/panics"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
type gRPCServer struct {
onConnectedHandler server.OnConnectedHandler
connections map[string]*gRPCConnection
listeningAddrs []string
server *grpc.Server
}
// NewGRPCServer creates and starts a gRPC server, listening on the
// provided addresses/ports
func NewGRPCServer(listeningAddrs []string) (server.Server, error) {
s := &gRPCServer{
server: grpc.NewServer(),
listeningAddrs: listeningAddrs,
connections: map[string]*gRPCConnection{},
}
protowire.RegisterP2PServer(s.server, newP2PServer(s))
return s, nil
}
func (s *gRPCServer) Start() error {
for _, listenAddr := range s.listeningAddrs {
err := s.listenOn(listenAddr)
if err != nil {
return err
}
}
return nil
}
func (s *gRPCServer) listenOn(listenAddr string) error {
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
return errors.Wrapf(err, "error listening on %s", listenAddr)
}
spawn(func() {
err := s.server.Serve(listener)
if err != nil {
panics.Exit(log, fmt.Sprintf("error serving on %s: %+v", listenAddr, err))
}
})
log.Infof("P2P server listening on %s", listenAddr)
return nil
}
func (s *gRPCServer) Stop() error {
for _, connection := range s.connections {
err := connection.Disconnect()
if err != nil {
log.Errorf("error closing connection to %s: %+v", connection, err)
}
}
s.server.GracefulStop()
return nil
}
// SetOnConnectedHandler sets the peer connected handler
// function for the server
func (s *gRPCServer) SetOnConnectedHandler(onConnectedHandler server.OnConnectedHandler) {
s.onConnectedHandler = onConnectedHandler
}
// Connect connects to the given address
// This is part of the Server interface
func (s *gRPCServer) Connect(address string) (server.Connection, error) {
log.Infof("Dialing to %s", address)
gRPCConnection, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
return nil, errors.Wrapf(err, "error connecting to %s", address)
}
client := protowire.NewP2PClient(gRPCConnection)
stream, err := client.MessageStream(context.Background())
if err != nil {
return nil, errors.Wrapf(err, "error getting client stream for %s", address)
}
peerInfo, ok := peer.FromContext(stream.Context())
if !ok {
return nil, errors.Errorf("error getting stream peer info from context for %s", address)
}
connection := newConnection(s, peerInfo.Addr, true, stream)
err = s.onConnectedHandler(connection)
if err != nil {
return nil, err
}
log.Infof("Connected to %s", address)
return connection, nil
}
// Connections returns a slice of connections the server
// is currently connected to.
// This is part of the Server interface
func (s *gRPCServer) Connections() []server.Connection {
result := make([]server.Connection, 0, len(s.connections))
for _, conn := range s.connections {
result = append(result, conn)
}
return result
}
// AddConnection adds the provided connection to the connection list
func (s *gRPCServer) AddConnection(connection server.Connection) error {
conn := connection.(*gRPCConnection)
s.connections[conn.String()] = conn
return nil
}
// RemoveConnection removes the provided connection from the connection list
func (s *gRPCServer) RemoveConnection(connection server.Connection) error {
delete(s.connections, connection.String())
return nil
}