Skip to content

Commit c31c3c2

Browse files
committed
multi: implement the status server
1 parent bd06da4 commit c31c3c2

File tree

4 files changed

+145
-3
lines changed

4 files changed

+145
-3
lines changed

perms/permissions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ var (
6262
Entity: "account",
6363
Action: "write",
6464
}},
65+
"/litrpc.Status/GetSubServerState": {},
6566
}
6667

6768
// whiteListedLNDMethods is a map of all lnd RPC methods that don't

rpc_proxy.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
"github.com/improbable-eng/grpc-web/go/grpcweb"
15+
"github.com/lightninglabs/lightning-terminal/litrpc"
1516
"github.com/lightninglabs/lightning-terminal/perms"
1617
"github.com/lightninglabs/lightning-terminal/session"
1718
"github.com/lightningnetwork/lnd/lncfg"
@@ -259,7 +260,7 @@ func (p *rpcProxy) isHandling(resp http.ResponseWriter,
259260
if p.grpcWebProxy.IsGrpcWebRequest(req) ||
260261
p.grpcWebProxy.IsGrpcWebSocketRequest(req) {
261262

262-
if !p.hasStarted() {
263+
if !p.hasStarted() && !isStatusReq(req.URL.Path) {
263264
resp.WriteHeader(http.StatusServiceUnavailable)
264265
_, _ = resp.Write(make([]byte, 0))
265266
} else {
@@ -273,7 +274,7 @@ func (p *rpcProxy) isHandling(resp http.ResponseWriter,
273274
// Normal gRPC requests are also easy to identify. These we can
274275
// send directly to the lnd proxy's gRPC server.
275276
if isGrpcRequest(req) {
276-
if !p.hasStarted() {
277+
if !p.hasStarted() && !isStatusReq(req.URL.Path) {
277278
resp.WriteHeader(http.StatusServiceUnavailable)
278279
_, _ = resp.Write(make([]byte, 0))
279280
} else {
@@ -652,3 +653,11 @@ func isGrpcRequest(req *http.Request) bool {
652653
return req.ProtoMajor == 2 &&
653654
strings.HasPrefix(contentType, contentTypeGrpc)
654655
}
656+
657+
// isStatusReq returns true if the given request is intended for the
658+
// litrpc.Status service.
659+
func isStatusReq(uri string) bool {
660+
return strings.HasPrefix(
661+
uri, fmt.Sprintf("/%s", litrpc.Status_ServiceDesc.ServiceName),
662+
)
663+
}

state_server.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package terminal
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"sync"
7+
8+
"github.com/lightninglabs/lightning-terminal/litrpc"
9+
)
10+
11+
const (
12+
LitSubServer string = "lit"
13+
LNDSubServer string = "lnd"
14+
PoolSubServer string = "pool"
15+
LoopSubServer string = "loop"
16+
FaradaySubServer string = "faraday"
17+
)
18+
19+
// statusServer is an implementation of the litrpc.StatusServer which can be
20+
// queried for the status of various LiT sub-servers.
21+
type statusServer struct {
22+
litrpc.UnimplementedStatusServer
23+
24+
m map[string]*subServerStatus
25+
mu sync.RWMutex
26+
}
27+
28+
// subServerStatus represents the status of a sub-server.
29+
type subServerStatus struct {
30+
running bool
31+
err string
32+
}
33+
34+
// newSubServerStatus constructs a new subServerStatus.
35+
func newSubServerStatus() *subServerStatus {
36+
return &subServerStatus{}
37+
}
38+
39+
// newStatusServer constructs a new statusServer.
40+
func newStatusServer() *statusServer {
41+
s := &statusServer{
42+
m: map[string]*subServerStatus{
43+
LitSubServer: newSubServerStatus(),
44+
LNDSubServer: newSubServerStatus(),
45+
FaradaySubServer: newSubServerStatus(),
46+
PoolSubServer: newSubServerStatus(),
47+
LoopSubServer: newSubServerStatus(),
48+
},
49+
}
50+
51+
return s
52+
}
53+
54+
// GetSubServerState queries the current status of a given sub-server.
55+
//
56+
// NOTE: this is part of the litrpc.StatusServer interface.
57+
func (s *statusServer) GetSubServerState(_ context.Context,
58+
_ *litrpc.GetSubServerStatusReq) (*litrpc.GetSubServerStatusResp,
59+
error) {
60+
61+
s.mu.RLock()
62+
defer s.mu.RUnlock()
63+
64+
resp := make(map[string]*litrpc.SubServerStatus, len(s.m))
65+
for server, status := range s.m {
66+
resp[server] = &litrpc.SubServerStatus{
67+
Running: status.running,
68+
Error: status.err,
69+
}
70+
}
71+
72+
return &litrpc.GetSubServerStatusResp{
73+
SubServers: resp,
74+
}, nil
75+
}
76+
77+
// getSubServerState queries the current status of a given sub-server.
78+
func (s *statusServer) getSubServerState(name string) (bool, string) {
79+
s.mu.RLock()
80+
defer s.mu.RUnlock()
81+
82+
system, ok := s.m[name]
83+
if !ok {
84+
return false, ""
85+
}
86+
87+
return system.running, system.err
88+
}
89+
90+
// setServerRunning can be used to set the status of a sub-server as running
91+
// with no errors.
92+
func (s *statusServer) setServerRunning(name string) {
93+
s.mu.Lock()
94+
defer s.mu.Unlock()
95+
96+
s.m[name] = &subServerStatus{
97+
running: true,
98+
}
99+
}
100+
101+
// setServerStopped can be used to set the status of a sub-server as not running
102+
// and with no errors.
103+
func (s *statusServer) setServerStopped(name string) {
104+
s.mu.Lock()
105+
defer s.mu.Unlock()
106+
107+
s.m[name] = &subServerStatus{
108+
running: false,
109+
}
110+
}
111+
112+
// setServerErrored can be used to set the status of a sub-server as not running
113+
// and also to set an error message for the sub-server.
114+
func (s *statusServer) setServerErrored(name string, errStr string,
115+
params ...interface{}) {
116+
117+
s.mu.Lock()
118+
defer s.mu.Unlock()
119+
120+
err := fmt.Sprintf(errStr, params...)
121+
log.Errorf("could not start the %s sub-server: %s", name, err)
122+
123+
s.m[name] = &subServerStatus{
124+
running: false,
125+
err: err,
126+
}
127+
}

terminal.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ type LightningTerminal struct {
151151
lndClient *lndclient.GrpcLndServices
152152
basicClient lnrpc.LightningClient
153153

154+
statusServer *statusServer
155+
154156
faradayServer *frdrpcserver.RPCServer
155157
faradayStarted bool
156158

@@ -183,7 +185,9 @@ type LightningTerminal struct {
183185

184186
// New creates a new instance of the lightning-terminal daemon.
185187
func New() *LightningTerminal {
186-
return &LightningTerminal{}
188+
return &LightningTerminal{
189+
statusServer: newStatusServer(),
190+
}
187191
}
188192

189193
// Run starts everything and then blocks until either the application is shut
@@ -756,6 +760,7 @@ func (g *LightningTerminal) registerSubDaemonGrpcServers(server *grpc.Server,
756760
if withLitRPC {
757761
litrpc.RegisterSessionsServer(server, g.sessionRpcServer)
758762
litrpc.RegisterAccountsServer(server, g.accountRpcServer)
763+
litrpc.RegisterStatusServer(server, g.statusServer)
759764
}
760765
}
761766

0 commit comments

Comments
 (0)