github.com/decred/dcrlnd@v0.7.6/lnrpc/sub_server.go (about)

     1  package lnrpc
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
     9  	"google.golang.org/grpc"
    10  	"gopkg.in/macaroon-bakery.v2/bakery"
    11  )
    12  
    13  // MacaroonPerms is a map from the FullMethod of an invoked gRPC command. It
    14  // maps the set of operations that the macaroon presented with the command MUST
    15  // satisfy. With this map, all sub-servers are able to communicate to the
    16  // primary macaroon service what type of macaroon must be passed with each
    17  // method present on the service of the sub-server.
    18  type MacaroonPerms map[string][]bakery.Op
    19  
    20  // SubServer is a child server of the main lnrpc gRPC server. Sub-servers allow
    21  // lnd to expose discrete services that can be used with or independent of the
    22  // main RPC server. The main rpcserver will create, start, stop, and manage
    23  // each sub-server in a generalized manner.
    24  type SubServer interface {
    25  	// Start starts the sub-server and all goroutines it needs to operate.
    26  	Start() error
    27  
    28  	// Stop signals that the sub-server should wrap up any lingering
    29  	// requests, and being a graceful shutdown.
    30  	Stop() error
    31  
    32  	// Name returns a unique string representation of the sub-server. This
    33  	// can be used to identify the sub-server and also de-duplicate them.
    34  	Name() string
    35  }
    36  
    37  // GrpcHandler is the interface that should be registered with the root gRPC
    38  // server, and is the interface that implements the subserver's defined RPC.
    39  // Before the actual sub server has been created, this will be an empty shell
    40  // allowing us to start the gRPC server before we have all the dependencies
    41  // needed to create the subserver itself.
    42  type GrpcHandler interface {
    43  	// RegisterWithRootServer will be called by the root gRPC server to
    44  	// direct a sub RPC server to register itself with the main gRPC root
    45  	// server. Until this is called, each sub-server won't be able to have
    46  	// requests routed towards it.
    47  	RegisterWithRootServer(*grpc.Server) error
    48  
    49  	// RegisterWithRestServer will be called by the root REST mux to direct
    50  	// a sub RPC server to register itself with the main REST mux server.
    51  	// Until this is called, each sub-server won't be able to have requests
    52  	// routed towards it.
    53  	RegisterWithRestServer(context.Context, *runtime.ServeMux, string,
    54  		[]grpc.DialOption) error
    55  
    56  	// CreateSubServer populates the subserver's dependencies using the
    57  	// passed SubServerConfigDispatcher. This method should fully
    58  	// initialize the sub-server instance, making it ready for action. It
    59  	// returns the macaroon permissions that the sub-server wishes to pass
    60  	// on to the root server for all methods routed towards it.
    61  	CreateSubServer(subCfgs SubServerConfigDispatcher) (SubServer,
    62  		MacaroonPerms, error)
    63  }
    64  
    65  // SubServerConfigDispatcher is an interface that all sub-servers will use to
    66  // dynamically locate their configuration files. This abstraction will allow
    67  // the primary RPC sever to initialize all sub-servers in a generic manner
    68  // without knowing of each individual sub server.
    69  type SubServerConfigDispatcher interface {
    70  	// FetchConfig attempts to locate an existing configuration file mapped
    71  	// to the target sub-server. If we're unable to find a config file
    72  	// matching the subServerName name, then false will be returned for the
    73  	// second parameter.
    74  	FetchConfig(subServerName string) (interface{}, bool)
    75  }
    76  
    77  // SubServerDriver is a template struct that allows the root server to create a
    78  // sub-server gRPC handler with minimal knowledge.
    79  type SubServerDriver struct {
    80  	// SubServerName is the full name of a sub-sever.
    81  	//
    82  	// NOTE: This MUST be unique.
    83  	SubServerName string
    84  
    85  	// NewGrpcHandler creates a a new sub-server gRPC interface that can be
    86  	// registered with the root gRPC server. It is not expected that the
    87  	// SubServer is ready for operation before its CreateSubServer and
    88  	// Start methods have been called.
    89  	NewGrpcHandler func() GrpcHandler
    90  }
    91  
    92  var (
    93  	// subServers is a package level global variable that houses all the
    94  	// registered sub-servers.
    95  	subServers = make(map[string]*SubServerDriver)
    96  
    97  	// registerMtx is a mutex that protects access to the above subServer
    98  	// map.
    99  	registerMtx sync.Mutex
   100  )
   101  
   102  // RegisteredSubServers returns all registered sub-servers.
   103  //
   104  // NOTE: This function is safe for concurrent access.
   105  func RegisteredSubServers() []*SubServerDriver {
   106  	registerMtx.Lock()
   107  	defer registerMtx.Unlock()
   108  
   109  	drivers := make([]*SubServerDriver, 0, len(subServers))
   110  	for _, driver := range subServers {
   111  		drivers = append(drivers, driver)
   112  	}
   113  
   114  	return drivers
   115  }
   116  
   117  // RegisterSubServer should be called by a sub-server within its package's
   118  // init() method to register its existence with the main sub-server map. Each
   119  // sub-server, if active, is meant to register via this method in their init()
   120  // method. This allows callers to easily initialize and register all
   121  // sub-servers without knowing any details beyond that the fact that they
   122  // satisfy the necessary interfaces.
   123  //
   124  // NOTE: This function is safe for concurrent access.
   125  func RegisterSubServer(driver *SubServerDriver) error {
   126  	registerMtx.Lock()
   127  	defer registerMtx.Unlock()
   128  
   129  	if _, ok := subServers[driver.SubServerName]; ok {
   130  		return fmt.Errorf("subserver already registered")
   131  	}
   132  
   133  	subServers[driver.SubServerName] = driver
   134  
   135  	return nil
   136  }
   137  
   138  // SupportedServers returns slice of the names of all registered sub-servers.
   139  //
   140  // NOTE: This function is safe for concurrent access.
   141  func SupportedServers() []string {
   142  	registerMtx.Lock()
   143  	defer registerMtx.Unlock()
   144  
   145  	supportedSubServers := make([]string, 0, len(subServers))
   146  	for driverName := range subServers {
   147  		supportedSubServers = append(supportedSubServers, driverName)
   148  	}
   149  
   150  	return supportedSubServers
   151  }