309 lines
8.5 KiB
Go
309 lines
8.5 KiB
Go
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
|
||
}
|