github.com/netdata/go.d.plugin@v0.58.1/modules/energid/collect.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package energid
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  
    12  	"github.com/netdata/go.d.plugin/pkg/stm"
    13  	"github.com/netdata/go.d.plugin/pkg/web"
    14  )
    15  
    16  const (
    17  	jsonRPCVersion = "1.1"
    18  
    19  	methodGetBlockchainInfo = "getblockchaininfo"
    20  	methodGetMemPoolInfo    = "getmempoolinfo"
    21  	methodGetNetworkInfo    = "getnetworkinfo"
    22  	methodGetTXOutSetInfo   = "gettxoutsetinfo"
    23  	methodGetMemoryInfo     = "getmemoryinfo"
    24  )
    25  
    26  var infoRequests = rpcRequests{
    27  	{JSONRPC: jsonRPCVersion, ID: 1, Method: methodGetBlockchainInfo},
    28  	{JSONRPC: jsonRPCVersion, ID: 2, Method: methodGetMemPoolInfo},
    29  	{JSONRPC: jsonRPCVersion, ID: 3, Method: methodGetNetworkInfo},
    30  	{JSONRPC: jsonRPCVersion, ID: 4, Method: methodGetTXOutSetInfo},
    31  	{JSONRPC: jsonRPCVersion, ID: 5, Method: methodGetMemoryInfo},
    32  }
    33  
    34  func (e *Energid) collect() (map[string]int64, error) {
    35  	responses, err := e.scrapeEnergid(infoRequests)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	info, err := e.collectInfoResponse(infoRequests, responses)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	return stm.ToMap(info), nil
    46  }
    47  
    48  func (e *Energid) collectInfoResponse(requests rpcRequests, responses rpcResponses) (*energidInfo, error) {
    49  	var info energidInfo
    50  	for _, req := range requests {
    51  		resp := responses.getByID(req.ID)
    52  		if resp == nil {
    53  			e.Warningf("method '%s' (id %d) not in responses", req.Method, req.ID)
    54  			continue
    55  		}
    56  
    57  		if resp.Error != nil {
    58  			e.Warningf("server returned an error on method '%s': %v", req.Method, resp.Error)
    59  			continue
    60  		}
    61  
    62  		var err error
    63  		switch req.Method {
    64  		case methodGetBlockchainInfo:
    65  			info.Blockchain, err = parseBlockchainInfo(resp.Result)
    66  		case methodGetMemPoolInfo:
    67  			info.MemPool, err = parseMemPoolInfo(resp.Result)
    68  		case methodGetNetworkInfo:
    69  			info.Network, err = parseNetworkInfo(resp.Result)
    70  		case methodGetTXOutSetInfo:
    71  			info.TxOutSet, err = parseTXOutSetInfo(resp.Result)
    72  		case methodGetMemoryInfo:
    73  			info.Memory, err = parseMemoryInfo(resp.Result)
    74  		}
    75  		if err != nil {
    76  			return nil, fmt.Errorf("parse '%s' method result: %v", req.Method, err)
    77  		}
    78  	}
    79  
    80  	return &info, nil
    81  }
    82  
    83  func parseBlockchainInfo(result []byte) (*blockchainInfo, error) {
    84  	var m blockchainInfo
    85  	if err := json.Unmarshal(result, &m); err != nil {
    86  		return nil, err
    87  	}
    88  	return &m, nil
    89  }
    90  
    91  func parseMemPoolInfo(result []byte) (*memPoolInfo, error) {
    92  	var m memPoolInfo
    93  	if err := json.Unmarshal(result, &m); err != nil {
    94  		return nil, err
    95  	}
    96  	return &m, nil
    97  }
    98  
    99  func parseNetworkInfo(result []byte) (*networkInfo, error) {
   100  	var m networkInfo
   101  	if err := json.Unmarshal(result, &m); err != nil {
   102  		return nil, err
   103  	}
   104  	return &m, nil
   105  }
   106  
   107  func parseTXOutSetInfo(result []byte) (*txOutSetInfo, error) {
   108  	var m txOutSetInfo
   109  	if err := json.Unmarshal(result, &m); err != nil {
   110  		return nil, err
   111  	}
   112  	return &m, nil
   113  }
   114  
   115  func parseMemoryInfo(result []byte) (*memoryInfo, error) {
   116  	var m memoryInfo
   117  	if err := json.Unmarshal(result, &m); err != nil {
   118  		return nil, err
   119  	}
   120  	return &m, nil
   121  }
   122  
   123  func (e *Energid) scrapeEnergid(requests rpcRequests) (rpcResponses, error) {
   124  	req, _ := web.NewHTTPRequest(e.Request)
   125  	req.Method = http.MethodPost
   126  	req.Header.Set("Content-Type", "application/json")
   127  	body, _ := json.Marshal(requests)
   128  	req.Body = io.NopCloser(bytes.NewReader(body))
   129  
   130  	var resp rpcResponses
   131  	if err := e.doOKDecode(req, &resp); err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	return resp, nil
   136  }
   137  
   138  func (e *Energid) doOKDecode(req *http.Request, in interface{}) error {
   139  	resp, err := e.httpClient.Do(req)
   140  	if err != nil {
   141  		return fmt.Errorf("error on HTTP request '%s': %v", req.URL, err)
   142  	}
   143  	defer closeBody(resp)
   144  
   145  	if resp.StatusCode != http.StatusOK {
   146  		return fmt.Errorf("'%s' returned HTTP status code: %d", req.URL, resp.StatusCode)
   147  	}
   148  
   149  	if err := json.NewDecoder(resp.Body).Decode(in); err != nil {
   150  		return fmt.Errorf("error on decoding response from '%s': %v", req.URL, err)
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  func closeBody(resp *http.Response) {
   157  	if resp != nil && resp.Body != nil {
   158  		_, _ = io.Copy(io.Discard, resp.Body)
   159  		_ = resp.Body.Close()
   160  	}
   161  }