diff --git a/sentinel/.idea/.gitignore b/iot/EdgeAgent/.idea/.gitignore
similarity index 100%
rename from sentinel/.idea/.gitignore
rename to iot/EdgeAgent/.idea/.gitignore
diff --git a/sentinel/.idea/dictionaries/project.xml b/iot/EdgeAgent/.idea/dictionaries/project.xml
similarity index 100%
rename from sentinel/.idea/dictionaries/project.xml
rename to iot/EdgeAgent/.idea/dictionaries/project.xml
diff --git a/sentinel/.idea/go.imports.xml b/iot/EdgeAgent/.idea/go.imports.xml
similarity index 100%
rename from sentinel/.idea/go.imports.xml
rename to iot/EdgeAgent/.idea/go.imports.xml
diff --git a/sentinel/.idea/modules.xml b/iot/EdgeAgent/.idea/modules.xml
similarity index 100%
rename from sentinel/.idea/modules.xml
rename to iot/EdgeAgent/.idea/modules.xml
diff --git a/sentinel/.idea/sentinel.iml b/iot/EdgeAgent/.idea/sentinel.iml
similarity index 100%
rename from sentinel/.idea/sentinel.iml
rename to iot/EdgeAgent/.idea/sentinel.iml
diff --git a/sentinel/.idea/vcs.xml b/iot/EdgeAgent/.idea/vcs.xml
similarity index 75%
rename from sentinel/.idea/vcs.xml
rename to iot/EdgeAgent/.idea/vcs.xml
index 6c0b863..64713b8 100644
--- a/sentinel/.idea/vcs.xml
+++ b/iot/EdgeAgent/.idea/vcs.xml
@@ -1,6 +1,7 @@
+
\ No newline at end of file
diff --git a/iot/EdgeAgent/build/linux_amd64/main b/iot/EdgeAgent/build/linux_amd64/main
new file mode 100644
index 0000000..3cd8be8
Binary files /dev/null and b/iot/EdgeAgent/build/linux_amd64/main differ
diff --git a/iot/EdgeAgent/build/linux_amd64/updater b/iot/EdgeAgent/build/linux_amd64/updater
new file mode 100644
index 0000000..f647d12
Binary files /dev/null and b/iot/EdgeAgent/build/linux_amd64/updater differ
diff --git a/iot/EdgeAgent/build/linux_arm64/main b/iot/EdgeAgent/build/linux_arm64/main
new file mode 100644
index 0000000..2010484
Binary files /dev/null and b/iot/EdgeAgent/build/linux_arm64/main differ
diff --git a/iot/EdgeAgent/build/linux_arm64/updater b/iot/EdgeAgent/build/linux_arm64/updater
new file mode 100644
index 0000000..a1df89f
Binary files /dev/null and b/iot/EdgeAgent/build/linux_arm64/updater differ
diff --git a/iot/EdgeAgent/build/win/main.exe b/iot/EdgeAgent/build/win/main.exe
new file mode 100644
index 0000000..df75d64
Binary files /dev/null and b/iot/EdgeAgent/build/win/main.exe differ
diff --git a/iot/EdgeAgent/build/win/updater.exe b/iot/EdgeAgent/build/win/updater.exe
new file mode 100644
index 0000000..88496bc
Binary files /dev/null and b/iot/EdgeAgent/build/win/updater.exe differ
diff --git a/sentinel/build_all.ps1 b/iot/EdgeAgent/build_all.ps1
similarity index 100%
rename from sentinel/build_all.ps1
rename to iot/EdgeAgent/build_all.ps1
diff --git a/sentinel/go.mod b/iot/EdgeAgent/go.mod
similarity index 100%
rename from sentinel/go.mod
rename to iot/EdgeAgent/go.mod
diff --git a/sentinel/go.sum b/iot/EdgeAgent/go.sum
similarity index 100%
rename from sentinel/go.sum
rename to iot/EdgeAgent/go.sum
diff --git a/sentinel/main/business_service.go b/iot/EdgeAgent/main/business_service.go
similarity index 100%
rename from sentinel/main/business_service.go
rename to iot/EdgeAgent/main/business_service.go
diff --git a/sentinel/main/main.go b/iot/EdgeAgent/main/main.go
similarity index 63%
rename from sentinel/main/main.go
rename to iot/EdgeAgent/main/main.go
index 3efee24..0638afa 100644
--- a/sentinel/main/main.go
+++ b/iot/EdgeAgent/main/main.go
@@ -12,15 +12,15 @@ import (
func main() {
banner := `
==========================================================================
- _______ _______ _ __________________ _ _______ _
-( ____ \( ____ \( ( /|\__ __/\__ __/( ( /|( ____ \( \
-| (_____ | (__ | \ | | | | | | | \ | || (__ | |
-(_____ )| __) | (\ \) | | | | | | (\ \) || __) | |
-/\____) || (____/\| ) \ | | | ___) (___| ) \ || (____/\| (____/\
-\_______)(_______/|/ )_) )_( \_______/|/ )_)(_______/(_______/
+
+██████ █████ █████ ██████ ██ █████ ██████ ██ ██ ██████
+██ ██ ██ ██ ██ ████ ██ ██ ███ ██ ██
+█████ ██ ██ ██ ██ █████ ██ ██ ██ ██ █████ ████ ██ ██
+██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ████ ██
+██████ █████ █████ ██████ ██ ██ █████ ██████ ██ ██ ██
+
==========================================================================
`
-
fmt.Println(banner)
deviceID := device.GetDeviceID()
log.Init(config.Log_file_dic) // 初始化日志目录
@@ -54,8 +54,6 @@ func main() {
time.Sleep(5 * time.Second)
continue
}
- // 个人业务
- test()
break
}
diff --git a/sentinel/main/main_factory.go b/iot/EdgeAgent/main/main_factory.go
similarity index 100%
rename from sentinel/main/main_factory.go
rename to iot/EdgeAgent/main/main_factory.go
diff --git a/sentinel/main/main_linux.go b/iot/EdgeAgent/main/main_linux.go
similarity index 100%
rename from sentinel/main/main_linux.go
rename to iot/EdgeAgent/main/main_linux.go
diff --git a/sentinel/main/main_windows.go b/iot/EdgeAgent/main/main_windows.go
similarity index 100%
rename from sentinel/main/main_windows.go
rename to iot/EdgeAgent/main/main_windows.go
diff --git a/sentinel/main/mqtt_service.go b/iot/EdgeAgent/main/mqtt_service.go
similarity index 100%
rename from sentinel/main/mqtt_service.go
rename to iot/EdgeAgent/main/mqtt_service.go
diff --git a/sentinel/pkg/config/config.go b/iot/EdgeAgent/pkg/config/config.go
similarity index 73%
rename from sentinel/pkg/config/config.go
rename to iot/EdgeAgent/pkg/config/config.go
index 2d95aa4..625c196 100644
--- a/sentinel/pkg/config/config.go
+++ b/iot/EdgeAgent/pkg/config/config.go
@@ -7,6 +7,8 @@ const (
// 版本号
APP_VERSION = 1
+ BASE_URL = "https://ai.ronsunny.cn:8090"
+ //BASE_URL = "http://127.0.0.1:13011"
Log_file_dic = "./logs"
MQTT_BROKER = "tls://ai.ronsunny.cn:8093"
PASSWORD = "123456"
diff --git a/sentinel/pkg/device/deviceid.go b/iot/EdgeAgent/pkg/device/deviceid.go
similarity index 100%
rename from sentinel/pkg/device/deviceid.go
rename to iot/EdgeAgent/pkg/device/deviceid.go
diff --git a/sentinel/pkg/log/logger.go b/iot/EdgeAgent/pkg/log/logger.go
similarity index 100%
rename from sentinel/pkg/log/logger.go
rename to iot/EdgeAgent/pkg/log/logger.go
diff --git a/sentinel/pkg/model/BaseResponse.go b/iot/EdgeAgent/pkg/model/BaseResponse.go
similarity index 100%
rename from sentinel/pkg/model/BaseResponse.go
rename to iot/EdgeAgent/pkg/model/BaseResponse.go
diff --git a/sentinel/pkg/model/MqttTopic.go b/iot/EdgeAgent/pkg/model/MqttTopic.go
similarity index 100%
rename from sentinel/pkg/model/MqttTopic.go
rename to iot/EdgeAgent/pkg/model/MqttTopic.go
diff --git a/sentinel/pkg/model/UpdateInfo.go b/iot/EdgeAgent/pkg/model/UpdateInfo.go
similarity index 100%
rename from sentinel/pkg/model/UpdateInfo.go
rename to iot/EdgeAgent/pkg/model/UpdateInfo.go
diff --git a/sentinel/pkg/net/api.go b/iot/EdgeAgent/pkg/net/api.go
similarity index 71%
rename from sentinel/pkg/net/api.go
rename to iot/EdgeAgent/pkg/net/api.go
index 00472fd..8de6cf7 100644
--- a/sentinel/pkg/net/api.go
+++ b/iot/EdgeAgent/pkg/net/api.go
@@ -4,7 +4,6 @@ import "sentinel/pkg/model"
const (
updateCheckURL = "/iot/common/update/check"
- analyticsURL = "/api/public/sentinel-record-analytics"
)
func CheckUpdate(deviceID string) (*model.UpdateInfo, error) {
@@ -21,7 +20,3 @@ func CheckUpdate(deviceID string) (*model.UpdateInfo, error) {
}
return &resp, nil
}
-
-func Analytics(req model.Record) error {
- return Post(analyticsURL, req, nil)
-}
diff --git a/iot/EdgeAgent/pkg/net/httpclient.go b/iot/EdgeAgent/pkg/net/httpclient.go
new file mode 100644
index 0000000..1cac3bf
--- /dev/null
+++ b/iot/EdgeAgent/pkg/net/httpclient.go
@@ -0,0 +1,101 @@
+package api
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "sentinel/pkg/model"
+ "time"
+
+ "sentinel/pkg/config"
+ "sentinel/pkg/log"
+)
+
+var client = &http.Client{
+ Timeout: 5 * time.Second,
+}
+
+func Get(path string, query map[string]string, out any) error {
+ return do(http.MethodGet, path, query, nil, out)
+}
+
+func Post(path string, body any, out any) error {
+ return do(http.MethodPost, path, nil, body, out)
+}
+
+func do(method, path string, query map[string]string, body any, out any) error {
+ u, err := url.Parse(config.BASE_URL + path)
+ if err != nil {
+ log.Error("parse url failed: " + err.Error())
+ return err
+ }
+
+ if len(query) > 0 {
+ q := u.Query()
+ for k, v := range query {
+ q.Set(k, v)
+ }
+ u.RawQuery = q.Encode()
+ }
+
+ var reqBody *bytes.Reader
+ if body != nil {
+ b, err := json.Marshal(body)
+ if err != nil {
+ log.Error("marshal body failed: " + err.Error())
+ return err
+ }
+ reqBody = bytes.NewReader(b)
+ } else {
+ reqBody = bytes.NewReader(nil)
+ }
+
+ req, err := http.NewRequest(method, u.String(), reqBody)
+ if err != nil {
+ log.Error("create request failed: " + err.Error())
+ return err
+ }
+ req.Header.Set("Content-Type", "application/json")
+ req.Header.Set("apikey", "NzusyzcLIUoZ22tflHN2sOjHrry3W7zJ")
+
+ resp, err := client.Do(req)
+ if err != nil {
+ log.Error("request failed: " + err.Error())
+ return err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+ log.Error("http status error: " + resp.Status)
+ return fmt.Errorf("http status %d", resp.StatusCode)
+ }
+
+ // 解析成 BaseResponse
+ var baseResp model.BaseResponse
+ if err := json.NewDecoder(resp.Body).Decode(&baseResp); err != nil {
+ log.Error("decode base response failed: " + err.Error())
+ return err
+ }
+
+ if !baseResp.Status {
+ log.Error("server returned error: " + baseResp.Message)
+ return fmt.Errorf(baseResp.Message)
+ }
+
+ if out != nil && baseResp.Data != nil {
+ // 将 Data 转成业务类型
+ b, err := json.Marshal(baseResp.Data)
+ if err != nil {
+ log.Error("marshal data failed: " + err.Error())
+ return err
+ }
+ if err := json.Unmarshal(b, out); err != nil {
+ log.Error("unmarshal data to out failed: " + err.Error())
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/sentinel/pkg/platform/Platform_interface.go b/iot/EdgeAgent/pkg/platform/Platform_interface.go
similarity index 100%
rename from sentinel/pkg/platform/Platform_interface.go
rename to iot/EdgeAgent/pkg/platform/Platform_interface.go
diff --git a/sentinel/pkg/utils/utils.go b/iot/EdgeAgent/pkg/utils/utils.go
similarity index 100%
rename from sentinel/pkg/utils/utils.go
rename to iot/EdgeAgent/pkg/utils/utils.go
diff --git a/sentinel/updater/main.go b/iot/EdgeAgent/updater/main.go
similarity index 100%
rename from sentinel/updater/main.go
rename to iot/EdgeAgent/updater/main.go
diff --git a/sentinel/updater/main_factory.go b/iot/EdgeAgent/updater/main_factory.go
similarity index 100%
rename from sentinel/updater/main_factory.go
rename to iot/EdgeAgent/updater/main_factory.go
diff --git a/sentinel/updater/main_linux.go b/iot/EdgeAgent/updater/main_linux.go
similarity index 100%
rename from sentinel/updater/main_linux.go
rename to iot/EdgeAgent/updater/main_linux.go
diff --git a/sentinel/updater/main_windows.go b/iot/EdgeAgent/updater/main_windows.go
similarity index 100%
rename from sentinel/updater/main_windows.go
rename to iot/EdgeAgent/updater/main_windows.go
diff --git a/iot/Sentinel/.idea/.gitignore b/iot/Sentinel/.idea/.gitignore
new file mode 100644
index 0000000..ab1f416
--- /dev/null
+++ b/iot/Sentinel/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Ignored default folder with query files
+/queries/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/iot/Sentinel/.idea/dictionaries/project.xml b/iot/Sentinel/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..42156b6
--- /dev/null
+++ b/iot/Sentinel/.idea/dictionaries/project.xml
@@ -0,0 +1,8 @@
+
+
+
+ linux
+ 从海康sdk获取图片以及信息
+
+
+
\ No newline at end of file
diff --git a/iot/Sentinel/.idea/go.imports.xml b/iot/Sentinel/.idea/go.imports.xml
new file mode 100644
index 0000000..d7202f0
--- /dev/null
+++ b/iot/Sentinel/.idea/go.imports.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iot/Sentinel/.idea/modules.xml b/iot/Sentinel/.idea/modules.xml
new file mode 100644
index 0000000..f5c9a13
--- /dev/null
+++ b/iot/Sentinel/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iot/Sentinel/.idea/remote-targets.xml b/iot/Sentinel/.idea/remote-targets.xml
new file mode 100644
index 0000000..219632d
--- /dev/null
+++ b/iot/Sentinel/.idea/remote-targets.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iot/Sentinel/.idea/sentinel.iml b/iot/Sentinel/.idea/sentinel.iml
new file mode 100644
index 0000000..2848ab9
--- /dev/null
+++ b/iot/Sentinel/.idea/sentinel.iml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iot/Sentinel/.idea/vcs.xml b/iot/Sentinel/.idea/vcs.xml
new file mode 100644
index 0000000..64713b8
--- /dev/null
+++ b/iot/Sentinel/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iot/Sentinel/Dockerfile b/iot/Sentinel/Dockerfile
new file mode 100644
index 0000000..4803a19
--- /dev/null
+++ b/iot/Sentinel/Dockerfile
@@ -0,0 +1,36 @@
+# ==========================
+# Stage 1: Build the Go binary
+# ==========================
+FROM golang:1.21-alpine AS builder
+
+# 设置工作目录
+WORKDIR /build
+
+# 复制 go.mod 和 go.sum,先做依赖缓存
+COPY go.mod go.sum ./
+
+# 下载依赖(缓存层)
+RUN go mod download
+
+# 复制源代码
+COPY app/ ./app
+
+# 编译可执行文件
+RUN go build -o sentinel ./app/main.go
+
+# ==========================
+# Stage 2: 生成最终运行镜像
+# ==========================
+FROM alpine:3.18
+
+# 安装 ca-certificates,如果程序需要访问 HTTPS
+RUN apk add --no-cache ca-certificates
+
+# 设置工作目录
+WORKDIR /app
+
+# 复制从 builder 构建好的二进制
+COPY --from=builder /build/sentinel .
+
+# 设置默认执行命令
+CMD ["./sentinel"]
diff --git a/iot/Sentinel/app/log/logger.go b/iot/Sentinel/app/log/logger.go
new file mode 100644
index 0000000..7bfa092
--- /dev/null
+++ b/iot/Sentinel/app/log/logger.go
@@ -0,0 +1,94 @@
+package log
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "time"
+)
+
+var logDir = "./logs" // 日志目录,可根据需要修改
+
+// 初始化日志目录
+func Init() {
+ if err := os.MkdirAll(logDir, 0755); err != nil {
+ fmt.Println("create log dir failed:", err)
+ }
+ cleanupOldLogs()
+}
+
+// Cleanup 删除超过7天的日志文件
+func cleanupOldLogs() {
+ files, err := os.ReadDir(logDir)
+ if err != nil {
+ return
+ }
+ cutoff := time.Now().AddDate(0, 0, -7)
+ for _, f := range files {
+ if f.IsDir() {
+ continue
+ }
+ info, err := f.Info()
+ if err != nil {
+ continue
+ }
+ if info.ModTime().Before(cutoff) {
+ _ = os.Remove(filepath.Join(logDir, f.Name()))
+ }
+ }
+}
+
+// log 内部写文件
+func logToFile(level, msg string) {
+ fmt.Println(msg)
+ t := time.Now()
+ // 确保日志目录存在
+ if err := os.MkdirAll(logDir, 0755); err != nil {
+ fmt.Println("create log dir failed:", err)
+ return
+ }
+
+ filename := filepath.Join(logDir, t.Format("2006-01-02")+".log")
+ f, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
+ if err != nil {
+ fmt.Println("open log file failed:", err)
+ return
+ }
+ defer f.Close()
+
+ line := fmt.Sprintf("%s [%s] %s\n", t.Format("2006-01-02 15:04:05"), level, msg)
+ _, _ = f.WriteString(line)
+}
+
+// 对外接口
+func Info(msg string) {
+ logToFile("INFO", msg)
+}
+
+// Println 支持多个参数拼接,写 INFO 日志
+func Println(v ...interface{}) {
+ msg := fmt.Sprint(v...)
+ logToFile("INFO", msg)
+}
+func Warn(msg string) {
+ logToFile("WARN", msg)
+}
+
+func Error(msg string) {
+ logToFile("ERROR", msg)
+}
+func Fatal(err error) {
+ if err == nil {
+ return
+ }
+ logToFile("ERROR", err.Error())
+}
+
+// Fatal 打印错误日志并退出程序
+func Fatalf(msg string, args ...interface{}) {
+ if len(args) > 0 {
+ msg = fmt.Sprintf(msg, args...)
+ }
+ logToFile("FATAL", msg)
+ os.Exit(1)
+}
diff --git a/sentinel/main/func.go b/iot/Sentinel/app/main.go
similarity index 54%
rename from sentinel/main/func.go
rename to iot/Sentinel/app/main.go
index db5cc84..d2e19e3 100644
--- a/sentinel/main/func.go
+++ b/iot/Sentinel/app/main.go
@@ -3,25 +3,38 @@ package main
import (
"context"
"fmt"
- "sentinel/pkg/device"
- "sentinel/pkg/log"
- "sentinel/pkg/model"
- api "sentinel/pkg/net"
- "sentinel/pkg/storage"
+ "sentinel/app/log"
+ "sentinel/app/model"
+ "sentinel/app/net"
+ "sentinel/app/storage"
)
-func test() {
+func main() {
+ banner := `
+==========================================================================
+ _______ _______ _ __________________ _ _______ _
+( ____ \( ____ \( ( /|\__ __/\__ __/( ( /|( ____ \( \
+| (_____ | (__ | \ | | | | | | | \ | || (__ | |
+(_____ )| __) | (\ \) | | | | | | (\ \) || __) | |
+/\____) || (____/\| ) \ | | | ___) (___| ) \ || (____/\| (____/\
+\_______)(_______/|/ )_) )_( \_______/|/ )_)(_______/(_______/
+==========================================================================
+`
+ deviceID := "6823316af0e540bea818ec1be25cc14a"
+ log.Init() // 初始化日志目录
+ log.Info("Device id: " + deviceID) // 第一次启动记录
+ log.Info(banner)
// 0. 从海康SDK获取图片以及信息
- record := loadData()
+ record := loadData(deviceID)
// 1. 上传图片到OSS
uploadFile(record.LicensePlateImage, record.VehicleImage)
// 2. 调用分析请求
analytics(record)
}
-func loadData() model.Record {
+func loadData(deviceID string) model.Record {
return model.Record{
- DeviceId: device.GetDeviceID(),
+ DeviceId: deviceID, //从环境变量取
LicensePlate: "晋A-888888",
LicensePlateImage: "licensePlateImage_test1.jpg",
VehicleType: "大型货车",
diff --git a/iot/Sentinel/app/model/BaseResponse.go b/iot/Sentinel/app/model/BaseResponse.go
new file mode 100644
index 0000000..7b33824
--- /dev/null
+++ b/iot/Sentinel/app/model/BaseResponse.go
@@ -0,0 +1,7 @@
+package model
+
+type BaseResponse struct {
+ Status bool `json:"status"` // 是否成功
+ Message string `json:"message"` // 提示信息
+ Data interface{} `json:"data,omitempty"` // 泛型数据,用 interface{} 接收任意类型
+}
diff --git a/sentinel/pkg/model/Record.go b/iot/Sentinel/app/model/Record.go
similarity index 100%
rename from sentinel/pkg/model/Record.go
rename to iot/Sentinel/app/model/Record.go
diff --git a/iot/Sentinel/app/net/api.go b/iot/Sentinel/app/net/api.go
new file mode 100644
index 0000000..8d9e70e
--- /dev/null
+++ b/iot/Sentinel/app/net/api.go
@@ -0,0 +1,13 @@
+package api
+
+import (
+ "sentinel/app/model"
+)
+
+const (
+ analyticsURL = "/api/public/sentinel-record-analytics"
+)
+
+func Analytics(req model.Record) error {
+ return Post(analyticsURL, req, nil)
+}
diff --git a/sentinel/pkg/net/httpclient.go b/iot/Sentinel/app/net/httpclient.go
similarity index 98%
rename from sentinel/pkg/net/httpclient.go
rename to iot/Sentinel/app/net/httpclient.go
index f3b7f64..19a0e3b 100644
--- a/sentinel/pkg/net/httpclient.go
+++ b/iot/Sentinel/app/net/httpclient.go
@@ -6,10 +6,9 @@ import (
"fmt"
"net/http"
"net/url"
- "sentinel/pkg/model"
+ "sentinel/app/log"
+ "sentinel/app/model"
"time"
-
- "sentinel/pkg/log"
)
// const baseURL = "http://127.0.0.1:13011"
diff --git a/sentinel/pkg/storage/minio.go b/iot/Sentinel/app/storage/minio.go
similarity index 100%
rename from sentinel/pkg/storage/minio.go
rename to iot/Sentinel/app/storage/minio.go
diff --git a/iot/Sentinel/app/utils/utils.go b/iot/Sentinel/app/utils/utils.go
new file mode 100644
index 0000000..5c28daf
--- /dev/null
+++ b/iot/Sentinel/app/utils/utils.go
@@ -0,0 +1,100 @@
+package utils
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "runtime"
+
+ "github.com/shirou/gopsutil/v3/cpu"
+ "github.com/shirou/gopsutil/v3/disk"
+ "github.com/shirou/gopsutil/v3/mem"
+)
+
+func GetLocalIP() string {
+ ifaces, err := net.Interfaces()
+ if err != nil {
+ return ""
+ }
+ for _, iface := range ifaces {
+ if iface.Flags&net.FlagUp == 0 {
+ continue // 接口未启用
+ }
+ if iface.Flags&net.FlagLoopback != 0 {
+ continue // 忽略回环
+ }
+ addrs, err := iface.Addrs()
+ if err != nil {
+ continue
+ }
+ for _, addr := range addrs {
+ var ip net.IP
+ switch v := addr.(type) {
+ case *net.IPNet:
+ ip = v.IP
+ case *net.IPAddr:
+ ip = v.IP
+ }
+ if ip == nil || ip.IsLoopback() {
+ continue
+ }
+ ip = ip.To4()
+ if ip == nil {
+ continue
+ }
+ return ip.String()
+ }
+ }
+ return ""
+}
+
+func GetHostname() string {
+ name, err := os.Hostname()
+ if err != nil {
+ return ""
+ }
+ return name
+}
+func GetMacAddress() string {
+ ifaces, err := net.Interfaces()
+ if err != nil {
+ return ""
+ }
+ for _, iface := range ifaces {
+ if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
+ continue
+ }
+ mac := iface.HardwareAddr.String()
+ if mac != "" {
+ return mac
+ }
+ }
+ return ""
+}
+
+func GetOSInfo() string {
+ return runtime.GOOS // windows, linux, darwin
+}
+func GetCPUInfo() string {
+ info, err := cpu.Info()
+ if err != nil || len(info) == 0 {
+ return ""
+ }
+ return info[0].ModelName
+}
+
+func GetMemory() string {
+ v, err := mem.VirtualMemory()
+ if err != nil {
+ return ""
+ }
+ return fmt.Sprintf("%dMB", v.Total/1024/1024)
+}
+
+func GetDisk() string {
+ usage, err := disk.Usage("/")
+ if err != nil {
+ return ""
+ }
+ return fmt.Sprintf("%dGB", usage.Total/1024/1024/1024)
+}
diff --git a/iot/Sentinel/go.mod b/iot/Sentinel/go.mod
new file mode 100644
index 0000000..587373a
--- /dev/null
+++ b/iot/Sentinel/go.mod
@@ -0,0 +1,34 @@
+module sentinel
+
+go 1.25.5
+
+require (
+ github.com/dustin/go-humanize v1.0.1 // indirect
+ github.com/eclipse/paho.mqtt.golang v1.5.1 // indirect
+ github.com/go-ini/ini v1.67.0 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/websocket v1.5.3 // indirect
+ github.com/klauspost/compress v1.18.0 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.11 // indirect
+ github.com/klauspost/crc32 v1.3.0 // indirect
+ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
+ github.com/minio/crc64nvme v1.1.0 // indirect
+ github.com/minio/md5-simd v1.1.2 // indirect
+ github.com/minio/minio-go/v7 v7.0.97 // indirect
+ github.com/philhofer/fwd v1.2.0 // indirect
+ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
+ github.com/rs/xid v1.6.0 // indirect
+ github.com/shirou/gopsutil/v3 v3.24.5 // indirect
+ github.com/shoenig/go-m1cpu v0.1.6 // indirect
+ github.com/tinylib/msgp v1.3.0 // indirect
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
+ github.com/tklauser/numcpus v0.6.1 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ golang.org/x/crypto v0.42.0 // indirect
+ golang.org/x/net v0.44.0 // indirect
+ golang.org/x/sync v0.17.0 // indirect
+ golang.org/x/sys v0.36.0 // indirect
+ golang.org/x/text v0.29.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/iot/Sentinel/go.sum b/iot/Sentinel/go.sum
new file mode 100644
index 0000000..4fc4b51
--- /dev/null
+++ b/iot/Sentinel/go.sum
@@ -0,0 +1,64 @@
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE=
+github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
+github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
+github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM=
+github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/minio/crc64nvme v1.1.0 h1:e/tAguZ+4cw32D+IO/8GSf5UVr9y+3eJcxZI2WOO/7Q=
+github.com/minio/crc64nvme v1.1.0/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
+github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
+github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
+github.com/minio/minio-go/v7 v7.0.97 h1:lqhREPyfgHTB/ciX8k2r8k0D93WaFqxbJX36UZq5occ=
+github.com/minio/minio-go/v7 v7.0.97/go.mod h1:re5VXuo0pwEtoNLsNuSr0RrLfT/MBtohwdaSmPPSRSk=
+github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
+github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
+github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
+github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
+github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
+github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
+github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
+github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
+github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
+github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
+golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
+golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
+golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
+golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
+golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
+golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
+golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=