cmd, graphql, node: graphql flag polishes, les integration

This commit is contained in:
Péter Szilágyi
2019-06-12 11:24:24 +03:00
parent 2b54666018
commit e3ec77f50e
9 changed files with 203 additions and 164 deletions

View File

@ -60,11 +60,11 @@ var graphiql = []byte(`
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.11/graphiql.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.11/graphiql.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.13.0/graphiql.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/3.0.0/fetch.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.5/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.5/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.13.0/graphiql.min.js"></script>
</head>
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden;">
<div id="graphiql" style="height: 100vh;">Loading...</div>

View File

@ -20,9 +20,6 @@ package graphql
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"time"
"github.com/ethereum/go-ethereum"
@ -32,16 +29,10 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
graphqlgo "github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
)
var OnlyOnMainChainError = errors.New("This operation is only available for blocks on the canonical chain.")
@ -49,7 +40,7 @@ var BlockInvariantError = errors.New("Block objects must be instantiated with at
// Account represents an Ethereum account at a particular block.
type Account struct {
backend *eth.EthAPIBackend
backend ethapi.Backend
address common.Address
blockNumber rpc.BlockNumber
}
@ -102,7 +93,7 @@ func (a *Account) Storage(ctx context.Context, args struct{ Slot common.Hash })
// Log represents an individual log message. All arguments are mandatory.
type Log struct {
backend *eth.EthAPIBackend
backend ethapi.Backend
transaction *Transaction
log *types.Log
}
@ -134,7 +125,7 @@ func (l *Log) Data(ctx context.Context) hexutil.Bytes {
// Transaction represents an Ethereum transaction.
// backend and hash are mandatory; all others will be fetched when required.
type Transaction struct {
backend *eth.EthAPIBackend
backend ethapi.Backend
hash common.Hash
tx *types.Transaction
block *Block
@ -349,7 +340,7 @@ const (
// backend, and either num or hash are mandatory. All other fields are lazily fetched
// when required.
type Block struct {
backend *eth.EthAPIBackend
backend ethapi.Backend
num *rpc.BlockNumber
hash common.Hash
header *types.Header
@ -745,7 +736,7 @@ type BlockFilterCriteria struct {
// runFilter accepts a filter and executes it, returning all its results as
// `Log` objects.
func runFilter(ctx context.Context, be *eth.EthAPIBackend, filter *filters.Filter) ([]*Log, error) {
func runFilter(ctx context.Context, be ethapi.Backend, filter *filters.Filter) ([]*Log, error) {
logs, err := filter.Logs(ctx)
if err != nil || logs == nil {
return nil, err
@ -888,7 +879,7 @@ func (b *Block) EstimateGas(ctx context.Context, args struct {
}
type Pending struct {
backend *eth.EthAPIBackend
backend ethapi.Backend
}
func (p *Pending) TransactionCount(ctx context.Context) (int32, error) {
@ -947,7 +938,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct {
// Resolver is the top-level object in the GraphQL hierarchy.
type Resolver struct {
backend *eth.EthAPIBackend
backend ethapi.Backend
}
func (r *Resolver) Block(ctx context.Context, args struct {
@ -1088,7 +1079,6 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria
// Construct the range filter
filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics)
return runFilter(ctx, r.backend, filter)
}
@ -1145,89 +1135,3 @@ func (r *Resolver) Syncing() (*SyncState, error) {
// Otherwise gather the block sync stats
return &SyncState{progress}, nil
}
// NewHandler returns a new `http.Handler` that will answer GraphQL queries.
// It additionally exports an interactive query browser on the / endpoint.
func NewHandler(be *eth.EthAPIBackend) (http.Handler, error) {
q := Resolver{be}
s, err := graphqlgo.ParseSchema(schema, &q)
if err != nil {
return nil, err
}
h := &relay.Handler{Schema: s}
mux := http.NewServeMux()
mux.Handle("/", GraphiQL{})
mux.Handle("/graphql", h)
mux.Handle("/graphql/", h)
return mux, nil
}
// Service encapsulates a GraphQL service.
type Service struct {
endpoint string // The host:port endpoint for this service.
cors []string // Allowed CORS domains
vhosts []string // Recognised vhosts
timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests.
backend *eth.EthAPIBackend // The backend that queries will operate onn.
handler http.Handler // The `http.Handler` used to answer queries.
listener net.Listener // The listening socket.
}
// Protocols returns the list of protocols exported by this service.
func (s *Service) Protocols() []p2p.Protocol { return nil }
// APIs returns the list of APIs exported by this service.
func (s *Service) APIs() []rpc.API { return nil }
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
func (s *Service) Start(server *p2p.Server) error {
var err error
s.handler, err = NewHandler(s.backend)
if err != nil {
return err
}
if s.listener, err = net.Listen("tcp", s.endpoint); err != nil {
return err
}
go rpc.NewHTTPServer(s.cors, s.vhosts, s.timeouts, s.handler).Serve(s.listener)
log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.endpoint))
return nil
}
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
func (s *Service) Stop() error {
if s.listener != nil {
s.listener.Close()
s.listener = nil
log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.endpoint))
}
return nil
}
// NewService constructs a new service instance.
func NewService(backend *eth.EthAPIBackend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
return &Service{
endpoint: endpoint,
cors: cors,
vhosts: vhosts,
timeouts: timeouts,
backend: backend,
}, nil
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
var ethereum *eth.Ethereum
if err := ctx.Service(&ethereum); err != nil {
return nil, err
}
return NewService(ethereum.APIBackend, endpoint, cors, vhosts, timeouts)
})
}

View File

@ -22,8 +22,7 @@ import (
func TestBuildSchema(t *testing.T) {
// Make sure the schema can be parsed and matched up to the object model.
_, err := NewHandler(nil)
if err != nil {
if _, err := newHandler(nil); err != nil {
t.Errorf("Could not construct GraphQL handler: %v", err)
}
}

103
graphql/service.go Normal file
View File

@ -0,0 +1,103 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package graphql
import (
"fmt"
"net"
"net/http"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
)
// Service encapsulates a GraphQL service.
type Service struct {
endpoint string // The host:port endpoint for this service.
cors []string // Allowed CORS domains
vhosts []string // Recognised vhosts
timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests.
backend ethapi.Backend // The backend that queries will operate onn.
handler http.Handler // The `http.Handler` used to answer queries.
listener net.Listener // The listening socket.
}
// New constructs a new GraphQL service instance.
func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
return &Service{
endpoint: endpoint,
cors: cors,
vhosts: vhosts,
timeouts: timeouts,
backend: backend,
}, nil
}
// Protocols returns the list of protocols exported by this service.
func (s *Service) Protocols() []p2p.Protocol { return nil }
// APIs returns the list of APIs exported by this service.
func (s *Service) APIs() []rpc.API { return nil }
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
func (s *Service) Start(server *p2p.Server) error {
var err error
s.handler, err = newHandler(s.backend)
if err != nil {
return err
}
if s.listener, err = net.Listen("tcp", s.endpoint); err != nil {
return err
}
go rpc.NewHTTPServer(s.cors, s.vhosts, s.timeouts, s.handler).Serve(s.listener)
log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.endpoint))
return nil
}
// newHandler returns a new `http.Handler` that will answer GraphQL queries.
// It additionally exports an interactive query browser on the / endpoint.
func newHandler(backend ethapi.Backend) (http.Handler, error) {
q := Resolver{backend}
s, err := graphql.ParseSchema(schema, &q)
if err != nil {
return nil, err
}
h := &relay.Handler{Schema: s}
mux := http.NewServeMux()
mux.Handle("/", GraphiQL{})
mux.Handle("/graphql", h)
mux.Handle("/graphql/", h)
return mux, nil
}
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
func (s *Service) Stop() error {
if s.listener != nil {
s.listener.Close()
s.listener = nil
log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.endpoint))
}
return nil
}