gitlab.com/flarenetwork/coreth@v0.1.1/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 type contextWithDeadline struct { 64 context.Context 65 deadline time.Time 66 } 67 68 func (ctx contextWithDeadline) Deadline() (time.Time, bool) { 69 deadline, exists := ctx.Context.Deadline() 70 if !exists { 71 return ctx.deadline, true 72 } 73 if ctx.deadline.Before(deadline) { 74 return ctx.deadline, true 75 } 76 return deadline, true 77 } 78 79 // NewServer creates a new server instance with no registered handlers. 80 // 81 // If [maximumDuration] > 0, the deadline of incoming requests is 82 // [maximumDuration] in the future. Otherwise, no deadline is assigned to 83 // incoming requests. 84 func NewServer(maximumDuration time.Duration) *Server { 85 server := &Server{ 86 idgen: randomIDGenerator(), 87 codecs: mapset.NewSet(), 88 run: 1, 89 maximumDuration: maximumDuration, 90 } 91 // Register the default service providing meta information about the RPC service such 92 // as the services and methods it offers. 93 rpcService := &RPCService{server} 94 server.RegisterName(MetadataApi, rpcService) 95 return server 96 } 97 98 // RegisterName creates a service for the given receiver type under the given name. When no 99 // methods on the given receiver match the criteria to be either a RPC method or a 100 // subscription an error is returned. Otherwise a new service is created and added to the 101 // service collection this server provides to clients. 102 func (s *Server) RegisterName(name string, receiver interface{}) error { 103 return s.services.registerName(name, receiver) 104 } 105 106 // ServeCodec reads incoming requests from codec, calls the appropriate callback and writes 107 // the response back using the given codec. It will block until the codec is closed or the 108 // server is stopped. In either case the codec is closed. 109 // 110 // Note that codec options are no longer supported. 111 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption, apiMaxDuration time.Duration) { 112 defer codec.close() 113 114 // Don't serve if server is stopped. 115 if atomic.LoadInt32(&s.run) == 0 { 116 return 117 } 118 119 // Add the codec to the set so it can be closed by Stop. 120 s.codecs.Add(codec) 121 defer s.codecs.Remove(codec) 122 123 c := initClient(codec, s.idgen, &s.services, apiMaxDuration) 124 <-codec.closed() 125 c.Close() 126 } 127 128 // serveSingleRequest reads and processes a single RPC request from the given codec. This 129 // is used to serve HTTP connections. Subscriptions and reverse calls are not allowed in 130 // this mode. 131 func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { 132 // Don't serve if server is stopped. 133 if atomic.LoadInt32(&s.run) == 0 { 134 return 135 } 136 137 h := newHandler(ctx, codec, s.idgen, &s.services) 138 h.deadlineContext = s.maximumDuration 139 h.allowSubscribe = false 140 defer h.close(io.EOF, nil) 141 142 reqs, batch, err := codec.readBatch() 143 if err != nil { 144 if err != io.EOF { 145 codec.writeJSON(ctx, errorMessage(&invalidMessageError{"parse error"})) 146 } 147 return 148 } 149 if batch { 150 h.handleBatch(reqs) 151 } else { 152 h.handleMsg(reqs[0]) 153 } 154 } 155 156 // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending 157 // requests to finish, then closes all codecs which will cancel pending requests and 158 // subscriptions. 159 func (s *Server) Stop() { 160 if atomic.CompareAndSwapInt32(&s.run, 1, 0) { 161 log.Debug("RPC server shutting down") 162 s.codecs.Each(func(c interface{}) bool { 163 c.(ServerCodec).close() 164 return true 165 }) 166 } 167 } 168 169 // RPCService gives meta information about the server. 170 // e.g. gives information about the loaded modules. 171 type RPCService struct { 172 server *Server 173 } 174 175 // Modules returns the list of RPC services with their version number 176 func (s *RPCService) Modules() map[string]string { 177 s.server.services.mu.Lock() 178 defer s.server.services.mu.Unlock() 179 180 modules := make(map[string]string) 181 for name := range s.server.services.services { 182 modules[name] = "1.0" 183 } 184 return modules 185 }