rpc.go (3820B)
1 package rpc 2 3 4 import ( 5 "bytes" 6 "encoding/json" 7 "fmt" 8 "io" 9 "log" 10 "net/http" 11 "net/url" 12 "strconv" 13 "strings" 14 ) 15 16 type jsonRpcMsg struct { 17 Method string 18 } 19 20 type jsonRpcMsgFull struct { 21 Method string 22 Id any 23 Params []any 24 } 25 26 type JsonRpcError struct { 27 Code int `json:"code"` 28 Message string `json:"message"` 29 } 30 31 type JsonRpcResponse struct { 32 Id any `json:"id"` 33 Error JsonRpcError `json:"error"` 34 } 35 36 type jsonRpcResponseFull struct { 37 Jsonrpc string `json:"jsonrpc"` 38 Id any `json:"id"` 39 Result any `json:"result"` 40 } 41 42 type ProxyServer struct { 43 Server http.Handler 44 uri *url.URL 45 } 46 47 type proxyWriter struct { 48 Status int 49 header map[string][]string 50 data *bytes.Buffer 51 afterHeader bool 52 } 53 54 55 func (p *proxyWriter) Header() http.Header { 56 return p.header 57 } 58 59 func (p *proxyWriter) Write(b []byte) (int, error) { 60 log.Printf("proxyserver %s", b) 61 return p.data.Write(b) 62 } 63 64 func (p *proxyWriter) WriteHeader(status int) { 65 p.Status = status 66 p.header["Status"] = []string{fmt.Sprintf("%d", status)} 67 } 68 69 func (p *proxyWriter) Copy(w http.ResponseWriter) (int, error) { 70 c := 0 71 l := p.data.Len() 72 b := p.data.Bytes() 73 for ;c < l; { 74 r, err := w.Write(b[c:]) 75 if err != nil { 76 return 0, err 77 } 78 c += r 79 } 80 return c, nil 81 } 82 83 func newProxyWriter() *proxyWriter { 84 b := make([]byte, 0, 1024) 85 p := &proxyWriter{ 86 header: make(map[string][]string), 87 data: bytes.NewBuffer(b), 88 } 89 return p 90 } 91 92 func NewProxyServer(backend http.Handler, remoteURI string) (*ProxyServer, error) { 93 var uri *url.URL 94 var err error 95 96 if remoteURI != "" { 97 uri, err = url.Parse(remoteURI) 98 if err != nil { 99 return nil, err 100 } 101 } 102 srv := &ProxyServer{ 103 Server: backend, 104 uri: uri, 105 } 106 log.Printf("proxy server shadowing: %s", uri) 107 return srv, nil 108 } 109 110 func (s *ProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 111 msg := jsonRpcMsg{} 112 b := make([]byte, r.ContentLength) 113 c, err := io.ReadFull(r.Body, b) 114 if (err != nil) { 115 log.Printf("%s", err) 116 r.Body.Close() 117 w.WriteHeader(http.StatusInternalServerError) 118 return 119 } 120 r.Body.Close() 121 err = json.Unmarshal(b, &msg) 122 if (err != nil) { 123 log.Printf("%s", err) 124 r.Body.Close() 125 w.WriteHeader(http.StatusInternalServerError) 126 return 127 } 128 129 rr := bytes.NewReader(b) 130 r.Body = io.NopCloser(rr) 131 132 for _, k := range([]string{ 133 "eth_getTransactionByHash", 134 "eth_getTransactionReceipt", 135 "eth_getBlockByNumber", 136 "eth_getBlockByHash", 137 }) { 138 rw := newProxyWriter() 139 if msg.Method == k { 140 log.Printf("proxy match method %s %s", k, msg.Method) 141 s.Server.ServeHTTP(rw, r) 142 hd := rw.Header() 143 parts := strings.SplitN(hd["Status"][0], " ", 1) 144 status, err := strconv.ParseInt(parts[0], 10, 16) 145 if (err != nil) { 146 r.Body.Close() 147 w.WriteHeader(http.StatusInternalServerError) 148 return 149 } 150 if status < 300 && status >= 200 { 151 rsp := JsonRpcResponse{ 152 Error: JsonRpcError{}, 153 } 154 err = json.Unmarshal(b, &rsp) 155 if (err != nil) { 156 r.Body.Close() 157 w.WriteHeader(http.StatusInternalServerError) 158 return 159 } 160 if rsp.Error.Code == 0 { 161 rw.WriteHeader(http.StatusOK) 162 rw.Copy(w) 163 return 164 } 165 } 166 167 log.Printf("not found in proxy: %s", k) 168 rr.Seek(0, io.SeekStart) 169 } 170 } 171 172 if s.uri == nil { 173 log.Printf("missing remote side for unproxied method: %s", msg.Method) 174 w.WriteHeader(http.StatusBadGateway) 175 return 176 } 177 178 client_req := &http.Request{} 179 client_req.Method = "POST" 180 client_req.URL = s.uri 181 client_req.Body = r.Body 182 client_req.ContentLength = int64(c) 183 client := &http.Client{} 184 res, err := client.Do(client_req) 185 if err != nil { 186 log.Printf("%s", err) 187 r.Body.Close() 188 w.WriteHeader(http.StatusBadGateway) 189 return 190 } 191 if res.StatusCode != http.StatusOK { 192 v, _ := io.ReadAll(res.Body) 193 log.Printf("%s", v) 194 } 195 w.WriteHeader(res.StatusCode) 196 rrr := io.TeeReader(res.Body, w) 197 io.ReadAll(rrr) 198 } 199