From 866a1e35a2d175eedefe8c45dced62853c0a1e8f Mon Sep 17 00:00:00 2001 From: "qcqcqc@wsl" <1220204124@zust.edu.cn> Date: Fri, 11 Apr 2025 20:23:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E6=A8=A1=E5=9D=97=EF=BC=8C?= =?UTF-8?q?=E9=83=A8=E5=88=86=E5=8A=9F=E8=83=BD=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-service/cmd/main.go | 198 +++++++++++++++ backend-service/go.mod | 18 ++ backend-service/go.sum | 36 +++ backend-service/pkg/client/client.go | 38 +++ backend-service/pkg/machine/info.go | 131 ++++++++++ backend-service/pkg/service/configManager.go | 50 ++++ backend-service/pkg/service/service.go | 110 +++++++++ config-loader/cmd/manager/main.go | 4 +- config-loader/internal/models/config.go | 2 +- config-loader/internal/shm/shm.go | 2 +- config-loader/internal/utils/config_loader.go | 2 +- .../manager/config_manager.go | 0 config/config.yaml | 2 + .../config => config}/execve_rules.json | 0 go.work.sum | 56 +++++ logs/2025-04-11.log | 17 ++ shared/pkg/client/client.go | 230 ++++++++++++++++++ shared/pkg/constants/colors.go | 13 + .../pkg}/constants/constants.go | 7 + shared/pkg/constants/server.go | 8 + shared/pkg/logger/logger.go | 96 ++++---- tests/go.mod | 10 + tests/testcase/http/http.go | 44 ++++ 23 files changed, 1016 insertions(+), 58 deletions(-) create mode 100644 backend-service/cmd/main.go create mode 100644 backend-service/go.sum create mode 100644 backend-service/pkg/client/client.go create mode 100644 backend-service/pkg/machine/info.go create mode 100644 backend-service/pkg/service/configManager.go create mode 100644 backend-service/pkg/service/service.go rename config-loader/{internal => pkg}/manager/config_manager.go (100%) create mode 100644 config/config.yaml rename {config-loader/config => config}/execve_rules.json (100%) create mode 100644 go.work.sum create mode 100755 logs/2025-04-11.log create mode 100644 shared/pkg/client/client.go create mode 100644 shared/pkg/constants/colors.go rename {config-loader/internal => shared/pkg}/constants/constants.go (59%) create mode 100644 shared/pkg/constants/server.go create mode 100644 tests/go.mod create mode 100644 tests/testcase/http/http.go diff --git a/backend-service/cmd/main.go b/backend-service/cmd/main.go new file mode 100644 index 0000000..95abfa9 --- /dev/null +++ b/backend-service/cmd/main.go @@ -0,0 +1,198 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "syscall" + "time" + + "backend-service/pkg/client" + "backend-service/pkg/machine" + "backend-service/pkg/service" + "bash_go_service/shared/pkg/constants" + "bash_go_service/shared/pkg/logger" + + "github.com/spf13/viper" +) + +// isDaemon 检查是否以守护进程模式运行 +func isDaemon() bool { + return len(os.Args) > 1 && os.Args[1] == constants.DaemonFlag +} + +func init() { + logger.Debug("Initializing...") + if isDaemon() { + logger.Debug("Starting daemon...") + runDaemon() + } +} + +func main() { + if err := run(); err != nil { + logger.Error("Application failed: %v", err) + os.Exit(1) + } +} + +// run 程序主逻辑 +func run() error { + // 初始化配置 + if err := initConfig(); err != nil { + return fmt.Errorf("init config: %w", err) + } + + // 采集并发送机器信息 + info, err := collectAndSendMachineInfo() + if err != nil { + return fmt.Errorf("collect and send machine info: %w", err) + } + + // 显示欢迎信息 + showWelcomeMessage(info) + + // 检查并启动守护进程 + if err := handleDaemonProcess(); err != nil { + return fmt.Errorf("handle daemon process: %w", err) + } + + return nil +} + +// initConfig 初始化配置 +func initConfig() error { + viper.AddConfigPath(constants.ConfigPath) + return viper.ReadInConfig() +} + +// collectAndSendMachineInfo 采集并发送机器信息 +func collectAndSendMachineInfo() (*machine.Info, error) { + info := machine.CollectMachineInfo() + if err := client.SendMachineInfo(info); err != nil { + return nil, fmt.Errorf("send machine info: %w", err) + } + return info, nil +} + +// handleDaemonProcess 处理守护进程相关逻辑 +func handleDaemonProcess() error { + // 获取可执行文件路径 + exePath, err := os.Executable() + if err != nil { + return fmt.Errorf("get executable path: %w", err) + } + logger.Debug("Exe path: %s", filepath.Dir(exePath)) + + // 检查现有进程 + if err := checkExistingProcess(); err != nil { + return err + } + + // 启动新的守护进程 + return startDaemonProcess() +} + +// checkExistingProcess 检查是否已有守护进程在运行 +func checkExistingProcess() error { + pidFile := constants.PidFilePath + pidBytes, err := os.ReadFile(pidFile) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return fmt.Errorf("read pid file: %w", err) + } + + pid, err := strconv.Atoi(string(pidBytes)) + if err != nil { + return fmt.Errorf("parse pid: %w", err) + } + + process, err := os.FindProcess(pid) + if err != nil { + return fmt.Errorf("find process: %w", err) + } + + if err := process.Signal(syscall.Signal(0)); err == nil { + logger.Info("Daemon already running with PID: %d", pid) + return fmt.Errorf("daemon already running") + } + + // 进程不存在,删除PID文件 + if err := os.Remove(pidFile); err != nil { + logger.Error("Failed to remove old PID file: %v", err) + } + return nil +} + +func formatGoTime(format string) string { + replacer := strings.NewReplacer( + "%Y", "2006", + "%m", "01", + "%d", "02", + "%H", "15", + "%M", "04", + "%S", "05", + ) + return replacer.Replace(format) +} + +// startDaemonProcess 启动守护进程 +func startDaemonProcess() error { + // 确保日志目录存在 + if err := os.MkdirAll(constants.LogFilePath, constants.LogFileMode); err != nil { + return fmt.Errorf("create logs directory: %w", err) + } + + // 将 strftime 风格格式转换为 Go 的时间格式 + goTimeFormat := formatGoTime(constants.LogNameFormate) + logFileName := time.Now().Format(goTimeFormat) + logFilePath := filepath.Join(constants.LogFilePath, logFileName) + + logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, constants.LogFileMode) + if err != nil { + return fmt.Errorf("open log file: %w", err) + } + + cmd := exec.Command(os.Args[0], constants.DaemonFlag) + cmd.Stdout = logFile + cmd.Stderr = logFile + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setsid: true, + } + + if err := cmd.Start(); err != nil { + return fmt.Errorf("start daemon: %w", err) + } + + // 写入 PID 文件 + pidStr := []byte(fmt.Sprintf("%d", cmd.Process.Pid)) + if err := os.WriteFile(constants.PidFilePath, pidStr, constants.LogFileMode); err != nil { + return fmt.Errorf("write pid file: %w", err) + } + + return nil +} + +// runDaemon 守护进程主逻辑 +func runDaemon() { + logger.Info("Daemon started with PID: %d", os.Getpid()) + service.Run() +} + +// showWelcomeMessage 显示欢迎信息 +func showWelcomeMessage(info *machine.Info) { + message := fmt.Sprintf(`%s +╔══════════════════════════════════════╗ +║ Welcome to Bash Security Service ║ +║ Hostname: %-20s ║ +║ OS: %-32s ║ +╚══════════════════════════════════════╝%s`, + constants.ColorGreen, info.Hostname, info.OS, constants.ColorReset) + + fmt.Println(message) +} diff --git a/backend-service/go.mod b/backend-service/go.mod index 8ec5a90..35354fb 100644 --- a/backend-service/go.mod +++ b/backend-service/go.mod @@ -1,3 +1,21 @@ module backend-service go 1.24.2 + +require ( + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/viper v1.20.1 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/backend-service/go.sum b/backend-service/go.sum new file mode 100644 index 0000000..51edcb7 --- /dev/null +++ b/backend-service/go.sum @@ -0,0 +1,36 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +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= diff --git a/backend-service/pkg/client/client.go b/backend-service/pkg/client/client.go new file mode 100644 index 0000000..24ee79f --- /dev/null +++ b/backend-service/pkg/client/client.go @@ -0,0 +1,38 @@ +package client + +import ( + "bash_go_service/shared/pkg/client" + "bash_go_service/shared/pkg/logger" + + "backend-service/pkg/machine" + + "github.com/spf13/viper" +) + +var ( + apiEndpoint string // 从常量改为变量 +) + +func init() { + viper.SetDefault("machine_registry.endpoint", "none") +} + +type Result struct { + Success bool `json:"success"` // 使用大写字段名,并添加json tag +} + +func SendMachineInfo(info *machine.Info) error { + // 如果是none直接打一个log之后返回 + if viper.GetString("machine_registry.endpoint") == "none" { + logger.InfoLogger.Printf("Machine info: %+v", info) + return nil + } + var result Result + client := client.NewClient() + client.Post("/machine/info", info, nil, &result) + + if !result.Success { + panic("Failed to send machine info") + } + return nil +} diff --git a/backend-service/pkg/machine/info.go b/backend-service/pkg/machine/info.go new file mode 100644 index 0000000..175f557 --- /dev/null +++ b/backend-service/pkg/machine/info.go @@ -0,0 +1,131 @@ +package machine + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "runtime" + "strings" +) + +type Info struct { + Hostname string + OS string + Kernel string + CPU string + Memory string +} + +func CollectMachineInfo() *Info { + return &Info{ + Hostname: getHostname(), + OS: getOSInfo(), + Kernel: getKernelVersion(), + CPU: getCPUInfo(), + Memory: getMemoryInfo(), + } +} + +func getHostname() string { + name, err := os.Hostname() + if err != nil { + return "unknown" + } + return name +} + +func getOSInfo() string { + if runtime.GOOS == "linux" { + out, err := exec.Command("lsb_release", "-d").Output() + if err == nil { + parts := strings.Split(string(out), ":") + if len(parts) > 1 { + return strings.TrimSpace(parts[1]) + } + } + // 尝试读取 /etc/os-release + file, err := os.Open("/etc/os-release") + if err == nil { + defer file.Close() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "PRETTY_NAME=") { + return strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"") + } + } + } + } + return runtime.GOOS +} + +func getKernelVersion() string { + if runtime.GOOS == "linux" { + out, err := exec.Command("uname", "-r").Output() + if err == nil { + return strings.TrimSpace(string(out)) + } + } + return "unknown" +} + +func getCPUInfo() string { + if runtime.GOOS == "linux" { + out, err := exec.Command("lscpu").Output() + if err == nil { + return parseCPUInfo(string(out)) + } + } + return runtime.GOARCH +} + +func parseCPUInfo(output string) string { + scanner := bufio.NewScanner(strings.NewReader(output)) + var model, cores string + + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "Model name:") { + model = strings.TrimSpace(strings.Split(line, ":")[1]) + } + if strings.Contains(line, "CPU(s):") { + cores = strings.TrimSpace(strings.Split(line, ":")[1]) + } + } + + if model != "" && cores != "" { + return fmt.Sprintf("%s (%s cores)", model, cores) + } + return "unknown" +} + +func getMemoryInfo() string { + if runtime.GOOS == "linux" { + file, err := os.Open("/proc/meminfo") + if err == nil { + defer file.Close() + + scanner := bufio.NewScanner(file) + var totalMem, availMem string + + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "MemTotal:") { + totalMem = strings.TrimSpace(strings.TrimPrefix(line, "MemTotal:")) + } else if strings.HasPrefix(line, "MemAvailable:") { + availMem = strings.TrimSpace(strings.TrimPrefix(line, "MemAvailable:")) + } + + if totalMem != "" && availMem != "" { + break + } + } + + if totalMem != "" && availMem != "" { + return fmt.Sprintf("Total: %s, Available: %s", totalMem, availMem) + } + } + } + return "unknown" +} diff --git a/backend-service/pkg/service/configManager.go b/backend-service/pkg/service/configManager.go new file mode 100644 index 0000000..d53a5d7 --- /dev/null +++ b/backend-service/pkg/service/configManager.go @@ -0,0 +1,50 @@ +package service + +import ( + "context" + "time" + + "bash_go_service/config-loader/pkg/manager" + "bash_go_service/shared/pkg/constants" + "bash_go_service/shared/pkg/logger" +) + +// ConfigManagerTask 配置管理器任务 + +type ConfigManagerTask struct { + manager *manager.ConfigManager +} + +func NewConfigManagerTask() *ConfigManagerTask { + return &ConfigManagerTask{ + manager: manager.NewConfigManager(constants.ConfigFile, 5*time.Second), + } +} + +func (t *ConfigManagerTask) Execute(ctx context.Context) { + // 初始化配置管理器 + if err := t.manager.Initialize(); err != nil { + logger.Error("Failed to initialize config manager: %v", err) + return + } + + // 启动配置监控 + t.manager.StartWatching() + + // 等待上下文取消 + <-ctx.Done() + + // 停止配置管理器 + t.manager.Stop() + + // 清理共享内存 + if err := t.manager.ClearSharedMemory(); err != nil { + logger.Error("Failed to clear shared memory: %v", err) + } + + logger.Info("Config manager task stopped") +} + +func (t *ConfigManagerTask) Name() string { + return "ConfigManagerTask" +} diff --git a/backend-service/pkg/service/service.go b/backend-service/pkg/service/service.go new file mode 100644 index 0000000..4dc1cea --- /dev/null +++ b/backend-service/pkg/service/service.go @@ -0,0 +1,110 @@ +package service + +import ( + "context" + "fmt" + "os" + "os/signal" + "sync" + "syscall" + + "bash_go_service/shared/pkg/logger" +) + +const ( + lockFile = "/tmp/bash_service.lock" +) + +// Task 接口定义后台任务 +type Task interface { + Execute(ctx context.Context) + Name() string +} + +// WorkerPool 工作池结构体 +type WorkerPool struct { + tasks []Task + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup +} + +// NewWorkerPool 创建工作池 +func NewWorkerPool(tasks []Task) *WorkerPool { + ctx, cancel := context.WithCancel(context.Background()) + return &WorkerPool{ + tasks: tasks, + ctx: ctx, + cancel: cancel, + } +} + +// Start 启动工作池中的所有任务 +func (wp *WorkerPool) Start() { + for _, task := range wp.tasks { + wp.wg.Add(1) + go func(t Task) { + defer wp.wg.Done() + logger.Info("Starting task: %s", t.Name()) + t.Execute(wp.ctx) + }(task) + } +} + +// Stop 停止所有任务 +func (wp *WorkerPool) Stop() { + wp.cancel() + wp.wg.Wait() +} + +// Service 服务结构体 +type Service struct { + workerPool *WorkerPool +} + +// NewService 创建服务实例 +func NewService() *Service { + tasks := []Task{ + NewConfigManagerTask(), // 添加配置管理器任务 + } + + return &Service{ + workerPool: NewWorkerPool(tasks), + } +} + +func CheckExistingInstance() bool { + if data, err := os.ReadFile(lockFile); err == nil { + existingPid := string(data) + logger.Debug("Found existing instance with PID: %s", existingPid) + return true + } + + pid := os.Getpid() + os.WriteFile(lockFile, []byte(fmt.Sprintf("%d", pid)), 0644) + logger.Debug("Created new lock file with PID: %d", pid) + return false +} + +func Run() { + service := NewService() + + // 信号处理 + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + + // 启动所有任务 + service.workerPool.Start() + + // 等待信号 + sig := <-sigChan + logger.Info("Received signal: %v", sig) + + // 停止所有任务 + service.workerPool.Stop() + cleanup() +} + +func cleanup() { + os.Remove(lockFile) +} diff --git a/config-loader/cmd/manager/main.go b/config-loader/cmd/manager/main.go index 88acf54..80c92c7 100644 --- a/config-loader/cmd/manager/main.go +++ b/config-loader/cmd/manager/main.go @@ -6,8 +6,8 @@ import ( "syscall" "time" - "bash_go_service/config-loader/internal/constants" - "bash_go_service/config-loader/internal/manager" + "bash_go_service/config-loader/pkg/manager" + "bash_go_service/shared/pkg/constants" "bash_go_service/shared/pkg/logger" ) diff --git a/config-loader/internal/models/config.go b/config-loader/internal/models/config.go index cb9f0bf..bcb88cb 100644 --- a/config-loader/internal/models/config.go +++ b/config-loader/internal/models/config.go @@ -1,6 +1,6 @@ package models -import "bash_go_service/config-loader/internal/constants" +import "bash_go_service/shared/pkg/constants" // Rule 映射 C 结构体 type Rule struct { diff --git a/config-loader/internal/shm/shm.go b/config-loader/internal/shm/shm.go index a585885..9a3507c 100644 --- a/config-loader/internal/shm/shm.go +++ b/config-loader/internal/shm/shm.go @@ -4,8 +4,8 @@ import ( "fmt" "unsafe" - "bash_go_service/config-loader/internal/constants" "bash_go_service/config-loader/internal/models" + "bash_go_service/shared/pkg/constants" "bash_go_service/shared/pkg/logger" "golang.org/x/sys/unix" diff --git a/config-loader/internal/utils/config_loader.go b/config-loader/internal/utils/config_loader.go index c8ab871..e35883c 100644 --- a/config-loader/internal/utils/config_loader.go +++ b/config-loader/internal/utils/config_loader.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" - "bash_go_service/config-loader/internal/constants" "bash_go_service/config-loader/internal/models" + "bash_go_service/shared/pkg/constants" "bash_go_service/shared/pkg/logger" ) diff --git a/config-loader/internal/manager/config_manager.go b/config-loader/pkg/manager/config_manager.go similarity index 100% rename from config-loader/internal/manager/config_manager.go rename to config-loader/pkg/manager/config_manager.go diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..e7532e2 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,2 @@ +machine_registry: + endpoint: "http://localhost:9900" \ No newline at end of file diff --git a/config-loader/config/execve_rules.json b/config/execve_rules.json similarity index 100% rename from config-loader/config/execve_rules.json rename to config/execve_rules.json diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..6f7619f --- /dev/null +++ b/go.work.sum @@ -0,0 +1,56 @@ +cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= +cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +google.golang.org/api v0.215.0/go.mod h1:fta3CVtuJYOEdugLNWm6WodzOS8KdFckABwN4I40hzY= +google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/logs/2025-04-11.log b/logs/2025-04-11.log new file mode 100755 index 0000000..abeb4bf --- /dev/null +++ b/logs/2025-04-11.log @@ -0,0 +1,17 @@ +2025-04-11 20:19:02.230 [DEBUG ] logger.go:64 | Initializing... +2025-04-11 20:19:02.230 [DEBUG ] logger.go:64 | Starting daemon... +2025-04-11 20:19:02.230 [INFO ] logger.go:60 | Daemon started with PID: 1759543 +2025-04-11 20:19:02.231 [INFO ] logger.go:60 | Starting task: ConfigManagerTask +2025-04-11 20:19:02.231 [INFO ] config_manager.go:40 | Initializing ConfigManager +2025-04-11 20:19:02.231 [DEBUG ] shm.go:84 | Starting to read configuration from shared memory +2025-04-11 20:19:02.233 [INFO ] shm.go:109 | Configuration successfully read from shared memory +2025-04-11 20:19:02.233 [INFO ] config_manager.go:45 | Loaded existing configuration from shared memory. Enabled: true, Rule Count: 8 +2025-04-11 20:19:02.233 [INFO ] config_manager.go:65 | Started watching configuration file for changes +2025-04-11 20:19:07.236 [INFO ] config_manager.go:162 | Configuration file changed, reloading +2025-04-11 20:19:07.236 [DEBUG ] config_manager.go:107 | Loading configuration from file: ./config/execve_rules.json +2025-04-11 20:19:07.236 [DEBUG ] config_loader.go:13 | Loading config from file: ./config/execve_rules.json +2025-04-11 20:19:07.236 [INFO ] config_loader.go:55 | Configuration successfully loaded from file with skip rules added +2025-04-11 20:19:07.236 [DEBUG ] config_loader.go:60 | Converting JSON config to C config +2025-04-11 20:19:07.236 [INFO ] config_loader.go:86 | Successfully converted JSON config to C config +2025-04-11 20:19:07.236 [DEBUG ] shm.go:51 | Starting to write configuration to shared memory +2025-04-11 20:19:07.237 [INFO ] shm.go:78 | Configuration successfully written to shared memory diff --git a/shared/pkg/client/client.go b/shared/pkg/client/client.go new file mode 100644 index 0000000..c9a2c1e --- /dev/null +++ b/shared/pkg/client/client.go @@ -0,0 +1,230 @@ +package client + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/url" + "path" + + "bash_go_service/shared/pkg/constants" + "bash_go_service/shared/pkg/logger" +) + +type Client struct { + baseURL string + client *http.Client +} + +type ClientOption func(*Client) + +func WithBaseURL(baseURL string) ClientOption { + return func(c *Client) { + if baseURL != "" { + c.baseURL = baseURL + } + } +} + +func NewClient(opts ...ClientOption) *Client { + client := &Client{ + baseURL: constants.BaseUrl, // 默认使用环境变量 + client: &http.Client{ + Timeout: constants.ClientTimeout, + }, + } + + // 应用可选参数 + for _, opt := range opts { + opt(client) + } + + return client +} + +func (c *Client) Get(uri string, query map[string]string, result interface{}) error { + // 构建URL + u, err := url.Parse(c.baseURL) + if err != nil { + logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) + return err + } + u.Path = path.Join(u.Path, uri) + + // 添加query参数 + q := u.Query() + for k, v := range query { + q.Set(k, v) + } + u.RawQuery = q.Encode() + + // 发送请求 + resp, err := c.client.Get(u.String()) + if err != nil { + logger.ErrorLogger.Printf("GET request failed: %v", err) + return err + } + defer resp.Body.Close() + + // 读取响应 + body, err := io.ReadAll(resp.Body) + if err != nil { + logger.ErrorLogger.Printf("Failed to read response body: %v", err) + return err + } + + // 解析JSON + if err := json.Unmarshal(body, result); err != nil { + logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) + return err + } + + return nil +} + +func (c *Client) Post(uri string, body interface{}, query map[string]string, result interface{}) error { + // 构建URL + u, err := url.Parse(c.baseURL) + if err != nil { + logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) + return err + } + u.Path = path.Join(u.Path, uri) + + // 添加query参数(如果有) + if query != nil { + q := u.Query() + for k, v := range query { + q.Set(k, v) + } + u.RawQuery = q.Encode() + } + + // 序列化请求体 + payload, err := json.Marshal(body) + + if err != nil { + logger.ErrorLogger.Printf("Failed to marshal request body: %v", err) + return err + } + + // 发送请求 + resp, err := c.client.Post(u.String(), "application/json", bytes.NewBuffer(payload)) + if err != nil { + logger.ErrorLogger.Printf("POST request failed: %v", err) + return err + } + defer resp.Body.Close() + + // 读取响应 + respBody, err := io.ReadAll(resp.Body) + + logger.DebugLogger.Printf("Response body: %s", string(respBody)) + + if err != nil { + logger.ErrorLogger.Printf("Failed to read response body: %v", err) + return err + } + + // 解析JSON + if err := json.Unmarshal(respBody, result); err != nil { + logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) + return err + } + + return nil +} + +func (c *Client) Put(uri string, body interface{}, query map[string]string, result interface{}) error { + u, err := url.Parse(c.baseURL) + if err != nil { + logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) + return err + } + u.Path = path.Join(u.Path, uri) + + if query != nil { + q := u.Query() + for k, v := range query { + q.Set(k, v) + } + u.RawQuery = q.Encode() + } + + payload, err := json.Marshal(body) + if err != nil { + logger.ErrorLogger.Printf("Failed to marshal request body: %v", err) + return err + } + + req, err := http.NewRequest(http.MethodPut, u.String(), bytes.NewBuffer(payload)) + if err != nil { + logger.ErrorLogger.Printf("Failed to create PUT request: %v", err) + return err + } + req.Header.Set("Content-Type", "application/json") + + resp, err := c.client.Do(req) + if err != nil { + logger.ErrorLogger.Printf("PUT request failed: %v", err) + return err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + logger.ErrorLogger.Printf("Failed to read response body: %v", err) + return err + } + + if err := json.Unmarshal(respBody, result); err != nil { + logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) + return err + } + + return nil +} + +func (c *Client) Delete(uri string, query map[string]string, result interface{}) error { + u, err := url.Parse(c.baseURL) + if err != nil { + logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) + return err + } + u.Path = path.Join(u.Path, uri) + + if query != nil { + q := u.Query() + for k, v := range query { + q.Set(k, v) + } + u.RawQuery = q.Encode() + } + + req, err := http.NewRequest(http.MethodDelete, u.String(), nil) + if err != nil { + logger.ErrorLogger.Printf("Failed to create DELETE request: %v", err) + return err + } + + resp, err := c.client.Do(req) + if err != nil { + logger.ErrorLogger.Printf("DELETE request failed: %v", err) + return err + } + defer resp.Body.Close() + + respBody, err := io.ReadAll(resp.Body) + if err != nil { + logger.ErrorLogger.Printf("Failed to read response body: %v", err) + return err + } + + if err := json.Unmarshal(respBody, result); err != nil { + logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) + return err + } + + return nil +} diff --git a/shared/pkg/constants/colors.go b/shared/pkg/constants/colors.go new file mode 100644 index 0000000..c0af954 --- /dev/null +++ b/shared/pkg/constants/colors.go @@ -0,0 +1,13 @@ +package constants + +const ( + ColorRed = "\033[31m" + ColorGreen = "\033[32m" + ColorYellow = "\033[33m" + ColorBlue = "\033[34m" + ColorPurple = "\033[35m" + ColorCyan = "\033[36m" + ColorGray = "\033[37m" + ColorReset = "\033[0m" + ColorBold = "\033[1m" +) diff --git a/config-loader/internal/constants/constants.go b/shared/pkg/constants/constants.go similarity index 59% rename from config-loader/internal/constants/constants.go rename to shared/pkg/constants/constants.go index f848199..af9f94c 100644 --- a/config-loader/internal/constants/constants.go +++ b/shared/pkg/constants/constants.go @@ -10,4 +10,11 @@ const ( ShmKey = 0x78945 // 共享内存的键值 ShmSize = 512 * 1024 // 共享内存的大小(字节) ConfigFile = "./config/execve_rules.json" // 配置文件路径 + PidFilePath = "/tmp/bash_service.pid" // PID 文件路径 + DaemonFlag = "-daemon" // 后台进程标志 + ConfigFileMode = 0644 // 文件权限 + ConfigPath = "./config" // 配置文件路径 + LogFileMode = 0755 // 日志文件权限 + LogFilePath = "./logs" // 日志文件路径 + LogNameFormate = "%Y-%m-%d.log" // 日志文件名称格式 ) diff --git a/shared/pkg/constants/server.go b/shared/pkg/constants/server.go new file mode 100644 index 0000000..21e1970 --- /dev/null +++ b/shared/pkg/constants/server.go @@ -0,0 +1,8 @@ +package constants + +import "time" + +const ( + BaseUrl = "http://localhost:9956" + ClientTimeout = 30 * time.Second +) diff --git a/shared/pkg/logger/logger.go b/shared/pkg/logger/logger.go index b2d1de3..d1e0330 100644 --- a/shared/pkg/logger/logger.go +++ b/shared/pkg/logger/logger.go @@ -1,83 +1,73 @@ package logger import ( - "fmt" - "log" - "os" - "path/filepath" - "runtime" - "time" -) + "fmt" + "log" + "os" + "path/filepath" + "runtime" + "time" -const ( - colorRed = "\033[31m" - colorGreen = "\033[32m" - colorYellow = "\033[33m" - colorBlue = "\033[34m" - colorPurple = "\033[35m" - colorCyan = "\033[36m" - colorGray = "\033[37m" - colorReset = "\033[0m" - colorBold = "\033[1m" + "bash_go_service/shared/pkg/constants" ) var ( - InfoLogger *log.Logger - DebugLogger *log.Logger - ErrorLogger *log.Logger - WarningLogger *log.Logger + InfoLogger *log.Logger + DebugLogger *log.Logger + ErrorLogger *log.Logger + WarningLogger *log.Logger ) type LogWriter struct { - prefix string - color string + prefix string + color string } func (w *LogWriter) Write(p []byte) (n int, err error) { - // 获取调用信息 - _, file, line, ok := runtime.Caller(3) // 调整调用深度 - if !ok { - file = "???" - line = 0 - } - - // 获取短文件名 - filename := filepath.Base(file) - - // 当前时间 - now := time.Now().Format("2006-01-02 15:04:05.000") - - // 构建日志前缀 - logPrefix := fmt.Sprintf("%s%s%s [%s%-7s%s] %s%s:%d%s | ", - colorGray, now, colorReset, - w.color, w.prefix, colorReset, - colorBold, filename, line, colorReset, - ) - - // 写入完整日志 - return os.Stdout.Write([]byte(logPrefix + string(p))) + // 获取调用信息 + _, file, line, ok := runtime.Caller(3) // 调整调用深度 + if !ok { + file = "???" + line = 0 + } + + // 获取短文件名 + filename := filepath.Base(file) + + // 当前时间 + now := time.Now().Format("2006-01-02 15:04:05.000") + + // 构建日志前缀 + logPrefix := fmt.Sprintf("%s%s%s [%s%-7s%s] %s%s:%d%s | ", + constants.ColorGray, now, constants.ColorReset, + w.color, w.prefix, constants.ColorReset, + constants.ColorBold, filename, line, constants.ColorReset, + ) + + // 写入完整日志 + return os.Stdout.Write([]byte(logPrefix + string(p))) } func init() { - InfoLogger = log.New(&LogWriter{prefix: "INFO", color: colorGreen}, "", 0) - DebugLogger = log.New(&LogWriter{prefix: "DEBUG", color: colorBlue}, "", 0) - ErrorLogger = log.New(&LogWriter{prefix: "ERROR", color: colorRed}, "", 0) - WarningLogger = log.New(&LogWriter{prefix: "WARN", color: colorYellow}, "", 0) + InfoLogger = log.New(&LogWriter{prefix: "INFO", color: constants.ColorGreen}, "", 0) + DebugLogger = log.New(&LogWriter{prefix: "DEBUG", color: constants.ColorBlue}, "", 0) + ErrorLogger = log.New(&LogWriter{prefix: "ERROR", color: constants.ColorRed}, "", 0) + WarningLogger = log.New(&LogWriter{prefix: "WARN", color: constants.ColorYellow}, "", 0) } // 辅助函数封装 func Info(format string, v ...interface{}) { - InfoLogger.Printf(format, v...) + InfoLogger.Printf(format, v...) } func Debug(format string, v ...interface{}) { - DebugLogger.Printf(format, v...) + DebugLogger.Printf(format, v...) } func Error(format string, v ...interface{}) { - ErrorLogger.Printf(format, v...) + ErrorLogger.Printf(format, v...) } func Warn(format string, v ...interface{}) { - WarningLogger.Printf(format, v...) + WarningLogger.Printf(format, v...) } diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..aa9404d --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,10 @@ +module tests + +go 1.24.2 + +require ( + bash_go_service/shared v0.0.0-00010101000000-000000000000 + golang.org/x/sys v0.15.0 +) + +replace bash_go_service/shared => ../shared \ No newline at end of file diff --git a/tests/testcase/http/http.go b/tests/testcase/http/http.go new file mode 100644 index 0000000..1cdc8a5 --- /dev/null +++ b/tests/testcase/http/http.go @@ -0,0 +1,44 @@ +package main + +import ( + "bash_go_service/shared/pkg/client" + "bash_go_service/shared/pkg/logger" +) + +type User struct { + ID int `json:"id"` + Name string `json:"name"` +} + +func main() { + client := client.NewClient(client.WithBaseURL("http://localhost:9956")) + + // GET请求 + var user User + err := client.Get("/users/1", map[string]string{"fields": "id,name"}, &user) + + if err != nil { + panic(err) + } + + // POST请求 + var newUser User + err = client.Post("/users", User{Name: "John"}, nil, &newUser) + + // 输出结果 + logger.InfoLogger.Printf("User: %+v", newUser) + + // PUT请求 + var updatedUser User + err = client.Put("/users/1", User{Name: "Jane"}, nil, &updatedUser) + + // 输出结果 + logger.InfoLogger.Printf("Updated User: %+v", updatedUser) + + // DELETE请求 + var deletedUser User + err = client.Delete("/users/1", nil, &deletedUser) + + // 输出结果 + logger.InfoLogger.Printf("Deleted User: %+v", deletedUser) +}