fix: 调整一些bug
This commit is contained in:
parent
0ba3f638f4
commit
ceb83afff2
362
http_server.go
362
http_server.go
@ -1,168 +1,194 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 启动HTTP服务器
|
// 启动HTTP服务器
|
||||||
func StartHTTPServer(address string) error {
|
func StartHTTPServer(address string) error {
|
||||||
http.HandleFunc("/", handleIndex)
|
http.HandleFunc("/", handleIndex)
|
||||||
|
|
||||||
http.HandleFunc("/api/data", handleGetData)
|
http.HandleFunc("/api/data", handleGetData)
|
||||||
http.HandleFunc("/api/sensors", handleGetSensors)
|
http.HandleFunc("/api/sensors", handleGetSensors)
|
||||||
http.HandleFunc("/api/clients", handleGetClients)
|
http.HandleFunc("/api/clients", handleGetClients)
|
||||||
fmt.Printf("HTTP服务器已启动,正在监听 %s\n", address)
|
http.HandleFunc("/api/trigger-query", handleTriggerQuery)
|
||||||
return http.ListenAndServe(address, nil)
|
fmt.Printf("HTTP服务器已启动,正在监听 %s\n", address)
|
||||||
}
|
return http.ListenAndServe(address, nil)
|
||||||
|
}
|
||||||
// 处理主页
|
|
||||||
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
// 处理主页
|
||||||
log.Printf("接收到主页请求: %s", r.URL.Path)
|
func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("接收到主页请求: %s", r.URL.Path)
|
||||||
templatePath := "templates/index.html"
|
|
||||||
absPath, _ := filepath.Abs(templatePath)
|
templatePath := "templates/index.html"
|
||||||
|
absPath, _ := filepath.Abs(templatePath)
|
||||||
_, err := os.Stat(templatePath)
|
|
||||||
if os.IsNotExist(err) {
|
_, err := os.Stat(templatePath)
|
||||||
log.Printf("错误: 模板文件不存在: %s", absPath)
|
if os.IsNotExist(err) {
|
||||||
http.Error(w, "模板文件不存在", http.StatusInternalServerError)
|
log.Printf("错误: 模板文件不存在: %s", absPath)
|
||||||
return
|
http.Error(w, "模板文件不存在", http.StatusInternalServerError)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
tmpl, err := template.ParseFiles(templatePath)
|
|
||||||
if err != nil {
|
tmpl, err := template.ParseFiles(templatePath)
|
||||||
log.Printf("错误: 无法解析模板: %v", err)
|
if err != nil {
|
||||||
http.Error(w, "无法加载模板:"+err.Error(), http.StatusInternalServerError)
|
log.Printf("错误: 无法解析模板: %v", err)
|
||||||
return
|
http.Error(w, "无法加载模板:"+err.Error(), http.StatusInternalServerError)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
log.Printf("模板加载成功,开始渲染")
|
|
||||||
err = tmpl.Execute(w, nil)
|
log.Printf("模板加载成功,开始渲染")
|
||||||
if err != nil {
|
err = tmpl.Execute(w, nil)
|
||||||
log.Printf("错误: 渲染模板出错: %v", err)
|
if err != nil {
|
||||||
http.Error(w, "渲染模板出错:"+err.Error(), http.StatusInternalServerError)
|
log.Printf("错误: 渲染模板出错: %v", err)
|
||||||
}
|
http.Error(w, "渲染模板出错:"+err.Error(), http.StatusInternalServerError)
|
||||||
log.Printf("模板渲染完成")
|
}
|
||||||
}
|
log.Printf("模板渲染完成")
|
||||||
|
}
|
||||||
// 处理获取传感器数据的API
|
|
||||||
func handleGetData(w http.ResponseWriter, r *http.Request) {
|
// 处理获取传感器数据的API
|
||||||
log.Printf("接收到获取数据请求: %s", r.URL.String())
|
func handleGetData(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("接收到获取数据请求: %s", r.URL.String())
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
sensorIDStr := r.URL.Query().Get("sensor_id")
|
|
||||||
limitStr := r.URL.Query().Get("limit")
|
sensorIDStr := r.URL.Query().Get("sensor_id")
|
||||||
startDateStr := r.URL.Query().Get("start_date")
|
limitStr := r.URL.Query().Get("limit")
|
||||||
endDateStr := r.URL.Query().Get("end_date")
|
startDateStr := r.URL.Query().Get("start_date")
|
||||||
|
endDateStr := r.URL.Query().Get("end_date")
|
||||||
limit := 500 // 默认限制为500条数据
|
|
||||||
noLimit := false // 是否不限制数据条数
|
limit := 500 // 默认限制为500条数据
|
||||||
|
noLimit := false // 是否不限制数据条数
|
||||||
var sensorID int
|
|
||||||
var err error
|
var sensorID int
|
||||||
if sensorIDStr != "" && sensorIDStr != "all" {
|
var err error
|
||||||
sensorID, err = strconv.Atoi(sensorIDStr)
|
if sensorIDStr != "" && sensorIDStr != "all" {
|
||||||
if err != nil {
|
sensorID, err = strconv.Atoi(sensorIDStr)
|
||||||
log.Printf("错误: 无效的传感器ID: %s", sensorIDStr)
|
if err != nil {
|
||||||
http.Error(w, "无效的传感器ID", http.StatusBadRequest)
|
log.Printf("错误: 无效的传感器ID: %s", sensorIDStr)
|
||||||
return
|
http.Error(w, "无效的传感器ID", http.StatusBadRequest)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if limitStr != "" {
|
|
||||||
if limitStr == "all" {
|
if limitStr != "" {
|
||||||
noLimit = true
|
if limitStr == "all" {
|
||||||
limit = 0 // 设置为0表示不使用LIMIT子句
|
noLimit = true
|
||||||
} else {
|
limit = 0 // 设置为0表示不使用LIMIT子句
|
||||||
limit, err = strconv.Atoi(limitStr)
|
} else {
|
||||||
if err != nil || limit <= 0 {
|
limit, err = strconv.Atoi(limitStr)
|
||||||
log.Printf("错误: 无效的记录数限制: %s", limitStr)
|
if err != nil || limit <= 0 {
|
||||||
http.Error(w, "无效的记录数限制", http.StatusBadRequest)
|
log.Printf("错误: 无效的记录数限制: %s", limitStr)
|
||||||
return
|
http.Error(w, "无效的记录数限制", http.StatusBadRequest)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var startDate, endDate time.Time
|
|
||||||
if startDateStr != "" {
|
var startDate, endDate time.Time
|
||||||
startDate, err = time.Parse("2006-01-02T15:04", startDateStr)
|
if startDateStr != "" {
|
||||||
if err != nil {
|
startDate, err = time.Parse("2006-01-02T15:04", startDateStr)
|
||||||
log.Printf("错误: 无效的开始日期: %s, %v", startDateStr, err)
|
if err != nil {
|
||||||
http.Error(w, "无效的开始日期", http.StatusBadRequest)
|
log.Printf("错误: 无效的开始日期: %s, %v", startDateStr, err)
|
||||||
return
|
http.Error(w, "无效的开始日期", http.StatusBadRequest)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if endDateStr != "" {
|
|
||||||
endDate, err = time.Parse("2006-01-02T15:04", endDateStr)
|
if endDateStr != "" {
|
||||||
if err != nil {
|
endDate, err = time.Parse("2006-01-02T15:04", endDateStr)
|
||||||
log.Printf("错误: 无效的结束日期: %s, %v", endDateStr, err)
|
if err != nil {
|
||||||
http.Error(w, "无效的结束日期", http.StatusBadRequest)
|
log.Printf("错误: 无效的结束日期: %s, %v", endDateStr, err)
|
||||||
return
|
http.Error(w, "无效的结束日期", http.StatusBadRequest)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var data []SensorData
|
|
||||||
if sensorIDStr == "all" || sensorIDStr == "" {
|
var data []SensorData
|
||||||
data, err = GetAllSensorData(limit, startDate, endDate)
|
if sensorIDStr == "all" || sensorIDStr == "" {
|
||||||
} else {
|
data, err = GetAllSensorData(limit, startDate, endDate)
|
||||||
data, err = GetSensorData(sensorID, limit, startDate, endDate)
|
} else {
|
||||||
}
|
data, err = GetSensorData(sensorID, limit, startDate, endDate)
|
||||||
|
}
|
||||||
if err != nil {
|
|
||||||
log.Printf("错误: 获取数据失败: %v", err)
|
if err != nil {
|
||||||
http.Error(w, "获取数据失败:"+err.Error(), http.StatusInternalServerError)
|
log.Printf("错误: 获取数据失败: %v", err)
|
||||||
return
|
http.Error(w, "获取数据失败:"+err.Error(), http.StatusInternalServerError)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
if noLimit {
|
|
||||||
log.Printf("成功获取到所有数据记录(%d条)", len(data))
|
if noLimit {
|
||||||
} else {
|
log.Printf("成功获取到所有数据记录(%d条)", len(data))
|
||||||
log.Printf("成功获取到 %d 条数据记录(限制:%d条)", len(data), limit)
|
} else {
|
||||||
}
|
log.Printf("成功获取到 %d 条数据记录(限制:%d条)", len(data), limit)
|
||||||
|
}
|
||||||
if err := json.NewEncoder(w).Encode(data); err != nil {
|
|
||||||
log.Printf("错误: 编码JSON失败: %v", err)
|
if err := json.NewEncoder(w).Encode(data); err != nil {
|
||||||
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
log.Printf("错误: 编码JSON失败: %v", err)
|
||||||
}
|
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 处理获取所有传感器ID的API
|
|
||||||
func handleGetSensors(w http.ResponseWriter, r *http.Request) {
|
// 处理获取所有传感器ID的API
|
||||||
log.Printf("接收到获取传感器列表请求")
|
func handleGetSensors(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("接收到获取传感器列表请求")
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
sensorIDs, err := GetAllSensorIDs()
|
|
||||||
if err != nil {
|
sensorIDs, err := GetAllSensorIDs()
|
||||||
log.Printf("错误: 获取传感器ID失败: %v", err)
|
if err != nil {
|
||||||
http.Error(w, "获取传感器ID失败:"+err.Error(), http.StatusInternalServerError)
|
log.Printf("错误: 获取传感器ID失败: %v", err)
|
||||||
return
|
http.Error(w, "获取传感器ID失败:"+err.Error(), http.StatusInternalServerError)
|
||||||
}
|
return
|
||||||
|
}
|
||||||
log.Printf("成功获取到 %d 个传感器ID", len(sensorIDs))
|
|
||||||
|
log.Printf("成功获取到 %d 个传感器ID", len(sensorIDs))
|
||||||
if err := json.NewEncoder(w).Encode(sensorIDs); err != nil {
|
|
||||||
log.Printf("错误: 编码JSON失败: %v", err)
|
if err := json.NewEncoder(w).Encode(sensorIDs); err != nil {
|
||||||
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
log.Printf("错误: 编码JSON失败: %v", err)
|
||||||
}
|
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
func handleGetClients(w http.ResponseWriter, r *http.Request) {
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
func handleGetClients(w http.ResponseWriter, r *http.Request) {
|
||||||
clients := getAllClients()
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
if err := json.NewEncoder(w).Encode(clients); err != nil {
|
clients := getAllClients()
|
||||||
log.Printf("错误: 编码客户端信息JSON失败: %v", err)
|
|
||||||
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
if err := json.NewEncoder(w).Encode(clients); err != nil {
|
||||||
}
|
log.Printf("错误: 编码客户端信息JSON失败: %v", err)
|
||||||
}
|
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理手动触发查询指令的API
|
||||||
|
func handleTriggerQuery(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.Error(w, "只支持POST请求", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发向所有在线客户端发送查询指令
|
||||||
|
sent := triggerManualQuery()
|
||||||
|
|
||||||
|
response := map[string]interface{}{
|
||||||
|
"success": true,
|
||||||
|
"message": fmt.Sprintf("已向%d个客户端发送查询指令", sent),
|
||||||
|
"sent_count": sent,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||||
|
log.Printf("错误: 编码响应JSON失败: %v", err)
|
||||||
|
http.Error(w, "编码JSON失败:"+err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ type ClientInfo struct {
|
|||||||
var (
|
var (
|
||||||
clientsMutex sync.Mutex
|
clientsMutex sync.Mutex
|
||||||
clients = make(map[string]*ClientInfo)
|
clients = make(map[string]*ClientInfo)
|
||||||
|
clientConns = make(map[string]net.Conn) // 存储客户端连接
|
||||||
)
|
)
|
||||||
|
|
||||||
// StartTCPServer 启动TCP服务器
|
// StartTCPServer 启动TCP服务器
|
||||||
@ -55,6 +56,11 @@ func handleConnection(conn net.Conn) {
|
|||||||
|
|
||||||
addClient(remoteAddr)
|
addClient(remoteAddr)
|
||||||
|
|
||||||
|
// 存储连接以便手动查询使用
|
||||||
|
clientsMutex.Lock()
|
||||||
|
clientConns[remoteAddr] = conn
|
||||||
|
clientsMutex.Unlock()
|
||||||
|
|
||||||
// 启动定时发送指令的goroutine
|
// 启动定时发送指令的goroutine
|
||||||
go sendPeriodicCommand(conn, remoteAddr)
|
go sendPeriodicCommand(conn, remoteAddr)
|
||||||
|
|
||||||
@ -69,6 +75,10 @@ func handleConnection(conn net.Conn) {
|
|||||||
Logger.Printf("客户端断开连接 %s", remoteAddr)
|
Logger.Printf("客户端断开连接 %s", remoteAddr)
|
||||||
}
|
}
|
||||||
removeClient(remoteAddr)
|
removeClient(remoteAddr)
|
||||||
|
// 清理连接映射
|
||||||
|
clientsMutex.Lock()
|
||||||
|
delete(clientConns, remoteAddr)
|
||||||
|
clientsMutex.Unlock()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +102,10 @@ func handleConnection(conn net.Conn) {
|
|||||||
if _, err := conn.Write([]byte(resp)); err != nil {
|
if _, err := conn.Write([]byte(resp)); err != nil {
|
||||||
Logger.Printf("发送响应到客户端 %s 失败: %v", remoteAddr, err)
|
Logger.Printf("发送响应到客户端 %s 失败: %v", remoteAddr, err)
|
||||||
removeClient(remoteAddr)
|
removeClient(remoteAddr)
|
||||||
|
// 清理连接映射
|
||||||
|
clientsMutex.Lock()
|
||||||
|
delete(clientConns, remoteAddr)
|
||||||
|
clientsMutex.Unlock()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +296,7 @@ func startClientCleanup() {
|
|||||||
for addr, client := range clients {
|
for addr, client := range clients {
|
||||||
if now.Sub(client.LastSeen) > 24*time.Hour {
|
if now.Sub(client.LastSeen) > 24*time.Hour {
|
||||||
delete(clients, addr)
|
delete(clients, addr)
|
||||||
|
delete(clientConns, addr) // 同时清理连接
|
||||||
Logger.Printf("移除过期客户端: %s", addr)
|
Logger.Printf("移除过期客户端: %s", addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,3 +305,31 @@ func startClientCleanup() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// triggerManualQuery 手动触发向所有在线客户端发送查询指令
|
||||||
|
func triggerManualQuery() int {
|
||||||
|
clientsMutex.Lock()
|
||||||
|
defer clientsMutex.Unlock()
|
||||||
|
|
||||||
|
sentCount := 0
|
||||||
|
command := "@1602301014A*0!\n"
|
||||||
|
|
||||||
|
for addr, client := range clients {
|
||||||
|
// 检查客户端是否在线(最近10分钟内活跃)
|
||||||
|
if time.Since(client.LastSeen) < 10*time.Minute {
|
||||||
|
if conn, exists := clientConns[addr]; exists {
|
||||||
|
if _, err := conn.Write([]byte(command)); err != nil {
|
||||||
|
Logger.Printf("手动发送查询指令到客户端 %s 失败: %v", addr, err)
|
||||||
|
// 连接可能已断开,从映射中移除
|
||||||
|
delete(clientConns, addr)
|
||||||
|
} else {
|
||||||
|
TCPDataLogger.Printf("手动发送查询指令到客户端 %s: %s", addr, strings.TrimSpace(command))
|
||||||
|
sentCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Printf("手动查询指令已发送到 %d 个客户端", sentCount)
|
||||||
|
return sentCount
|
||||||
|
}
|
||||||
|
|||||||
@ -275,6 +275,9 @@
|
|||||||
// 检查连接状态
|
// 检查连接状态
|
||||||
checkConnectionStatus();
|
checkConnectionStatus();
|
||||||
connectionCheckTimer = setInterval(checkConnectionStatus, 30000); // 每30秒检查一次
|
connectionCheckTimer = setInterval(checkConnectionStatus, 30000); // 每30秒检查一次
|
||||||
|
|
||||||
|
// 显示数据库中的最新数据(不发送TCP查询指令)
|
||||||
|
fetchLatestData();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化日期选择器
|
// 初始化日期选择器
|
||||||
@ -784,13 +787,35 @@
|
|||||||
// 先获取一次当前最新数据
|
// 先获取一次当前最新数据
|
||||||
fetchLatestData();
|
fetchLatestData();
|
||||||
|
|
||||||
// 触发TCP服务器发送查询指令,等待3秒后再次获取最新数据
|
// 发送TCP查询指令
|
||||||
setTimeout(() => {
|
fetch('/api/trigger-query', {
|
||||||
fetchLatestData();
|
method: 'POST',
|
||||||
loadData(); // 也刷新一下表格数据
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
console.log(`查询指令已发送到 ${data.sent_count} 个设备`);
|
||||||
|
// 等待3秒后获取最新数据(给设备响应时间)
|
||||||
|
setTimeout(() => {
|
||||||
|
fetchLatestData();
|
||||||
|
loadData(); // 也刷新一下表格数据
|
||||||
|
latestDataElement.style.opacity = 1;
|
||||||
|
document.getElementById('queryLatestBtn').textContent = '查询最新数据';
|
||||||
|
}, 3000);
|
||||||
|
} else {
|
||||||
|
console.error('发送查询指令失败:', data.message);
|
||||||
|
latestDataElement.style.opacity = 1;
|
||||||
|
document.getElementById('queryLatestBtn').textContent = '查询最新数据';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('发送查询指令出错:', error);
|
||||||
latestDataElement.style.opacity = 1;
|
latestDataElement.style.opacity = 1;
|
||||||
document.getElementById('queryLatestBtn').textContent = '查询最新数据';
|
document.getElementById('queryLatestBtn').textContent = '查询最新数据';
|
||||||
}, 3000);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面卸载时清除定时器
|
// 页面卸载时清除定时器
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user