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