github.com/livepeer/go-ethereum@v1.9.7/rpc/server.go (about) 1 // Copyright 2015 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 rpc 18 19 import ( 20 "context" 21 "io" 22 "sync/atomic" 23 24 mapset "github.com/deckarep/golang-set" 25 "github.com/ethereum/go-ethereum/log" 26 ) 27 28 const MetadataApi = "rpc" 29 30 // CodecOption specifies which type of messages a codec supports. 31 // 32 // Deprecated: this option is no longer honored by Server. 33 type CodecOption int 34 35 const ( 36 // OptionMethodInvocation is an indication that the codec supports RPC method calls 37 OptionMethodInvocation CodecOption = 1 << iota 38 39 // OptionSubscriptions is an indication that the codec suports RPC notifications 40 OptionSubscriptions = 1 << iota // support pub sub 41 ) 42 43 // Server is an RPC server. 44 type Server struct { 45 services serviceRegistry 46 idgen func() ID 47 run int32 48 codecs mapset.Set 49 } 50 51 // NewServer creates a new server instance with no registered handlers. 52 func NewServer() *Server { 53 server := &Server{idgen: randomIDGenerator(), codecs: mapset.NewSet(), run: 1} 54 // Register the default service providing meta information about the RPC service such 55 // as the services and methods it offers. 56 rpcService := &RPCService{server} 57 server.RegisterName(MetadataApi, rpcService) 58 return server 59 } 60 61 // RegisterName creates a service for the given receiver type under the given name. When no 62 // methods on the given receiver match the criteria to be either a RPC method or a 63 // subscription an error is returned. Otherwise a new service is created and added to the 64 // service collection this server provides to clients. 65 func (s *Server) RegisterName(name string, receiver interface{}) error { 66 return s.services.registerName(name, receiver) 67 } 68 69 // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes 70 // the response back using the given codec. It will block until the codec is closed or the 71 // server is stopped. In either case the codec is closed. 72 // 73 // Note that codec options are no longer supported. 74 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { 75 defer codec.Close() 76 77 // Don't serve if server is stopped. 78 if atomic.LoadInt32(&s.run) == 0 { 79 return 80 } 81 82 // Add the codec to the set so it can be closed by Stop. 83 s.codecs.Add(codec) 84 defer s.codecs.Remove(codec) 85 86 c := initClient(codec, s.idgen, &s.services) 87 <-codec.Closed() 88 c.Close() 89 } 90 91 // serveSingleRequest reads and processes a single RPC request from the given codec. This 92 // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in 93 // this mode. 94 func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { 95 // Don't serve if server is stopped. 96 if atomic.LoadInt32(&s.run) == 0 { 97 return 98 } 99 100 h := newHandler(ctx, codec, s.idgen, &s.services) 101 h.allowSubscribe = false 102 defer h.close(io.EOF, nil) 103 104 reqs, batch, err := codec.Read() 105 if err != nil { 106 if err != io.EOF { 107 codec.Write(ctx, errorMessage(&invalidMessageError{"parse error"})) 108 } 109 return 110 } 111 if batch { 112 h.handleBatch(reqs) 113 } else { 114 h.handleMsg(reqs[0]) 115 } 116 } 117 118 // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending 119 // requests to finish, then closes all codecs which will cancel pending requests and 120 // subscriptions. 121 func (s *Server) Stop() { 122 if atomic.CompareAndSwapInt32(&s.run, 1, 0) { 123 log.Debug("RPC server shutting down") 124 s.codecs.Each(func(c interface{}) bool { 125 c.(ServerCodec).Close() 126 return true 127 }) 128 } 129 } 130 131 // RPCService gives meta information about the server. 132 // e.g. gives information about the loaded modules. 133 type RPCService struct { 134 server *Server 135 } 136 137 // Modules returns the list of RPC services with their version number 138 func (s *RPCService) Modules() map[string]string { 139 s.server.services.mu.Lock() 140 defer s.server.services.mu.Unlock() 141 142 modules := make(map[string]string) 143 for name := range s.server.services.services { 144 modules[name] = "1.0" 145 } 146 return modules 147 }