新增Windows代理程序支持

This commit is contained in:
Alex Yang
2025-12-07 18:15:50 +08:00
parent ccc43fe70e
commit 2efe02682c
16 changed files with 4392 additions and 115 deletions

View File

@@ -511,6 +511,18 @@ func HandleMetricsPost(c *gin.Context) {
var globalStorage *storage.Storage
var deviceStorage device.Storage
// 硬件信息缓存结构
type hardwareCacheItem struct {
Data map[string]interface{}
ExpiresAt time.Time
}
// 硬件信息缓存
var (
hardwareCache sync.Map
cacheDuration = 5 * time.Minute // 缓存过期时间5分钟
)
// SetStorage 设置全局存储实例
func SetStorage(s *storage.Storage) {
globalStorage = s
@@ -1275,12 +1287,35 @@ func GetHardwareMetrics(c *gin.Context) {
return
}
// 从存储中查询硬件信息
hardwareInfo, err := globalStorage.QueryHardwareMetrics(context.Background(), deviceID)
// 尝试从缓存中获取硬件信息
var hardwareInfo map[string]interface{}
var err error
if cached, ok := hardwareCache.Load(deviceID); ok {
cacheItem := cached.(hardwareCacheItem)
if time.Now().Before(cacheItem.ExpiresAt) {
// 缓存有效
hardwareInfo = cacheItem.Data
} else {
// 缓存过期,删除并重新查询
hardwareCache.Delete(deviceID)
hardwareInfo, err = globalStorage.QueryHardwareMetrics(context.Background(), deviceID)
}
} else {
// 缓存未命中,查询数据库
hardwareInfo, err = globalStorage.QueryHardwareMetrics(context.Background(), deviceID)
}
if err != nil {
log.Printf("Warning: Failed to query hardware metrics: %v", err)
// 查询失败时,返回一个空的硬件信息对象
hardwareInfo = make(map[string]interface{})
} else if len(hardwareInfo) > 0 {
// 查询成功且有数据,更新缓存
hardwareCache.Store(deviceID, hardwareCacheItem{
Data: hardwareInfo,
ExpiresAt: time.Now().Add(cacheDuration),
})
}
// 为了确保返回的结构与前端期望的一致,我们需要将查询结果转换为期望的格式

View File

@@ -484,18 +484,19 @@ func (s *Storage) QueryHardwareMetrics(ctx context.Context, deviceID string) (ma
if hardwareType == "os" || hardwareType == "cpu" || hardwareType == "memory" {
// 对于os、cpu、memory类型我们只需要一个结果
query = `from(bucket: "` + s.bucket + `")
|> range(start: -24h)
|> filter(fn: (r) => r["_measurement"] == "hardware")
|> filter(fn: (r) => r["device_id"] == "` + deviceID + `")
|> filter(fn: (r) => r["type"] == "` + hardwareType + `")
|> last()`
|> range(start: -24h) // 扩大查询范围到最近24小时
|> filter(fn: (r) => r["_measurement"] == "hardware")
|> filter(fn: (r) => r["device_id"] == "` + deviceID + `")
|> filter(fn: (r) => r["type"] == "` + hardwareType + `")
|> last()`
} else {
// 对于disk和network类型我们需要获取所有设备的所有字段记录
// 对于disk和network类型我们需要获取所有设备的最新完整记录
// 先获取所有记录,然后按时间排序,最后只保留最新的记录
query = `from(bucket: "` + s.bucket + `")
|> range(start: -24h)
|> filter(fn: (r) => r["_measurement"] == "hardware")
|> filter(fn: (r) => r["device_id"] == "` + deviceID + `")
|> filter(fn: (r) => r["type"] == "` + hardwareType + `")`
|> range(start: -24h) // 扩大查询范围到最近24小时
|> filter(fn: (r) => r["_measurement"] == "hardware")
|> filter(fn: (r) => r["device_id"] == "` + deviceID + `")
|> filter(fn: (r) => r["type"] == "` + hardwareType + `")`
}
// 执行查询
@@ -517,7 +518,14 @@ func (s *Storage) QueryHardwareMetrics(ctx context.Context, deviceID string) (ma
record := queryResult.Record()
fieldName := record.Field()
fieldValue := record.Value()
fieldMap[fieldName] = fieldValue
// 处理布尔类型的值转换为字符串以避免InfluxDB客户端错误
switch v := fieldValue.(type) {
case bool:
fieldMap[fieldName] = fmt.Sprintf("%t", v)
default:
fieldMap[fieldName] = fieldValue
}
}
// 如果有字段数据,添加到硬件信息结果中
@@ -543,38 +551,53 @@ func (s *Storage) QueryHardwareMetrics(ctx context.Context, deviceID string) (ma
// 获取设备唯一标识
deviceKey := ""
// 优先使用id字段作为设备标识
if id, isString := fieldValue.(string); fieldName == "id" && isString {
deviceKey = id
// 首先从字段中查找id
if fieldName == "id" {
if id, isString := fieldValue.(string); isString {
deviceKey = id
} else if id, isFloat := fieldValue.(float64); isFloat {
deviceKey = fmt.Sprintf("%d", int(id))
}
// 创建设备字段映射
deviceFields[deviceKey] = make(map[string]interface{})
deviceFields[deviceKey]["id"] = id
} else {
// 否则,查找已存在的设备映射
// 遍历所有设备映射,查找当前记录对应的设备
for key, fields := range deviceFields {
// 如果设备映射中没有id字段或者id字段为空跳过
if id, ok := fields["id"].(string); ok && id != "" {
// 假设当前记录属于该设备
deviceKey = key
break
}
if deviceKey != "" {
deviceFields[deviceKey] = make(map[string]interface{})
deviceFields[deviceKey]["id"] = deviceKey
}
}
// 如果没有找到设备标识,使用index作为设备标识
// 如果没有通过id字段找到设备标识,尝试从index获取
if deviceKey == "" {
index := 0
if idx, ok := record.ValueByKey("index").(int); ok {
index = idx
if index, ok := record.ValueByKey("index").(int); ok {
deviceKey = fmt.Sprintf("%d", index)
// 创建设备字段映射
deviceFields[deviceKey] = make(map[string]interface{})
}
}
// 如果仍然没有设备标识,查找已存在的设备映射
if deviceKey == "" {
// 遍历所有设备映射,查找当前记录对应的设备
for key := range deviceFields {
deviceKey = key
break
}
// 如果没有找到任何设备映射,创建一个新的
if deviceKey == "" {
deviceKey = "0" // 默认使用0作为第一个设备的标识
deviceFields[deviceKey] = make(map[string]interface{})
}
deviceKey = fmt.Sprintf("%d", index)
// 创建设备字段映射
deviceFields[deviceKey] = make(map[string]interface{})
}
// 添加字段值到设备字段映射中
deviceFields[deviceKey][fieldName] = fieldValue
// 处理布尔类型的值转换为字符串以避免InfluxDB客户端错误
switch v := fieldValue.(type) {
case bool:
deviceFields[deviceKey][fieldName] = fmt.Sprintf("%t", v)
default:
deviceFields[deviceKey][fieldName] = fieldValue
}
}
// 将deviceFields转换为切片