m2pool_core/internal/gbt/alph/http/http.go

309 lines
8.5 KiB
Go
Raw Normal View History

2025-04-10 07:27:24 +00:00
package http
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
)
type HttpClient struct {
host string
port string
apiKey string
}
func NewHttpClient(host, port, apiKey string) *HttpClient {
return &HttpClient{
host: host,
port: port,
apiKey: apiKey,
}
}
func (client *HttpClient) parseJson(resp *http.Response, data []byte) (map[string]interface{}, error) {
// 尝试解析为 JSON 对象
var dataJson map[string]interface{}
if err := json.Unmarshal(data, &dataJson); err != nil {
// 如果解析为 JSON 对象失败,检查是否是布尔值
var booleanValue bool
if err := json.Unmarshal(data, &booleanValue); err == nil {
// 如果是布尔值,包装成一个 map 返回
return map[string]interface{}{"success": booleanValue}, nil
}
// 如果既不是 JSON 对象也不是布尔值,返回错误
return nil, fmt.Errorf("invalid JSON response: %s", string(data))
}
// 检查 HTTP 状态码
if resp.StatusCode != http.StatusOK {
errMessage, _ := dataJson["detail"].(string) // 如果没有 "detail",默认为空字符串
dataJson["statusCode"] = resp.StatusCode
dataJson["error"] = errMessage
return dataJson, fmt.Errorf("HTTP error: %d - %s", resp.StatusCode, errMessage)
}
return dataJson, nil
}
func (client *HttpClient) httpRequest(method, path string, headers map[string]string, requestData []byte) (map[string]interface{}, error) {
var url string
if client.port == "" {
url = "http://" + client.host + path
} else {
url = fmt.Sprintf("%s://%s:%s%s", "http", client.host, client.port, path)
}
req, err := http.NewRequest(method, url, bytes.NewBuffer(requestData))
if err != nil {
return nil, err
}
for key, value := range headers {
req.Header.Set(key, value)
}
clientResponse, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer clientResponse.Body.Close()
body, err := ioutil.ReadAll(clientResponse.Body)
if err != nil {
return nil, err
}
return client.parseJson(clientResponse, body)
}
func (client *HttpClient) Get(path string) (map[string]interface{}, error) {
headers := map[string]string{
"Accept": "application/json",
}
if client.apiKey != "" {
headers["X-API-KEY"] = client.apiKey
}
return client.httpRequest("GET", path, headers, nil)
}
func (client *HttpClient) Post(path string, data interface{}) (map[string]interface{}, error) {
headers := map[string]string{
"Content-Type": "application/json",
}
if client.apiKey != "" {
headers["X-API-KEY"] = client.apiKey
}
jsonData, err := json.Marshal(data)
if err != nil {
return nil, err
}
fmt.Println("POST 请求的数据:", string(jsonData))
response, err := client.httpRequest("POST", path, headers, jsonData)
if err != nil {
return nil, err
}
fmt.Println("POST 响应的数据:", response)
return response, nil
}
func (client *HttpClient) WalletStatus(walletName string) (map[string]interface{}, error) {
path := fmt.Sprintf("/wallets/%s", walletName)
return client.Get(path)
}
func (client *HttpClient) UnlockWallet(walletName, password, mnemonicPassphrase string) (map[string]interface{}, error) {
path := fmt.Sprintf("/wallets/%s/unlock", walletName)
data := map[string]string{"password": password}
if mnemonicPassphrase != "" {
data["mnemonicPassphrase"] = mnemonicPassphrase
}
return client.Post(path, data)
}
func (client *HttpClient) BuildUnsignedTx(fromPubKey string, destinations []interface{}) (map[string]interface{}, error) {
path := "/transactions/build"
data := map[string]interface{}{
"fromPublicKey": fromPubKey,
"destinations": destinations,
}
return client.Post(path, data)
}
func (client *HttpClient) SelfClique() (map[string]interface{}, error) {
path := "/infos/self-clique"
return client.Get(path)
}
func (client *HttpClient) GetBlockHash(fromGroup uint32, toGroup uint32, height uint32) (string, error) {
// 构建请求路径
path := fmt.Sprintf("/blockflow/hashes?fromGroup=%d&toGroup=%d&height=%d", fromGroup, toGroup, height)
// 调用客户端的 Get 方法
result, err := client.Get(path)
if err != nil {
fmt.Println("获取hash失败", err)
return "", err
}
// 断言 result 是 map[string]interface{}
data := result
// 获取 headers 字段并断言为 []interface{}
headers, ok := data["headers"].([]interface{})
if !ok {
fmt.Println("headers 字段格式不正确")
return "", errors.New("headers 字段格式不正确")
}
// 转换为字符串切片
var headerStrings []string
for _, header := range headers {
if str, ok := header.(string); ok {
headerStrings = append(headerStrings, str)
} else {
fmt.Println("headers 中存在非字符串类型数据")
return "", errors.New("headers 中存在非字符串类型数据")
}
}
// 如果只需要第一个字符串,返回它
if len(headerStrings) > 0 {
return headerStrings[0], nil
}
// 如果 headers 是空的,返回空字符串
return "", nil
}
func (client *HttpClient) CheckBlk(hash string) bool {
path := fmt.Sprintf("/blockflow/is-block-in-main-chain?blockHash=%s", hash)
result, err := client.Get(path)
if err != nil {
fmt.Println("获取hash失败", err)
return false
}
// 从返回结果中提取布尔值
if success, ok := result["success"].(bool); ok {
return success
}
// 如果结果不包含布尔值或格式不对
fmt.Println("返回的结果格式不正确:", result)
return false
}
type Block struct {
ChainFrom int `json:"chainFrom"`
ChainTo int `json:"chainTo"`
DepStateHash string `json:"depStateHash"`
Deps []string `json:"deps"`
GhostUncles interface{} `json:"ghostUncles"`
Hash string `json:"hash"`
Height int64 `json:"height"`
Nonce string `json:"nonce"`
Target string `json:"target"`
Timestamp float64 `json:"timestamp"`
Transactions []TxDetail `json:"transactions"`
TxsHash string `json:"txsHash"`
Version int `json:"version"`
}
type TxDetail struct {
Unsigned UnsignedTx `json:"unsigned"`
}
type UnsignedTx struct {
Inputs []Input `json:"inputs"`
FixedOutputs []FixedOutput `json:"fixedOutputs"`
}
type Input struct {
}
type FixedOutput struct {
Address string `json:"address"`
AttoAlphAmount string `json:"attoAlphAmount"`
Hint float64 `json:"hint"`
Key string `json:"key"`
LockTime int64 `json:"lockTime"`
}
func (client *HttpClient) GetBlcokInfo(hash string) Block {
path := fmt.Sprintf("/blockflow/blocks/%s", hash)
result, err := client.Get(path)
if err != nil {
fmt.Println("获取区块信息失败:", err)
return Block{}
} // 将 map[string]interface{} 转换为 JSON 字符串
jsonData, err := json.Marshal(result)
if err != nil {
fmt.Println("转换为 JSON 字符串失败:", err)
return Block{}
}
var blockInfo Block
err = json.Unmarshal(jsonData, &blockInfo)
if err != nil {
fmt.Println("解析失败:", err)
return Block{}
}
return blockInfo
}
// func (client *HttpClient) GetBlockCount(fromGroup uint32, toGroup uint32) (int, error) {
// }
func (client *HttpClient) ChangeActiveAddress(walletName string, address string) (map[string]interface{}, error) {
path := fmt.Sprintf("/wallets/%s/change-active-address", walletName)
data := map[string]interface{}{
"address": address,
}
return client.Post(path, data)
}
func (client *HttpClient) SignTx(walletName string, txId string) (map[string]interface{}, error) {
path := fmt.Sprintf("/wallets/%s/sign", walletName)
data := map[string]interface{}{
"data": txId,
}
return client.Post(path, data)
}
func (client *HttpClient) GetAddressInfo(walletName string, address string) (map[string]interface{}, error) {
path := fmt.Sprintf("/wallets/%s/addresses/%s", walletName, address)
return client.Get(path)
}
func (client *HttpClient) SweepActiveAddress(walletName string, toAddress string) (map[string]interface{}, error) {
path := fmt.Sprintf("/wallets/%s/sweep-active-address", walletName)
data := map[string]interface{}{
"toAddress": toAddress,
}
return client.Post(path, data)
}
func (client *HttpClient) CheckAccount(coin string, account string) bool {
path := "/api/pool/checkAccount"
data := map[string]interface{}{
"coin": coin,
"ma": account,
}
result, err := client.Post(path, data)
if err != nil {
fmt.Println("校验挖矿账号失败:", err)
return false
}
// 检查返回值中的 "success" 字段
success, ok := result["success"].(bool)
if !ok {
fmt.Println("响应格式错误或 success 字段不存在:", result)
return false
}
return success
}