@@ -18,7 +18,9 @@ import (
1818 "strings"
1919 "time"
2020
21- "github.com/onflow/go-ethereum/core"
21+ "github.com/onflow/flow-go/module/component"
22+ "github.com/onflow/flow-go/module/irrecoverable"
23+
2224 gethVM "github.com/onflow/go-ethereum/core/vm"
2325 gethLog "github.com/onflow/go-ethereum/log"
2426 "github.com/onflow/go-ethereum/rpc"
@@ -57,8 +59,12 @@ type Server struct {
5759
5860 config config.Config
5961 collector metrics.Collector
62+
63+ startupCompleted chan struct {}
6064}
6165
66+ var _ component.Component = (* Server )(nil )
67+
6268const (
6369 shutdownTimeout = 5 * time .Second
6470 batchRequestLimit = 50
@@ -79,10 +85,11 @@ func NewServer(
7985 gethLog .SetDefault (gethLog .NewLogger (zeroSlog ))
8086
8187 return & Server {
82- logger : logger ,
83- timeouts : rpc .DefaultHTTPTimeouts ,
84- config : cfg ,
85- collector : collector ,
88+ logger : logger ,
89+ timeouts : rpc .DefaultHTTPTimeouts ,
90+ config : cfg ,
91+ collector : collector ,
92+ startupCompleted : make (chan struct {}),
8693 }
8794}
8895
@@ -179,9 +186,10 @@ func (h *Server) disableWS() bool {
179186}
180187
181188// Start starts the HTTP server if it is enabled and not already running.
182- func (h * Server ) Start () error {
189+ func (h * Server ) Start (ctx irrecoverable.SignalerContext ) {
190+ defer close (h .startupCompleted )
183191 if h .endpoint == "" || h .listener != nil {
184- return nil // already running or not configured
192+ return // already running or not configured
185193 }
186194
187195 // Initialize the server.
@@ -192,16 +200,21 @@ func (h *Server) Start() error {
192200 h .server .ReadHeaderTimeout = h .timeouts .ReadHeaderTimeout
193201 h .server .WriteTimeout = h .timeouts .WriteTimeout
194202 h .server .IdleTimeout = h .timeouts .IdleTimeout
203+ h .server .BaseContext = func (_ net.Listener ) context.Context {
204+ return ctx
205+ }
195206 }
196207
208+ listenConfig := net.ListenConfig {}
197209 // Start the server.
198- listener , err := net .Listen ("tcp" , h .endpoint )
210+ listener , err := listenConfig .Listen (ctx , "tcp" , h .endpoint )
199211 if err != nil {
200212 // If the server fails to start, we need to clear out the RPC and WS
201213 // configurations so they can be configured another time.
202214 h .disableRPC ()
203215 h .disableWS ()
204- return err
216+ ctx .Throw (err )
217+ return
205218 }
206219
207220 h .listener = listener
@@ -213,7 +226,7 @@ func (h *Server) Start() error {
213226 return
214227 }
215228 h .logger .Err (err ).Msg ("failed to start API server" )
216- panic (err )
229+ ctx . Throw (err )
217230 }
218231 }()
219232
@@ -225,8 +238,17 @@ func (h *Server) Start() error {
225238 url := fmt .Sprintf ("ws://%v" , listener .Addr ())
226239 h .logger .Info ().Msgf ("JSON-RPC over WebSocket enabled: %s" , url )
227240 }
241+ }
228242
229- return nil
243+ func (h * Server ) Ready () <- chan struct {} {
244+ ready := make (chan struct {})
245+
246+ go func () {
247+ <- h .startupCompleted
248+ close (ready )
249+ }()
250+
251+ return ready
230252}
231253
232254// disableRPC stops the JSON-RPC over HTTP handler.
@@ -296,41 +318,50 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
296318 w .WriteHeader (http .StatusNotFound )
297319}
298320
299- // Stop shuts down the HTTP server.
300- func (h * Server ) Stop () {
301- if h .listener == nil {
302- return // not running
303- }
321+ // Done shuts down the HTTP server.
322+ func (h * Server ) Done () <- chan struct {} {
323+ done := make (chan struct {})
304324
305- // Shut down the server.
306- httpHandler := h .httpHandler
307- if httpHandler != nil {
308- httpHandler .server .Stop ()
309- h .httpHandler = nil
310- }
325+ go func () {
326+ defer close (done )
311327
312- wsHandler := h .wsHandler
313- if wsHandler != nil {
314- wsHandler .server .Stop ()
315- h .wsHandler = nil
316- }
328+ if h .listener == nil {
329+ return // not running
330+ }
317331
318- ctx , cancel := context .WithTimeout (context .Background (), shutdownTimeout )
319- defer cancel ()
320- err := h .server .Shutdown (ctx )
321- if err != nil && err == ctx .Err () {
322- h .logger .Warn ().Msg ("HTTP server graceful shutdown timed out" )
323- h .server .Close ()
324- }
332+ // Shut down the server.
333+ httpHandler := h .httpHandler
334+ if httpHandler != nil {
335+ httpHandler .server .Stop ()
336+ h .httpHandler = nil
337+ }
338+
339+ wsHandler := h .wsHandler
340+ if wsHandler != nil {
341+ wsHandler .server .Stop ()
342+ h .wsHandler = nil
343+ }
344+
345+ ctx , cancel := context .WithTimeout (context .Background (), shutdownTimeout )
346+ defer cancel ()
347+ err := h .server .Shutdown (ctx )
348+ if err != nil && err == ctx .Err () {
349+ h .logger .Warn ().Msg ("HTTP server graceful shutdown timed out" )
350+ h .server .Close ()
351+ }
325352
326- h .listener .Close ()
327- h .logger .Info ().Msgf (
328- "HTTP server stopped, endpoint: %s" , h .listener .Addr (),
329- )
353+ h .listener .Close ()
354+ h .logger .Info ().Msgf (
355+ "HTTP server stopped, endpoint: %s" , h .listener .Addr (),
356+ )
357+
358+ // Clear out everything to allow re-configuring it later.
359+ h .host , h .port , h .endpoint = "" , 0 , ""
360+ h .server , h .listener = nil , nil
361+
362+ }()
330363
331- // Clear out everything to allow re-configuring it later.
332- h .host , h .port , h .endpoint = "" , 0 , ""
333- h .server , h .listener = nil , nil
364+ return done
334365}
335366
336367// CheckTimeouts ensures that timeout values are meaningful
0 commit comments