/
subserver.go
152 lines (122 loc) · 3.23 KB
/
subserver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package subservers
import (
"fmt"
"sync"
"github.com/lightninglabs/lndclient"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc"
"google.golang.org/grpc"
)
const (
LND string = "lnd"
LIT string = "lit"
LOOP string = "loop"
POOL string = "pool"
TAP string = "taproot-assets"
FARADAY string = "faraday"
ACCOUNTS string = "accounts"
)
// subServerWrapper is a wrapper around the SubServer interface and is used by
// the subServerMgr to manage a SubServer.
type subServerWrapper struct {
SubServer
integratedStarted bool
startedMu sync.RWMutex
stopped sync.Once
remoteConn *grpc.ClientConn
wg sync.WaitGroup
quit chan struct{}
}
// started returns true if the subServer has been started. This only applies if
// the subServer is running in integrated mode.
func (s *subServerWrapper) started() bool {
s.startedMu.RLock()
defer s.startedMu.RUnlock()
return s.integratedStarted
}
// setStarted sets the subServer as started or not. This only applies if the
// subServer is running in integrated mode.
func (s *subServerWrapper) setStarted(started bool) {
s.startedMu.Lock()
defer s.startedMu.Unlock()
s.integratedStarted = started
}
// stop the subServer by closing the connection to it if it is remote or by
// stopping the integrated process.
func (s *subServerWrapper) stop() error {
// If the sub-server has not yet started, then we can exit early.
if !s.started() {
return nil
}
var returnErr error
s.stopped.Do(func() {
close(s.quit)
s.wg.Wait()
// If running in remote mode, close the connection.
if s.Remote() && s.remoteConn != nil {
err := s.remoteConn.Close()
if err != nil {
returnErr = fmt.Errorf("could not close "+
"remote connection: %v", err)
}
return
}
// Else, stop the integrated sub-server process.
err := s.Stop()
if err != nil {
returnErr = fmt.Errorf("could not close "+
"integrated connection: %v", err)
return
}
if s.ServerErrChan() == nil {
return
}
select {
case returnErr = <-s.ServerErrChan():
default:
}
})
return returnErr
}
// startIntegrated starts the subServer in integrated mode.
func (s *subServerWrapper) startIntegrated(lndClient lnrpc.LightningClient,
lndGrpc *lndclient.GrpcLndServices, withMacaroonService bool,
onError func(error)) error {
err := s.Start(lndClient, lndGrpc, withMacaroonService)
if err != nil {
return err
}
s.setStarted(true)
if s.ServerErrChan() == nil {
return nil
}
s.wg.Add(1)
go func() {
defer s.wg.Done()
select {
case err := <-s.ServerErrChan():
// The sub server should shut itself down if an error
// happens. We don't need to try to stop it again.
s.setStarted(false)
onError(
fmt.Errorf("received critical error from "+
"sub-server (%s), shutting down: %v",
s.Name(), err),
)
case <-s.quit:
}
}()
return nil
}
// connectRemote attempts to make a connection to the remote sub-server.
func (s *subServerWrapper) connectRemote() error {
cfg := s.RemoteConfig()
certPath := lncfg.CleanAndExpandPath(cfg.TLSCertPath)
name := s.Name()
conn, err := dialBackend(name, cfg.RPCServer, certPath)
if err != nil {
return fmt.Errorf("remote dial error: %v", err)
}
s.remoteConn = conn
return nil
}