@@ -26,6 +26,7 @@ import (
26
26
"github.com/lightningnetwork/lnd/fn"
27
27
"github.com/lightningnetwork/lnd/macaroons"
28
28
"google.golang.org/grpc"
29
+ "google.golang.org/grpc/metadata"
29
30
"gopkg.in/macaroon-bakery.v2/bakery"
30
31
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
31
32
"gopkg.in/macaroon.v2"
@@ -77,10 +78,23 @@ func newSessionRPCServer(cfg *sessionRpcServerConfig) (*sessionRpcServer,
77
78
// actual mailbox server that spins up the Terminal Connect server
78
79
// interface.
79
80
server := session .NewServer (
80
- func (opts ... grpc.ServerOption ) * grpc.Server {
81
- allOpts := append (cfg .grpcOptions , opts ... )
81
+ func (id session.ID , opts ... grpc.ServerOption ) * grpc.Server {
82
+ // Add the session ID injector interceptors first so
83
+ // that the session ID is available in the context of
84
+ // all interceptors that come after.
85
+ allOpts := []grpc.ServerOption {
86
+ addSessionIDToStreamCtx (id ),
87
+ addSessionIDToUnaryCtx (id ),
88
+ }
89
+
90
+ allOpts = append (allOpts , cfg .grpcOptions ... )
91
+ allOpts = append (allOpts , opts ... )
92
+
93
+ // Construct the gRPC server with the options.
82
94
grpcServer := grpc .NewServer (allOpts ... )
83
95
96
+ // Register various grpc servers with the LNC session
97
+ // server.
84
98
cfg .registerGrpcServers (grpcServer )
85
99
86
100
return grpcServer
@@ -94,6 +108,62 @@ func newSessionRPCServer(cfg *sessionRpcServerConfig) (*sessionRpcServer,
94
108
}, nil
95
109
}
96
110
111
+ // wrappedServerStream is a wrapper around the grpc.ServerStream that allows us
112
+ // to set a custom context. This is needed since the stream handler function
113
+ // doesn't take a context as an argument, but rather has a Context method on the
114
+ // handler itself. So we use this custom wrapper to override this method.
115
+ type wrappedServerStream struct {
116
+ grpc.ServerStream
117
+ ctx context.Context
118
+ }
119
+
120
+ // Context returns the context of the stream.
121
+ //
122
+ // NOTE: This implements the grpc.ServerStream Context method.
123
+ func (w * wrappedServerStream ) Context () context.Context {
124
+ return w .ctx
125
+ }
126
+
127
+ // addSessionIDToStreamCtx is a gRPC stream interceptor that adds the given
128
+ // session ID to the context of the stream. This allows us to access the
129
+ // session ID later on for any gRPC calls made through this stream.
130
+ func addSessionIDToStreamCtx (id session.ID ) grpc.ServerOption {
131
+ return grpc .StreamInterceptor (func (srv any , ss grpc.ServerStream ,
132
+ info * grpc.StreamServerInfo ,
133
+ handler grpc.StreamHandler ) error {
134
+
135
+ md , _ := metadata .FromIncomingContext (ss .Context ())
136
+ mdCopy := md .Copy ()
137
+ session .AddToGRPCMetadata (mdCopy , id )
138
+
139
+ // Wrap the original stream with our custom context.
140
+ wrapped := & wrappedServerStream {
141
+ ServerStream : ss ,
142
+ ctx : metadata .NewIncomingContext (
143
+ ss .Context (), mdCopy ,
144
+ ),
145
+ }
146
+
147
+ return handler (srv , wrapped )
148
+ })
149
+ }
150
+
151
+ // addSessionIDToUnaryCtx is a gRPC unary interceptor that adds the given
152
+ // session ID to the context of the unary call. This allows us to access the
153
+ // session ID later on for any gRPC calls made through this context.
154
+ func addSessionIDToUnaryCtx (id session.ID ) grpc.ServerOption {
155
+ return grpc .UnaryInterceptor (func (ctx context.Context , req any ,
156
+ info * grpc.UnaryServerInfo ,
157
+ handler grpc.UnaryHandler ) (resp any , err error ) {
158
+
159
+ md , _ := metadata .FromIncomingContext (ctx )
160
+ mdCopy := md .Copy ()
161
+ session .AddToGRPCMetadata (mdCopy , id )
162
+
163
+ return handler (metadata .NewIncomingContext (ctx , mdCopy ), req )
164
+ })
165
+ }
166
+
97
167
// start all the components necessary for the sessionRpcServer to start serving
98
168
// requests. This includes resuming all non-revoked sessions.
99
169
func (s * sessionRpcServer ) start (ctx context.Context ) error {
0 commit comments