lnrpc: add new sub RPC server registration system
In this commit, we add the scafolding for the future sub-server RPC system. The idea is that each sub server will implement this particular interface. From there on, a "root" RPC server is able to query this registry, and dynamically create each sub-sever instance without knowing the details of each sub-server. In the init() method of the pacakge of a sub-server, the sub-server is to call: RegisterSubServer to claim its namespace. Afterwards, the root RPC server can use the RegisteredSubServers() method to obtain a slice of ALL regsitered sub-servers. Once this list is obtained, it can use the New() method of the SubServerDriver struct to create a new sub-server instance. Each sub-server needs to be able to locate it's primary config using the SubServerConfigDispatcher interface. This can be a map of maps, or a regular config structr. The main requirement is that the sub-server be able to find a config under the same name that it registered with. This string of abstractions will allow the main RPC server to find, create, and run each sub-server without knowing the details of its configuration or its role.
This commit is contained in:
parent
9f24049bbc
commit
184f160fb9
131
lnrpc/sub_server.go
Normal file
131
lnrpc/sub_server.go
Normal file
@ -0,0 +1,131 @@
|
||||
package lnrpc
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
)
|
||||
|
||||
// MacaroonPerms is a map from the FullMethod of an invoked gRPC command. to
|
||||
// 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 use with or independent of the
|
||||
// main RPC server. The main rpcserver will create, start, stop, and manage
|
||||
// each ubs-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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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 with minimal knowledge. The root server only need a fully
|
||||
// populated SubServerConfigDispatcher and with the aide of the
|
||||
// RegisterSubServers method, it's able to create and initialize all
|
||||
// sub-servers.
|
||||
type SubServerDriver struct {
|
||||
// SubServerName is the full name of a sub-sever.
|
||||
//
|
||||
// NOTE: This MUST be unique.
|
||||
SubServerName string
|
||||
|
||||
// New creates, and fully initializes a new sub-server instance with
|
||||
// the aide of the SubServerConfigDispatcher. This closure should
|
||||
// return the SubServer, ready for action, along with the set of
|
||||
// macaroon permissions that the sub-server wishes to pass on to the
|
||||
// root server for all methods routed towards it.
|
||||
New func(subCfgs SubServerConfigDispatcher) (SubServer, MacaroonPerms, error)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user