lnd/lnrpc/sub_server.go
2021-07-27 13:09:59 +02:00

152 lines
5.5 KiB
Go

package lnrpc
import (
"context"
"fmt"
"sync"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"gopkg.in/macaroon-bakery.v2/bakery"
)
// MacaroonPerms is a map from the FullMethod of an invoked gRPC command. It
// maps the set of operations that the macaroon presented with the command MUST
// satisfy. With this map, all sub-servers are able to communicate to the
// primary macaroon service what type of macaroon must be passed with each
// method present on the service of the sub-server.
type MacaroonPerms map[string][]bakery.Op
// SubServer is a child server of the main lnrpc gRPC server. Sub-servers allow
// lnd to expose discrete services that can be used with or independent of the
// main RPC server. The main rpcserver will create, start, stop, and manage
// each sub-server in a generalized manner.
type SubServer interface {
// Start starts the sub-server and all goroutines it needs to operate.
Start() error
// Stop signals that the sub-server should wrap up any lingering
// requests, and being a graceful shutdown.
Stop() error
// Name returns a unique string representation of the sub-server. This
// can be used to identify the sub-server and also de-duplicate them.
Name() string
}
// GrpcHandler is the interface that should be registered with the root gRPC
// server, and is the interface that implements the subserver's defined RPC.
// Before the actual sub server has been created, this will be an empty shell
// allowing us to start the gRPC server before we have all the dependencies
// needed to create the subserver itself.
type GrpcHandler interface {
// RegisterWithRootServer will be called by the root gRPC server to
// direct a sub RPC server to register itself with the main gRPC root
// server. Until this is called, each sub-server won't be able to have
// requests routed towards it.
RegisterWithRootServer(*grpc.Server) error
// RegisterWithRestServer will be called by the root REST mux to direct
// a sub RPC server to register itself with the main REST mux server.
// Until this is called, each sub-server won't be able to have requests
// routed towards it.
RegisterWithRestServer(context.Context, *runtime.ServeMux, string,
[]grpc.DialOption) error
// CreateSubServer populates the subserver's dependencies using the
// passed SubServerConfigDispatcher. This method should fully
// initialize the sub-server instance, making it ready for action. It
// returns the macaroon permissions that the sub-server wishes to pass
// on to the root server for all methods routed towards it.
CreateSubServer(subCfgs SubServerConfigDispatcher) (SubServer,
MacaroonPerms, error)
}
// SubServerConfigDispatcher is an interface that all sub-servers will use to
// dynamically locate their configuration files. This abstraction will allow
// the primary RPC sever to initialize all sub-servers in a generic manner
// without knowing of each individual sub server.
type SubServerConfigDispatcher interface {
// FetchConfig attempts to locate an existing configuration file mapped
// to the target sub-server. If we're unable to find a config file
// matching the subServerName name, then false will be returned for the
// second parameter.
FetchConfig(subServerName string) (interface{}, bool)
}
// SubServerDriver is a template struct that allows the root server to create a
// sub-server gRPC handler with minimal knowledge.
type SubServerDriver struct {
// SubServerName is the full name of a sub-sever.
//
// NOTE: This MUST be unique.
SubServerName string
// NewGrpcHandler creates a a new sub-server gRPC interface that can be
// registered with the root gRPC server. It is not expected that the
// SubServer is ready for operation before its CreateSubServer and
// Start methods have been called.
NewGrpcHandler func() GrpcHandler
}
var (
// subServers is a package level global variable that houses all the
// registered sub-servers.
subServers = make(map[string]*SubServerDriver)
// registerMtx is a mutex that protects access to the above subServer
// map.
registerMtx sync.Mutex
)
// RegisteredSubServers returns all registered sub-servers.
//
// NOTE: This function is safe for concurrent access.
func RegisteredSubServers() []*SubServerDriver {
registerMtx.Lock()
defer registerMtx.Unlock()
drivers := make([]*SubServerDriver, 0, len(subServers))
for _, driver := range subServers {
drivers = append(drivers, driver)
}
return drivers
}
// RegisterSubServer should be called by a sub-server within its package's
// init() method to register its existence with the main sub-server map. Each
// sub-server, if active, is meant to register via this method in their init()
// method. This allows callers to easily initialize and register all
// sub-servers without knowing any details beyond that the fact that they
// satisfy the necessary interfaces.
//
// NOTE: This function is safe for concurrent access.
func RegisterSubServer(driver *SubServerDriver) error {
registerMtx.Lock()
defer registerMtx.Unlock()
if _, ok := subServers[driver.SubServerName]; ok {
return fmt.Errorf("subserver already registered")
}
subServers[driver.SubServerName] = driver
return nil
}
// SupportedServers returns slice of the names of all registered sub-servers.
//
// NOTE: This function is safe for concurrent access.
func SupportedServers() []string {
registerMtx.Lock()
defer registerMtx.Unlock()
supportedSubServers := make([]string, 0, len(subServers))
for driverName := range subServers {
supportedSubServers = append(supportedSubServers, driverName)
}
return supportedSubServers
}