github.com/cgcardona/r-subnet-evm@v0.1.5/rpc/server.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2015 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package rpc 28 29 import ( 30 "context" 31 "io" 32 "sync/atomic" 33 "time" 34 35 mapset "github.com/deckarep/golang-set" 36 "github.com/ethereum/go-ethereum/log" 37 ) 38 39 const MetadataApi = "rpc" 40 41 // CodecOption specifies which type of messages a codec supports. 42 // 43 // Deprecated: this option is no longer honored by Server. 44 type CodecOption int 45 46 const ( 47 // OptionMethodInvocation is an indication that the codec supports RPC method calls 48 OptionMethodInvocation CodecOption = 1 << iota 49 50 // OptionSubscriptions is an indication that the codec supports RPC notifications 51 OptionSubscriptions = 1 << iota // support pub sub 52 ) 53 54 // Server is an RPC server. 55 type Server struct { 56 services serviceRegistry 57 idgen func() ID 58 run int32 59 codecs mapset.Set 60 maximumDuration time.Duration 61 } 62 63 // NewServer creates a new server instance with no registered handlers. 64 // 65 // If [maximumDuration] > 0, the deadline of incoming requests is 66 // [maximumDuration] in the future. Otherwise, no deadline is assigned to 67 // incoming requests. 68 func NewServer(maximumDuration time.Duration) *Server { 69 server := &Server{ 70 idgen: randomIDGenerator(), 71 codecs: mapset.NewSet(), 72 run: 1, 73 maximumDuration: maximumDuration, 74 } 75 // Register the default service providing meta information about the RPC service such 76 // as the services and methods it offers. 77 rpcService := &RPCService{server} 78 server.RegisterName(MetadataApi, rpcService) 79 return server 80 } 81 82 // RegisterName creates a service for the given receiver type under the given name. When no 83 // methods on the given receiver match the criteria to be either a RPC method or a 84 // subscription an error is returned. Otherwise a new service is created and added to the 85 // service collection this server provides to clients. 86 func (s *Server) RegisterName(name string, receiver interface{}) error { 87 return s.services.registerName(name, receiver) 88 } 89 90 // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes 91 // the response back using the given codec. It will block until the codec is closed or the 92 // server is stopped. In either case the codec is closed. 93 // 94 // Note that codec options are no longer supported. 95 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption, apiMaxDuration, refillRate, maxStored time.Duration) { 96 defer codec.close() 97 98 // Don't serve if server is stopped. 99 if atomic.LoadInt32(&s.run) == 0 { 100 return 101 } 102 103 // Add the codec to the set so it can be closed by Stop. 104 s.codecs.Add(codec) 105 defer s.codecs.Remove(codec) 106 107 c := initClient(codec, s.idgen, &s.services, apiMaxDuration, refillRate, maxStored) 108 <-codec.closed() 109 c.Close() 110 } 111 112 // serveSingleRequest reads and processes a single RPC request from the given codec. This 113 // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in 114 // this mode. 115 func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { 116 // Don't serve if server is stopped. 117 if atomic.LoadInt32(&s.run) == 0 { 118 return 119 } 120 121 h := newHandler(ctx, codec, s.idgen, &s.services) 122 h.deadlineContext = s.maximumDuration 123 h.allowSubscribe = false 124 defer h.close(io.EOF, nil) 125 126 reqs, batch, err := codec.readBatch() 127 if err != nil { 128 if err != io.EOF { 129 codec.writeJSON(ctx, errorMessage(&invalidMessageError{"parse error"})) 130 } 131 return 132 } 133 if batch { 134 h.handleBatch(reqs) 135 } else { 136 h.handleMsg(reqs[0]) 137 } 138 } 139 140 // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending 141 // requests to finish, then closes all codecs which will cancel pending requests and 142 // subscriptions. 143 func (s *Server) Stop() { 144 if atomic.CompareAndSwapInt32(&s.run, 1, 0) { 145 log.Debug("RPC server shutting down") 146 s.codecs.Each(func(c interface{}) bool { 147 c.(ServerCodec).close() 148 return true 149 }) 150 } 151 } 152 153 // RPCService gives meta information about the server. 154 // e.g. gives information about the loaded modules. 155 type RPCService struct { 156 server *Server 157 } 158 159 // Modules returns the list of RPC services with their version number 160 func (s *RPCService) Modules() map[string]string { 161 s.server.services.mu.Lock() 162 defer s.server.services.mu.Unlock() 163 164 modules := make(map[string]string) 165 for name := range s.server.services.services { 166 modules[name] = "1.0" 167 } 168 return modules 169 } 170 171 // PeerInfo contains information about the remote end of the network connection. 172 // 173 // This is available within RPC method handlers through the context. Call 174 // PeerInfoFromContext to get information about the client connection related to 175 // the current method call. 176 type PeerInfo struct { 177 // Transport is name of the protocol used by the client. 178 // This can be "http", "ws" or "ipc". 179 Transport string 180 181 // Address of client. This will usually contain the IP address and port. 182 RemoteAddr string 183 184 // Additional information for HTTP and WebSocket connections. 185 HTTP struct { 186 // Protocol version, i.e. "HTTP/1.1". This is not set for WebSocket. 187 Version string 188 // Header values sent by the client. 189 UserAgent string 190 Origin string 191 Host string 192 } 193 } 194 195 type peerInfoContextKey struct{} 196 197 // PeerInfoFromContext returns information about the client's network connection. 198 // Use this with the context passed to RPC method handler functions. 199 // 200 // The zero value is returned if no connection info is present in ctx. 201 func PeerInfoFromContext(ctx context.Context) PeerInfo { 202 info, _ := ctx.Value(peerInfoContextKey{}).(PeerInfo) 203 return info 204 }