code.vegaprotocol.io/vega@v0.79.0/blockexplorer/api/rest.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package api
    17  
    18  import (
    19  	"context"
    20  	"net/http"
    21  
    22  	datanodeRest "code.vegaprotocol.io/vega/datanode/gateway/rest"
    23  	"code.vegaprotocol.io/vega/logging"
    24  	protoapi "code.vegaprotocol.io/vega/protos/blockexplorer/api/v1"
    25  
    26  	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    27  	"google.golang.org/grpc"
    28  	"google.golang.org/grpc/credentials/insecure"
    29  )
    30  
    31  // Handler implement a rest server acting as a proxy to the grpc api.
    32  type RESTHandler struct {
    33  	RESTConfig
    34  	log    *logging.Logger
    35  	dialer grpcDialer
    36  	mux    *runtime.ServeMux
    37  	conn   *grpc.ClientConn
    38  }
    39  
    40  func NewRESTHandler(log *logging.Logger, dialer grpcDialer, config RESTConfig) *RESTHandler {
    41  	log = log.Named(restNamedLogger)
    42  	log.SetLevel(config.Level.Get())
    43  
    44  	return &RESTHandler{
    45  		log:        log,
    46  		RESTConfig: config,
    47  		dialer:     dialer,
    48  		mux:        runtime.NewServeMux(restHandlerServeMuxOptions()...),
    49  	}
    50  }
    51  
    52  func (r *RESTHandler) Name() string { return "REST" }
    53  
    54  func (r *RESTHandler) Start(ctx context.Context) error {
    55  	r.log.Info("Starting REST API", logging.String("endpoint", r.Endpoint))
    56  
    57  	opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
    58  	if err := r.registerBlockExplorer(ctx, r.mux, opts); err != nil {
    59  		r.log.Panic("Failure registering trading handler for REST proxy endpoints", logging.Error(err))
    60  	}
    61  
    62  	return nil
    63  }
    64  
    65  // registerBlockExplorer is a variation of RegisterBlockExplorerHandlerFromEndpoint, which uses our custom dialer.
    66  func (r *RESTHandler) registerBlockExplorer(ctx context.Context, mux *runtime.ServeMux, opts []grpc.DialOption) error {
    67  	conn, err := r.dialer.DialGRPC(ctx, opts...)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	r.conn = conn
    72  	return protoapi.RegisterBlockExplorerServiceHandler(ctx, mux, conn)
    73  }
    74  
    75  func (r *RESTHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    76  	r.mux.ServeHTTP(w, req)
    77  }
    78  
    79  func (r *RESTHandler) Stop() {
    80  	if r.conn != nil {
    81  		r.log.Info("Stopping REST API")
    82  		_ = r.conn.Close()
    83  	}
    84  }
    85  
    86  func restHandlerServeMuxOptions() []runtime.ServeMuxOption {
    87  	jsonPB := &datanodeRest.JSONPb{
    88  		EmitDefaults: true,
    89  		Indent:       "  ", // formatted json output
    90  		OrigName:     false,
    91  	}
    92  
    93  	return []runtime.ServeMuxOption{
    94  		runtime.WithMarshalerOption(runtime.MIMEWildcard, jsonPB),
    95  	}
    96  }