| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | // Copyright 2015 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/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | package rpc | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-03-22 18:20:33 +01:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-16 00:54:19 -07:00
										 |  |  | 	mapset "github.com/deckarep/golang-set" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-08 12:08:37 +03:00
										 |  |  | const MetadataApi = "rpc" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // CodecOption specifies which type of messages a codec supports. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Deprecated: this option is no longer honored by Server. | 
					
						
							| 
									
										
										
										
											2016-03-29 15:07:40 +02:00
										 |  |  | type CodecOption int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	// OptionMethodInvocation is an indication that the codec supports RPC method calls | 
					
						
							|  |  |  | 	OptionMethodInvocation CodecOption = 1 << iota | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-25 16:21:28 +08:00
										 |  |  | 	// OptionSubscriptions is an indication that the codec supports RPC notifications | 
					
						
							| 
									
										
										
										
											2016-03-29 15:07:40 +02:00
										 |  |  | 	OptionSubscriptions = 1 << iota // support pub sub | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // Server is an RPC server. | 
					
						
							|  |  |  | type Server struct { | 
					
						
							|  |  |  | 	services serviceRegistry | 
					
						
							|  |  |  | 	idgen    func() ID | 
					
						
							|  |  |  | 	run      int32 | 
					
						
							|  |  |  | 	codecs   mapset.Set | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // NewServer creates a new server instance with no registered handlers. | 
					
						
							|  |  |  | func NewServer() *Server { | 
					
						
							|  |  |  | 	server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet(), run: 1} | 
					
						
							|  |  |  | 	// Register the default service providing meta information about the RPC service such | 
					
						
							|  |  |  | 	// as the services and methods it offers. | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	rpcService := &RPCService{server} | 
					
						
							| 
									
										
										
										
											2016-05-11 11:49:44 +03:00
										 |  |  | 	server.RegisterName(MetadataApi, rpcService) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	return server | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // RegisterName creates a service for the given receiver type under the given name. When no | 
					
						
							|  |  |  | // methods on the given receiver match the criteria to be either a RPC method or a | 
					
						
							|  |  |  | // subscription an error is returned. Otherwise a new service is created and added to the | 
					
						
							|  |  |  | // service collection this server provides to clients. | 
					
						
							|  |  |  | func (s *Server) RegisterName(name string, receiver interface{}) error { | 
					
						
							|  |  |  | 	return s.services.registerName(name, receiver) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes | 
					
						
							|  |  |  | // the response back using the given codec. It will block until the codec is closed or the | 
					
						
							|  |  |  | // server is stopped. In either case the codec is closed. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note that codec options are no longer supported. | 
					
						
							|  |  |  | func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	defer codec.close() | 
					
						
							| 
									
										
										
										
											2017-04-06 08:56:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	// Don't serve if server is stopped. | 
					
						
							|  |  |  | 	if atomic.LoadInt32(&s.run) == 0 { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-07-24 08:00:55 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	// Add the codec to the set so it can be closed by Stop. | 
					
						
							|  |  |  | 	s.codecs.Add(codec) | 
					
						
							|  |  |  | 	defer s.codecs.Remove(codec) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	c := initClient(codec, s.idgen, &s.services) | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	<-codec.closed() | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	c.Close() | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // serveSingleRequest reads and processes a single RPC request from the given codec. This | 
					
						
							|  |  |  | // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in | 
					
						
							|  |  |  | // this mode. | 
					
						
							|  |  |  | func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { | 
					
						
							|  |  |  | 	// Don't serve if server is stopped. | 
					
						
							|  |  |  | 	if atomic.LoadInt32(&s.run) == 0 { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	h := newHandler(ctx, codec, s.idgen, &s.services) | 
					
						
							|  |  |  | 	h.allowSubscribe = false | 
					
						
							|  |  |  | 	defer h.close(io.EOF, nil) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 	reqs, batch, err := codec.readBatch() | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if err != io.EOF { | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 			codec.writeJSON(ctx, errorMessage(&invalidMessageError{"parse error"})) | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if batch { | 
					
						
							|  |  |  | 		h.handleBatch(reqs) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		h.handleMsg(reqs[0]) | 
					
						
							| 
									
										
										
										
											2017-03-24 13:07:12 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending | 
					
						
							|  |  |  | // requests to finish, then closes all codecs which will cancel pending requests and | 
					
						
							|  |  |  | // subscriptions. | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | func (s *Server) Stop() { | 
					
						
							|  |  |  | 	if atomic.CompareAndSwapInt32(&s.run, 1, 0) { | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 		log.Debug("RPC server shutting down") | 
					
						
							| 
									
										
										
										
											2016-07-12 17:34:59 +02:00
										 |  |  | 		s.codecs.Each(func(c interface{}) bool { | 
					
						
							| 
									
										
										
										
											2019-11-18 09:40:59 +01:00
										 |  |  | 			c.(ServerCodec).close() | 
					
						
							| 
									
										
										
										
											2016-07-12 17:34:59 +02:00
										 |  |  | 			return true | 
					
						
							| 
									
										
										
										
											2015-12-16 10:58:01 +01:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // RPCService gives meta information about the server. | 
					
						
							|  |  |  | // e.g. gives information about the loaded modules. | 
					
						
							|  |  |  | type RPCService struct { | 
					
						
							|  |  |  | 	server *Server | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | // Modules returns the list of RPC services with their version number | 
					
						
							|  |  |  | func (s *RPCService) Modules() map[string]string { | 
					
						
							|  |  |  | 	s.server.services.mu.Lock() | 
					
						
							|  |  |  | 	defer s.server.services.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	modules := make(map[string]string) | 
					
						
							|  |  |  | 	for name := range s.server.services.services { | 
					
						
							|  |  |  | 		modules[name] = "1.0" | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-02-04 13:47:34 +01:00
										 |  |  | 	return modules | 
					
						
							| 
									
										
										
										
											2015-10-15 16:07:19 +02:00
										 |  |  | } |