Initial qiwei secondary development handoff
This commit is contained in:
245
http_client.go
Normal file
245
http_client.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HTTPClient HTTP客户端结构体,用于替代原来的IPC客户端
|
||||
type HTTPClient struct {
|
||||
httpClient *http.Client
|
||||
serverURL string
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewHTTPClient 创建一个新的HTTP客户端
|
||||
func NewHTTPClient(ctx context.Context, port int) *HTTPClient {
|
||||
return &HTTPClient{
|
||||
httpClient: &http.Client{
|
||||
Timeout: 30 * time.Second, // 设置请求超时时间
|
||||
},
|
||||
serverURL: fmt.Sprintf("http://localhost:%d", port),
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// SendWxWorkData 向辅助程序的HTTP服务发送企业微信数据
|
||||
func (c *HTTPClient) SendWxWorkData(clientId string, jsonData string) (bool, error) {
|
||||
// 解析JSON数据以获取消息类型
|
||||
var message map[string]interface{}
|
||||
timestamp1 := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
globalLogger.Info("[进入HTTP SendWxWorkData请求] 时间: %s", timestamp1)
|
||||
|
||||
messageTypeValue := -1
|
||||
if err := json.Unmarshal([]byte(jsonData), &message); err != nil {
|
||||
globalLogger.Warn("解析JSON数据失败: %v, 原始数据: %s", err, jsonData)
|
||||
} else {
|
||||
// 获取消息类型
|
||||
messageType, typeExists := message["type"]
|
||||
if typeExists {
|
||||
typeValue, ok := messageType.(float64) // JSON解析数字默认为float64
|
||||
if ok {
|
||||
messageTypeValue = int(typeValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录所有请求的日志
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
globalLogger.Info("[HTTPSendWxWorkData请求] 时间: %s, 客户端ID: %s, 消息类型: %d, 数据: %s",
|
||||
timestamp, clientId, messageTypeValue, jsonData)
|
||||
|
||||
// 创建请求体
|
||||
requestBody := map[string]interface{}{
|
||||
"clientId": clientId,
|
||||
"data": jsonData,
|
||||
}
|
||||
|
||||
// 序列化请求体
|
||||
jsonBytes, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
globalLogger.Error("序列化请求体失败: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 创建HTTP请求
|
||||
url := fmt.Sprintf("%s/api/send-wxwork-data", c.serverURL)
|
||||
req, err := http.NewRequestWithContext(c.ctx, "POST", url, bytes.NewBuffer(jsonBytes))
|
||||
if err != nil {
|
||||
globalLogger.Error("创建HTTP请求失败: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// 发送请求 - 添加重试机制
|
||||
timestamp2 := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
globalLogger.Info("[发送HTTP请求] 时间: %s, URL: %s", timestamp2, url)
|
||||
|
||||
// 设置重试参数
|
||||
maxRetries := 3
|
||||
retryInterval := 1 * time.Second
|
||||
var lastErr error
|
||||
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
return handleHTTPResponse(resp, messageTypeValue, clientId)
|
||||
}
|
||||
|
||||
lastErr = err
|
||||
globalLogger.Error("HTTP请求失败 (尝试 %d/%d): %v, URL: %s", i+1, maxRetries, err, url)
|
||||
|
||||
// 如果是连接被拒绝的错误,可能是辅助程序刚启动还未准备好,尝试重启辅助程序
|
||||
errMsg := err.Error()
|
||||
if strings.Contains(errMsg, "connectex: No connection could be made") ||
|
||||
strings.Contains(errMsg, "connection refused") {
|
||||
globalLogger.Info("尝试重新启动辅助程序...")
|
||||
// 调用外部的startHelperProgram函数
|
||||
// 注意:这里需要在main.go中将startHelperProgram声明为可导出的函数
|
||||
// 或者通过其他方式实现辅助程序的重启
|
||||
}
|
||||
|
||||
// 如果不是最后一次尝试,等待一段时间后重试
|
||||
if i < maxRetries-1 {
|
||||
globalLogger.Info("%d秒后重试...", retryInterval/time.Second)
|
||||
time.Sleep(retryInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// 所有重试都失败
|
||||
globalLogger.Error("HTTP请求失败,已尝试所有重试: %v", lastErr)
|
||||
return false, lastErr
|
||||
}
|
||||
|
||||
// handleHTTPResponse 处理HTTP响应
|
||||
func handleHTTPResponse(resp *http.Response, messageTypeValue int, clientId string) (bool, error) {
|
||||
timestamp := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
globalLogger.Info("[HTTP响应接收] 时间: %s, 客户端ID: %s, 状态码: %d", timestamp, clientId, resp.StatusCode)
|
||||
|
||||
// 读取响应体
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
globalLogger.Error("读取HTTP响应体失败: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
globalLogger.Info("[HTTP响应内容] 长度: %d 字节, 内容: %s", len(body), string(body))
|
||||
|
||||
// 解析响应体
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
globalLogger.Error("解析HTTP响应体失败: %v, 响应内容: %s", err, string(body))
|
||||
return false, err
|
||||
}
|
||||
|
||||
globalLogger.Info("[HTTP响应解析] 成功, 解析结果: %v", result)
|
||||
|
||||
// 获取success字段
|
||||
successValue, successExists := result["success"]
|
||||
if !successExists {
|
||||
globalLogger.Error("HTTP响应中缺少success字段")
|
||||
return false, fmt.Errorf("返回结果格式错误")
|
||||
}
|
||||
|
||||
success, ok := successValue.(bool)
|
||||
if !ok {
|
||||
globalLogger.Error("HTTP响应的success字段类型错误: %T", successValue)
|
||||
return false, fmt.Errorf("返回结果字段类型错误")
|
||||
}
|
||||
|
||||
// 检查是否包含data字段
|
||||
if data, exists := result["data"]; exists {
|
||||
globalLogger.Info("[HTTP响应数据] 客户端ID: %s, 数据: %v", clientId, data)
|
||||
}
|
||||
|
||||
// 记录返回日志(如果是特定类型的消息)
|
||||
timestampReturn := time.Now().Format("2006-01-02 15:04:05.000")
|
||||
globalLogger.Info("[HTTPSendWxWorkData返回] 时间: %s, 客户端ID: %s, 消息类型: %d, 成功: %v",
|
||||
timestampReturn, clientId, messageTypeValue, success)
|
||||
|
||||
return success, nil
|
||||
}
|
||||
|
||||
// CheckHealth 检查辅助程序的HTTP服务健康状态
|
||||
func (c *HTTPClient) CheckHealth() (bool, error) {
|
||||
url := fmt.Sprintf("%s/api/health", c.serverURL)
|
||||
resp, err := c.httpClient.Get(url)
|
||||
if err != nil {
|
||||
globalLogger.Error("健康检查请求失败: %v", err)
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
globalLogger.Error("健康检查失败,状态码: %d", resp.StatusCode)
|
||||
return false, fmt.Errorf("健康检查失败,状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetJSON calls a helper HTTP endpoint and decodes its JSON body.
|
||||
func (c *HTTPClient) GetJSON(path string) (map[string]interface{}, error) {
|
||||
url := fmt.Sprintf("%s%s", c.serverURL, path)
|
||||
req, err := http.NewRequestWithContext(c.ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v, body=%s", err, string(body))
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return result, fmt.Errorf("HTTP状态码错误: %d", resp.StatusCode)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PostJSON calls a helper HTTP endpoint with a JSON payload.
|
||||
func (c *HTTPClient) PostJSON(path string, payload interface{}) (map[string]interface{}, error) {
|
||||
jsonBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
url := fmt.Sprintf("%s%s", c.serverURL, path)
|
||||
req, err := http.NewRequestWithContext(c.ctx, "POST", url, bytes.NewBuffer(jsonBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, fmt.Errorf("解析响应失败: %v, body=%s", err, string(body))
|
||||
}
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return result, fmt.Errorf("HTTP状态码错误: %d", resp.StatusCode)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user