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 }