多个模块,部分功能完成

This commit is contained in:
Pan Qiancheng 2025-04-11 20:23:09 +08:00
parent 53db7c174c
commit 866a1e35a2
23 changed files with 1016 additions and 58 deletions

198
backend-service/cmd/main.go Normal file
View File

@ -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)
}

View File

@ -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
)

36
backend-service/go.sum Normal file
View File

@ -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=

View File

@ -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
}

View File

@ -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"
}

View File

@ -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"
}

View File

@ -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)
}

View File

@ -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"
)

View File

@ -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 {

View File

@ -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"

View File

@ -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"
)

2
config/config.yaml Normal file
View File

@ -0,0 +1,2 @@
machine_registry:
endpoint: "http://localhost:9900"

56
go.work.sum Normal file
View File

@ -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=

17
logs/2025-04-11.log Executable file
View File

@ -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

230
shared/pkg/client/client.go Normal file
View File

@ -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
}

View File

@ -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"
)

View File

@ -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" // 日志文件名称格式
)

View File

@ -0,0 +1,8 @@
package constants
import "time"
const (
BaseUrl = "http://localhost:9956"
ClientTimeout = 30 * time.Second
)

View File

@ -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...)
}

10
tests/go.mod Normal file
View File

@ -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

View File

@ -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)
}