github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/node/api.go (about) 1 package node 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "time" 8 9 "github.com/neatlab/neatio/network/p2p" 10 "github.com/neatlab/neatio/network/p2p/discover" 11 "github.com/neatlab/neatio/network/rpc" 12 "github.com/neatlab/neatio/utilities/common/hexutil" 13 "github.com/neatlab/neatio/utilities/crypto" 14 "github.com/neatlab/neatio/utilities/metrics" 15 ) 16 17 type PrivateAdminAPI struct { 18 node *Node 19 } 20 21 func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI { 22 return &PrivateAdminAPI{node: node} 23 } 24 25 func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { 26 27 server := api.node.Server() 28 if server == nil { 29 return false, ErrNodeStopped 30 } 31 32 node, err := discover.ParseNode(url) 33 if err != nil { 34 return false, fmt.Errorf("invalid enode: %v", err) 35 } 36 server.AddPeer(node) 37 return true, nil 38 } 39 40 func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { 41 42 server := api.node.Server() 43 if server == nil { 44 return false, ErrNodeStopped 45 } 46 47 node, err := discover.ParseNode(url) 48 if err != nil { 49 return false, fmt.Errorf("invalid enode: %v", err) 50 } 51 server.RemovePeer(node) 52 return true, nil 53 } 54 55 func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { 56 57 server := api.node.Server() 58 if server == nil { 59 return nil, ErrNodeStopped 60 } 61 62 notifier, supported := rpc.NotifierFromContext(ctx) 63 if !supported { 64 return nil, rpc.ErrNotificationsUnsupported 65 } 66 rpcSub := notifier.CreateSubscription() 67 68 go func() { 69 events := make(chan *p2p.PeerEvent) 70 sub := server.SubscribeEvents(events) 71 defer sub.Unsubscribe() 72 73 for { 74 select { 75 case event := <-events: 76 notifier.Notify(rpcSub.ID, event) 77 case <-sub.Err(): 78 return 79 case <-rpcSub.Err(): 80 return 81 case <-notifier.Closed(): 82 return 83 } 84 } 85 }() 86 87 return rpcSub, nil 88 } 89 90 func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { 91 api.node.lock.Lock() 92 defer api.node.lock.Unlock() 93 94 if api.node.httpHandler != nil { 95 return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint) 96 } 97 98 if host == nil { 99 h := DefaultHTTPHost 100 if api.node.config.HTTPHost != "" { 101 h = api.node.config.HTTPHost 102 } 103 host = &h 104 } 105 if port == nil { 106 port = &api.node.config.HTTPPort 107 } 108 109 allowedOrigins := api.node.config.HTTPCors 110 if cors != nil { 111 allowedOrigins = nil 112 for _, origin := range strings.Split(*cors, ",") { 113 allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin)) 114 } 115 } 116 117 allowedVHosts := api.node.config.HTTPVirtualHosts 118 if vhosts != nil { 119 allowedVHosts = nil 120 for _, vhost := range strings.Split(*host, ",") { 121 allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost)) 122 } 123 } 124 125 modules := api.node.httpWhitelist 126 if apis != nil { 127 modules = nil 128 for _, m := range strings.Split(*apis, ",") { 129 modules = append(modules, strings.TrimSpace(m)) 130 } 131 } 132 133 if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts); err != nil { 134 return false, err 135 } 136 return true, nil 137 } 138 139 func (api *PrivateAdminAPI) StopRPC() (bool, error) { 140 api.node.lock.Lock() 141 defer api.node.lock.Unlock() 142 143 if api.node.httpHandler == nil { 144 return false, fmt.Errorf("HTTP RPC not running") 145 } 146 api.node.stopHTTP() 147 return true, nil 148 } 149 150 func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { 151 api.node.lock.Lock() 152 defer api.node.lock.Unlock() 153 154 if api.node.wsHandler != nil { 155 return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint) 156 } 157 158 if host == nil { 159 h := DefaultWSHost 160 if api.node.config.WSHost != "" { 161 h = api.node.config.WSHost 162 } 163 host = &h 164 } 165 if port == nil { 166 port = &api.node.config.WSPort 167 } 168 169 origins := api.node.config.WSOrigins 170 if allowedOrigins != nil { 171 origins = nil 172 for _, origin := range strings.Split(*allowedOrigins, ",") { 173 origins = append(origins, strings.TrimSpace(origin)) 174 } 175 } 176 177 modules := api.node.config.WSModules 178 if apis != nil { 179 modules = nil 180 for _, m := range strings.Split(*apis, ",") { 181 modules = append(modules, strings.TrimSpace(m)) 182 } 183 } 184 185 if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil { 186 return false, err 187 } 188 return true, nil 189 } 190 191 func (api *PrivateAdminAPI) StopWS() (bool, error) { 192 api.node.lock.Lock() 193 defer api.node.lock.Unlock() 194 195 if api.node.wsHandler == nil { 196 return false, fmt.Errorf("WebSocket RPC not running") 197 } 198 api.node.stopWS() 199 return true, nil 200 } 201 202 type PublicAdminAPI struct { 203 node *Node 204 } 205 206 func NewPublicAdminAPI(node *Node) *PublicAdminAPI { 207 return &PublicAdminAPI{node: node} 208 } 209 210 func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { 211 server := api.node.Server() 212 if server == nil { 213 return nil, ErrNodeStopped 214 } 215 return server.PeersInfo(), nil 216 } 217 218 func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { 219 server := api.node.Server() 220 if server == nil { 221 return nil, ErrNodeStopped 222 } 223 return server.NodeInfo(), nil 224 } 225 226 func (api *PublicAdminAPI) Datadir() string { 227 return api.node.DataDir() 228 } 229 230 type PublicDebugAPI struct { 231 node *Node 232 } 233 234 func NewPublicDebugAPI(node *Node) *PublicDebugAPI { 235 return &PublicDebugAPI{node: node} 236 } 237 238 func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { 239 240 units := []string{"", "K", "M", "G", "T", "E", "P"} 241 round := func(value float64, prec int) string { 242 unit := 0 243 for value >= 1000 { 244 unit, value, prec = unit+1, value/1000, 2 245 } 246 return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) 247 } 248 format := func(total float64, rate float64) string { 249 return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) 250 } 251 252 counters := make(map[string]interface{}) 253 metrics.DefaultRegistry.Each(func(name string, metric interface{}) { 254 255 root, parts := counters, strings.Split(name, "/") 256 for _, part := range parts[:len(parts)-1] { 257 if _, ok := root[part]; !ok { 258 root[part] = make(map[string]interface{}) 259 } 260 root = root[part].(map[string]interface{}) 261 } 262 name = parts[len(parts)-1] 263 264 if raw { 265 switch metric := metric.(type) { 266 case metrics.Counter: 267 root[name] = map[string]interface{}{ 268 "Overall": float64(metric.Count()), 269 } 270 271 case metrics.Meter: 272 root[name] = map[string]interface{}{ 273 "AvgRate01Min": metric.Rate1(), 274 "AvgRate05Min": metric.Rate5(), 275 "AvgRate15Min": metric.Rate15(), 276 "MeanRate": metric.RateMean(), 277 "Overall": float64(metric.Count()), 278 } 279 280 case metrics.Timer: 281 root[name] = map[string]interface{}{ 282 "AvgRate01Min": metric.Rate1(), 283 "AvgRate05Min": metric.Rate5(), 284 "AvgRate15Min": metric.Rate15(), 285 "MeanRate": metric.RateMean(), 286 "Overall": float64(metric.Count()), 287 "Percentiles": map[string]interface{}{ 288 "5": metric.Percentile(0.05), 289 "20": metric.Percentile(0.2), 290 "50": metric.Percentile(0.5), 291 "80": metric.Percentile(0.8), 292 "95": metric.Percentile(0.95), 293 }, 294 } 295 296 default: 297 root[name] = "Unknown metric type" 298 } 299 } else { 300 switch metric := metric.(type) { 301 case metrics.Counter: 302 root[name] = map[string]interface{}{ 303 "Overall": float64(metric.Count()), 304 } 305 306 case metrics.Meter: 307 root[name] = map[string]interface{}{ 308 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 309 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 310 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 311 "Overall": format(float64(metric.Count()), metric.RateMean()), 312 } 313 314 case metrics.Timer: 315 root[name] = map[string]interface{}{ 316 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 317 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 318 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 319 "Overall": format(float64(metric.Count()), metric.RateMean()), 320 "Maximum": time.Duration(metric.Max()).String(), 321 "Minimum": time.Duration(metric.Min()).String(), 322 "Percentiles": map[string]interface{}{ 323 "5": time.Duration(metric.Percentile(0.05)).String(), 324 "20": time.Duration(metric.Percentile(0.2)).String(), 325 "50": time.Duration(metric.Percentile(0.5)).String(), 326 "80": time.Duration(metric.Percentile(0.8)).String(), 327 "95": time.Duration(metric.Percentile(0.95)).String(), 328 }, 329 } 330 331 default: 332 root[name] = "Unknown metric type" 333 } 334 } 335 }) 336 return counters, nil 337 } 338 339 type PublicWeb3API struct { 340 stack *Node 341 } 342 343 func NewPublicWeb3API(stack *Node) *PublicWeb3API { 344 return &PublicWeb3API{stack} 345 } 346 347 func (s *PublicWeb3API) ClientVersion() string { 348 return s.stack.Server().Name 349 } 350 351 func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { 352 return crypto.Keccak256(input) 353 }