github.com/aquanetwork/aquachain@v1.7.8/node/api.go (about) 1 // Copyright 2015 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain 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 aquachain 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 aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "context" 21 "fmt" 22 "strings" 23 "time" 24 25 "gitlab.com/aquachain/aquachain/common/hexutil" 26 "gitlab.com/aquachain/aquachain/common/metrics" 27 "gitlab.com/aquachain/aquachain/crypto" 28 "gitlab.com/aquachain/aquachain/p2p" 29 "gitlab.com/aquachain/aquachain/p2p/discover" 30 "gitlab.com/aquachain/aquachain/rpc" 31 ) 32 33 // PrivateAdminAPI is the collection of administrative API methods exposed only 34 // over a secure RPC channel. 35 type PrivateAdminAPI struct { 36 node *Node // Node interfaced by this API 37 } 38 39 // NewPrivateAdminAPI creates a new API definition for the private admin methods 40 // of the node itself. 41 func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI { 42 return &PrivateAdminAPI{node: node} 43 } 44 45 // AddPeer requests connecting to a remote node, and also maintaining the new 46 // connection at all times, even reconnecting if it is lost. 47 func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { 48 // Make sure the server is running, fail otherwise 49 server := api.node.Server() 50 if server == nil { 51 return false, ErrNodeStopped 52 } 53 // Try to add the url as a static peer and return 54 node, err := discover.ParseNode(url) 55 if err != nil { 56 return false, fmt.Errorf("invalid enode: %v", err) 57 } 58 server.AddPeer(node) 59 return true, nil 60 } 61 62 // RemovePeer disconnects from a a remote node if the connection exists 63 func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { 64 // Make sure the server is running, fail otherwise 65 server := api.node.Server() 66 if server == nil { 67 return false, ErrNodeStopped 68 } 69 // Try to remove the url as a static peer and return 70 node, err := discover.ParseNode(url) 71 if err != nil { 72 return false, fmt.Errorf("invalid enode: %v", err) 73 } 74 server.RemovePeer(node) 75 return true, nil 76 } 77 78 // PeerEvents creates an RPC subscription which receives peer events from the 79 // node's p2p.Server 80 func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { 81 // Make sure the server is running, fail otherwise 82 server := api.node.Server() 83 if server == nil { 84 return nil, ErrNodeStopped 85 } 86 87 // Create the subscription 88 notifier, supported := rpc.NotifierFromContext(ctx) 89 if !supported { 90 return nil, rpc.ErrNotificationsUnsupported 91 } 92 rpcSub := notifier.CreateSubscription() 93 94 go func() { 95 events := make(chan *p2p.PeerEvent) 96 sub := server.SubscribeEvents(events) 97 defer sub.Unsubscribe() 98 99 for { 100 select { 101 case event := <-events: 102 notifier.Notify(rpcSub.ID, event) 103 case <-sub.Err(): 104 return 105 case <-rpcSub.Err(): 106 return 107 case <-notifier.Closed(): 108 return 109 } 110 } 111 }() 112 113 return rpcSub, nil 114 } 115 116 // StartRPC starts the HTTP RPC API server. 117 func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { 118 api.node.lock.Lock() 119 defer api.node.lock.Unlock() 120 121 if api.node.httpHandler != nil { 122 return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint) 123 } 124 125 if host == nil { 126 h := DefaultHTTPHost 127 if api.node.config.HTTPHost != "" { 128 h = api.node.config.HTTPHost 129 } 130 host = &h 131 } 132 if port == nil { 133 port = &api.node.config.HTTPPort 134 } 135 136 allowedOrigins := api.node.config.HTTPCors 137 if cors != nil { 138 allowedOrigins = nil 139 for _, origin := range strings.Split(*cors, ",") { 140 allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin)) 141 } 142 } 143 144 allowedVHosts := api.node.config.HTTPVirtualHosts 145 if vhosts != nil { 146 allowedVHosts = nil 147 for _, vhost := range strings.Split(*host, ",") { 148 allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost)) 149 } 150 } 151 152 allowedIPs := api.node.config.RPCAllowIP 153 modules := api.node.httpWhitelist 154 if apis != nil { 155 modules = nil 156 for _, m := range strings.Split(*apis, ",") { 157 modules = append(modules, strings.TrimSpace(m)) 158 } 159 } 160 161 if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, allowedIPs); err != nil { 162 return false, err 163 } 164 return true, nil 165 } 166 167 // StopRPC terminates an already running HTTP RPC API endpoint. 168 func (api *PrivateAdminAPI) StopRPC() (bool, error) { 169 api.node.lock.Lock() 170 defer api.node.lock.Unlock() 171 172 if api.node.httpHandler == nil { 173 return false, fmt.Errorf("HTTP RPC not running") 174 } 175 api.node.stopHTTP() 176 return true, nil 177 } 178 179 // StartWS starts the websocket RPC API server. 180 func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { 181 api.node.lock.Lock() 182 defer api.node.lock.Unlock() 183 184 if api.node.wsHandler != nil { 185 return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint) 186 } 187 188 if host == nil { 189 h := DefaultWSHost 190 if api.node.config.WSHost != "" { 191 h = api.node.config.WSHost 192 } 193 host = &h 194 } 195 if port == nil { 196 port = &api.node.config.WSPort 197 } 198 199 origins := api.node.config.WSOrigins 200 if allowedOrigins != nil { 201 origins = nil 202 for _, origin := range strings.Split(*allowedOrigins, ",") { 203 origins = append(origins, strings.TrimSpace(origin)) 204 } 205 } 206 207 modules := api.node.config.WSModules 208 if apis != nil { 209 modules = nil 210 for _, m := range strings.Split(*apis, ",") { 211 modules = append(modules, strings.TrimSpace(m)) 212 } 213 } 214 215 if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll, api.node.config.RPCAllowIP); err != nil { 216 return false, err 217 } 218 return true, nil 219 } 220 221 // StopRPC terminates an already running websocket RPC API endpoint. 222 func (api *PrivateAdminAPI) StopWS() (bool, error) { 223 api.node.lock.Lock() 224 defer api.node.lock.Unlock() 225 226 if api.node.wsHandler == nil { 227 return false, fmt.Errorf("WebSocket RPC not running") 228 } 229 api.node.stopWS() 230 return true, nil 231 } 232 233 // PublicAdminAPI is the collection of administrative API methods exposed over 234 // both secure and unsecure RPC channels. 235 type PublicAdminAPI struct { 236 node *Node // Node interfaced by this API 237 } 238 239 // NewPublicAdminAPI creates a new API definition for the public admin methods 240 // of the node itself. 241 func NewPublicAdminAPI(node *Node) *PublicAdminAPI { 242 return &PublicAdminAPI{node: node} 243 } 244 245 // Peers retrieves all the information we know about each individual peer at the 246 // protocol granularity. 247 func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { 248 server := api.node.Server() 249 if server == nil { 250 return nil, ErrNodeStopped 251 } 252 return server.PeersInfo(), nil 253 } 254 255 // NodeInfo retrieves all the information we know about the host node at the 256 // protocol granularity. 257 func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { 258 server := api.node.Server() 259 if server == nil { 260 return nil, ErrNodeStopped 261 } 262 return server.NodeInfo(), nil 263 } 264 265 // Datadir retrieves the current data directory the node is using. 266 func (api *PublicAdminAPI) Datadir() string { 267 return api.node.DataDir() 268 } 269 270 // PublicDebugAPI is the collection of debugging related API methods exposed over 271 // both secure and unsecure RPC channels. 272 type PublicDebugAPI struct { 273 node *Node // Node interfaced by this API 274 } 275 276 // NewPublicDebugAPI creates a new API definition for the public debug methods 277 // of the node itself. 278 func NewPublicDebugAPI(node *Node) *PublicDebugAPI { 279 return &PublicDebugAPI{node: node} 280 } 281 282 // Metrics retrieves all the known system metric collected by the node. 283 func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { 284 // Create a rate formatter 285 units := []string{"", "K", "M", "G", "T", "E", "P"} 286 round := func(value float64, prec int) string { 287 unit := 0 288 for value >= 1000 { 289 unit, value, prec = unit+1, value/1000, 2 290 } 291 return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) 292 } 293 format := func(total float64, rate float64) string { 294 return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) 295 } 296 // Iterate over all the metrics, and just dump for now 297 counters := make(map[string]interface{}) 298 metrics.DefaultRegistry.Each(func(name string, metric interface{}) { 299 // Create or retrieve the counter hierarchy for this metric 300 root, parts := counters, strings.Split(name, "/") 301 for _, part := range parts[:len(parts)-1] { 302 if _, ok := root[part]; !ok { 303 root[part] = make(map[string]interface{}) 304 } 305 root = root[part].(map[string]interface{}) 306 } 307 name = parts[len(parts)-1] 308 309 // Fill the counter with the metric details, formatting if requested 310 if raw { 311 switch metric := metric.(type) { 312 case metrics.Meter: 313 root[name] = map[string]interface{}{ 314 "AvgRate01Min": metric.Rate1(), 315 "AvgRate05Min": metric.Rate5(), 316 "AvgRate15Min": metric.Rate15(), 317 "MeanRate": metric.RateMean(), 318 "Overall": float64(metric.Count()), 319 } 320 321 case metrics.Timer: 322 root[name] = map[string]interface{}{ 323 "AvgRate01Min": metric.Rate1(), 324 "AvgRate05Min": metric.Rate5(), 325 "AvgRate15Min": metric.Rate15(), 326 "MeanRate": metric.RateMean(), 327 "Overall": float64(metric.Count()), 328 "Percentiles": map[string]interface{}{ 329 "5": metric.Percentile(0.05), 330 "20": metric.Percentile(0.2), 331 "50": metric.Percentile(0.5), 332 "80": metric.Percentile(0.8), 333 "95": metric.Percentile(0.95), 334 }, 335 } 336 337 default: 338 root[name] = "Unknown metric type" 339 } 340 } else { 341 switch metric := metric.(type) { 342 case metrics.Meter: 343 root[name] = map[string]interface{}{ 344 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 345 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 346 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 347 "Overall": format(float64(metric.Count()), metric.RateMean()), 348 } 349 350 case metrics.Timer: 351 root[name] = map[string]interface{}{ 352 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 353 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 354 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 355 "Overall": format(float64(metric.Count()), metric.RateMean()), 356 "Maximum": time.Duration(metric.Max()).String(), 357 "Minimum": time.Duration(metric.Min()).String(), 358 "Percentiles": map[string]interface{}{ 359 "5": time.Duration(metric.Percentile(0.05)).String(), 360 "20": time.Duration(metric.Percentile(0.2)).String(), 361 "50": time.Duration(metric.Percentile(0.5)).String(), 362 "80": time.Duration(metric.Percentile(0.8)).String(), 363 "95": time.Duration(metric.Percentile(0.95)).String(), 364 }, 365 } 366 367 default: 368 root[name] = "Unknown metric type" 369 } 370 } 371 }) 372 return counters, nil 373 } 374 375 // PublicWeb3API offers helper utils 376 type PublicWeb3API struct { 377 stack *Node 378 } 379 380 // NewPublicWeb3API creates a new Web3Service instance 381 func NewPublicWeb3API(stack *Node) *PublicWeb3API { 382 return &PublicWeb3API{stack} 383 } 384 385 // ClientVersion returns the node name 386 func (s *PublicWeb3API) ClientVersion() string { 387 if s.stack == nil || s.stack.Server() == nil { 388 return "shutting down" 389 } 390 return s.stack.Server().Name 391 } 392 393 // Sha3 applies the aquachain sha3 implementation on the input. 394 // It assumes the input is hex encoded. 395 func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { 396 return crypto.Keccak256(input) 397 }