github.com/hardtosaygoodbye/go-ethereum@v1.10.16-0.20220122011429-97003b9e6c15/les/vflux/server/service.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package server
    18  
    19  import (
    20  	"net"
    21  	"strings"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/hardtosaygoodbye/go-ethereum/les/utils"
    26  	"github.com/hardtosaygoodbye/go-ethereum/les/vflux"
    27  	"github.com/hardtosaygoodbye/go-ethereum/log"
    28  	"github.com/hardtosaygoodbye/go-ethereum/p2p/enode"
    29  	"github.com/hardtosaygoodbye/go-ethereum/rlp"
    30  )
    31  
    32  type (
    33  	// Server serves vflux requests
    34  	Server struct {
    35  		limiter         *utils.Limiter
    36  		lock            sync.Mutex
    37  		services        map[string]*serviceEntry
    38  		delayPerRequest time.Duration
    39  	}
    40  
    41  	// Service is a service registered at the Server and identified by a string id
    42  	Service interface {
    43  		Handle(id enode.ID, address string, name string, data []byte) []byte // never called concurrently
    44  	}
    45  
    46  	serviceEntry struct {
    47  		id, desc string
    48  		backend  Service
    49  	}
    50  )
    51  
    52  // NewServer creates a new Server
    53  func NewServer(delayPerRequest time.Duration) *Server {
    54  	return &Server{
    55  		limiter:         utils.NewLimiter(1000),
    56  		delayPerRequest: delayPerRequest,
    57  		services:        make(map[string]*serviceEntry),
    58  	}
    59  }
    60  
    61  // Register registers a Service
    62  func (s *Server) Register(b Service, id, desc string) {
    63  	srv := &serviceEntry{backend: b, id: id, desc: desc}
    64  	if strings.Contains(srv.id, ":") {
    65  		// srv.id + ":" will be used as a service database prefix
    66  		log.Error("Service ID contains ':'", "id", srv.id)
    67  		return
    68  	}
    69  	s.lock.Lock()
    70  	s.services[srv.id] = srv
    71  	s.lock.Unlock()
    72  }
    73  
    74  // Serve serves a vflux request batch
    75  // Note: requests are served by the Handle functions of the registered services. Serve
    76  // may be called concurrently but the Handle functions are called sequentially and
    77  // therefore thread safety is guaranteed.
    78  func (s *Server) Serve(id enode.ID, address string, requests vflux.Requests) vflux.Replies {
    79  	reqLen := uint(len(requests))
    80  	if reqLen == 0 || reqLen > vflux.MaxRequestLength {
    81  		return nil
    82  	}
    83  	// Note: the value parameter will be supplied by the token sale module (total amount paid)
    84  	ch := <-s.limiter.Add(id, address, 0, reqLen)
    85  	if ch == nil {
    86  		return nil
    87  	}
    88  	// Note: the limiter ensures that the following section is not running concurrently,
    89  	// the lock only protects against contention caused by new service registration
    90  	s.lock.Lock()
    91  	results := make(vflux.Replies, len(requests))
    92  	for i, req := range requests {
    93  		if service := s.services[req.Service]; service != nil {
    94  			results[i] = service.backend.Handle(id, address, req.Name, req.Params)
    95  		}
    96  	}
    97  	s.lock.Unlock()
    98  	time.Sleep(s.delayPerRequest * time.Duration(reqLen))
    99  	close(ch)
   100  	return results
   101  }
   102  
   103  // ServeEncoded serves an encoded vflux request batch and returns the encoded replies
   104  func (s *Server) ServeEncoded(id enode.ID, addr *net.UDPAddr, req []byte) []byte {
   105  	var requests vflux.Requests
   106  	if err := rlp.DecodeBytes(req, &requests); err != nil {
   107  		return nil
   108  	}
   109  	results := s.Serve(id, addr.String(), requests)
   110  	if results == nil {
   111  		return nil
   112  	}
   113  	res, _ := rlp.EncodeToBytes(&results)
   114  	return res
   115  }
   116  
   117  // Stop shuts down the server
   118  func (s *Server) Stop() {
   119  	s.limiter.Stop()
   120  }