新增welcome模块,添加到service中,规范日志调用

This commit is contained in:
Pan Qiancheng 2025-04-11 23:58:50 +08:00
parent 866a1e35a2
commit cc33b9c94a
20 changed files with 545 additions and 68 deletions

View File

@ -28,11 +28,19 @@ func init() {
logger.Debug("Initializing...") logger.Debug("Initializing...")
if isDaemon() { if isDaemon() {
logger.Debug("Starting daemon...") logger.Debug("Starting daemon...")
err := checkExistingProcess()
if err != nil {
logger.Error("Error starting daemon.")
return
}
runDaemon() runDaemon()
} }
} }
func main() { func main() {
if isDaemon() {
return
}
if err := run(); err != nil { if err := run(); err != nil {
logger.Error("Application failed: %v", err) logger.Error("Application failed: %v", err)
os.Exit(1) os.Exit(1)

View File

@ -18,4 +18,10 @@ require (
golang.org/x/sys v0.29.0 // indirect golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
bash_go_service/shared v0.0.0-00010101000000-000000000000
bash_go_service/welcome v0.0.0-00010101000000-000000000000
) )
replace bash_go_service/shared => ../shared
replace bash_go_service/welcome => ../welcome

View File

@ -24,7 +24,7 @@ type Result struct {
func SendMachineInfo(info *machine.Info) error { func SendMachineInfo(info *machine.Info) error {
// 如果是none直接打一个log之后返回 // 如果是none直接打一个log之后返回
if viper.GetString("machine_registry.endpoint") == "none" { if viper.GetString("machine_registry.endpoint") == "none" {
logger.InfoLogger.Printf("Machine info: %+v", info) logger.Info("Machine info: %+v", info)
return nil return nil
} }
var result Result var result Result

View File

@ -66,6 +66,7 @@ type Service struct {
func NewService() *Service { func NewService() *Service {
tasks := []Task{ tasks := []Task{
NewConfigManagerTask(), // 添加配置管理器任务 NewConfigManagerTask(), // 添加配置管理器任务
NewWelcomeTask(),
} }
return &Service{ return &Service{

View File

@ -0,0 +1,56 @@
package service
import (
"context"
"os"
"os/signal"
"syscall"
"bash_go_service/shared/pkg/logger"
"bash_go_service/welcome/service"
)
// WelcomeTask 欢迎服务任务
type WelcomeTask struct {
service *welcome.Service
}
// NewWelcomeTask 创建欢迎服务任务实例
func NewWelcomeTask() *WelcomeTask {
return &WelcomeTask{}
}
// Execute 执行任务
func (t *WelcomeTask) Execute(ctx context.Context) {
// 初始化logger
// 创建welcome service
service, err := welcome.NewService()
if err != nil {
logger.Error("Failed to create welcome service:", err)
return
}
t.service = service
defer t.service.Stop()
// 启动服务
if err := t.service.Start(); err != nil {
logger.Error("Failed to start welcome service:", err)
return
}
// 等待上下文取消或中断信号
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
select {
case <-ctx.Done():
logger.Info("Context cancelled, shutting down welcome service...")
case sig := <-sigChan:
logger.Info("Received signal %v, shutting down welcome service...", sig)
}
}
// Name 返回任务名称
func (t *WelcomeTask) Name() string {
return "WelcomeTask"
}

View File

@ -17,7 +17,7 @@ func main() {
// Initialize the manager // Initialize the manager
if err := configManager.Initialize(); err != nil { if err := configManager.Initialize(); err != nil {
logger.ErrorLogger.Printf("Failed to initialize config manager: %v", err) logger.Error("Failed to initialize config manager: %v", err)
os.Exit(1) os.Exit(1)
} }
@ -28,17 +28,17 @@ func main() {
signalChan := make(chan os.Signal, 1) signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
logger.InfoLogger.Println("Configuration manager started. Press Ctrl+C to exit.") logger.Info("Configuration manager started. Press Ctrl+C to exit.")
// Wait for shutdown signal // Wait for shutdown signal
<-signalChan <-signalChan
logger.InfoLogger.Println("Shutdown signal received") logger.Info("Shutdown signal received")
// Clean up // Clean up
configManager.Stop() configManager.Stop()
if err := configManager.ClearSharedMemory(); err != nil { if err := configManager.ClearSharedMemory(); err != nil {
logger.ErrorLogger.Printf("Failed to clear shared memory: %v", err) logger.Error("Failed to clear shared memory: %v", err)
} }
logger.InfoLogger.Println("Configuration manager shutdown complete") logger.Info("Configuration manager shutdown complete")
} }

View File

@ -48,19 +48,19 @@ func shmdt(shmaddr unsafe.Pointer) error {
// WriteConfigToSharedMemory 将配置数据写入共享内存 // WriteConfigToSharedMemory 将配置数据写入共享内存
// config: 要写入的配置数据 // config: 要写入的配置数据
func WriteConfigToSharedMemory(config *models.ConfigData) error { func WriteConfigToSharedMemory(config *models.ConfigData) error {
logger.DebugLogger.Println("Starting to write configuration to shared memory") logger.Debug("Starting to write configuration to shared memory")
// 创建或获取共享内存段 // 创建或获取共享内存段
shmID, err := shmget(constants.ShmKey, constants.ShmSize, unix.IPC_CREAT|0666) shmID, err := shmget(constants.ShmKey, constants.ShmSize, unix.IPC_CREAT|0666)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("shmget failed: %v", err) logger.Error("shmget failed: %v", err)
return fmt.Errorf("shmget failed: %w", err) return fmt.Errorf("shmget failed: %w", err)
} }
// 将共享内存段附加到进程地址空间 // 将共享内存段附加到进程地址空间
shmPtr, err := shmat(shmID, 0, 0) shmPtr, err := shmat(shmID, 0, 0)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("shmat failed: %v", err) logger.Error("shmat failed: %v", err)
return fmt.Errorf("shmat failed: %w", err) return fmt.Errorf("shmat failed: %w", err)
} }
defer shmdt(shmPtr) // 确保在函数结束时分离共享内存 defer shmdt(shmPtr) // 确保在函数结束时分离共享内存
@ -75,13 +75,13 @@ func WriteConfigToSharedMemory(config *models.ConfigData) error {
data := (*[constants.ShmSize]byte)(unsafe.Pointer(config))[:] data := (*[constants.ShmSize]byte)(unsafe.Pointer(config))[:]
copy((*[constants.ShmSize]byte)(shmPtr)[:], data) copy((*[constants.ShmSize]byte)(shmPtr)[:], data)
logger.InfoLogger.Println("Configuration successfully written to shared memory") logger.Info("Configuration successfully written to shared memory")
return nil return nil
} }
// ReadConfigFromSharedMemory 从共享内存读取配置数据 // ReadConfigFromSharedMemory 从共享内存读取配置数据
func ReadConfigFromSharedMemory() (*models.ConfigData, error) { func ReadConfigFromSharedMemory() (*models.ConfigData, error) {
logger.DebugLogger.Println("Starting to read configuration from shared memory") logger.Debug("Starting to read configuration from shared memory")
// 获取共享内存段 // 获取共享内存段
shmID, err := shmget(constants.ShmKey, constants.ShmSize, 0) shmID, err := shmget(constants.ShmKey, constants.ShmSize, 0)
@ -106,6 +106,6 @@ func ReadConfigFromSharedMemory() (*models.ConfigData, error) {
// 从共享内存复制数据到配置对象 // 从共享内存复制数据到配置对象
copy((*[constants.ShmSize]byte)(unsafe.Pointer(config))[:], (*[constants.ShmSize]byte)(shmPtr)[:]) copy((*[constants.ShmSize]byte)(unsafe.Pointer(config))[:], (*[constants.ShmSize]byte)(shmPtr)[:])
logger.InfoLogger.Println("Configuration successfully read from shared memory") logger.Info("Configuration successfully read from shared memory")
return config, nil return config, nil
} }

View File

@ -10,18 +10,18 @@ import (
) )
func LoadConfigFromFile(filename string) (*models.JSONConfig, error) { func LoadConfigFromFile(filename string) (*models.JSONConfig, error) {
logger.DebugLogger.Printf("Loading config from file: %s", filename) logger.Debug("Loading config from file: %s", filename)
data, err := os.ReadFile(filename) data, err := os.ReadFile(filename)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to read config file: %v", err) logger.Error("Failed to read config file: %v", err)
return nil, err return nil, err
} }
var config models.JSONConfig var config models.JSONConfig
err = json.Unmarshal(data, &config) err = json.Unmarshal(data, &config)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to unmarshal config: %v", err) logger.Error("Failed to unmarshal config: %v", err)
return nil, err return nil, err
} }
@ -52,12 +52,12 @@ func LoadConfigFromFile(filename string) (*models.JSONConfig, error) {
// 将规则添加到配置中 // 将规则添加到配置中
config.Rules = append(config.Rules, skipRules...) config.Rules = append(config.Rules, skipRules...)
logger.InfoLogger.Println("Configuration successfully loaded from file with skip rules added") logger.Info("Configuration successfully loaded from file with skip rules added")
return &config, nil return &config, nil
} }
func ConvertToCConfig(jsonConfig *models.JSONConfig) *models.ConfigData { func ConvertToCConfig(jsonConfig *models.JSONConfig) *models.ConfigData {
logger.DebugLogger.Println("Converting JSON config to C config") logger.Debug("Converting JSON config to C config")
cConfig := &models.ConfigData{ cConfig := &models.ConfigData{
Enabled: jsonConfig.Enabled, Enabled: jsonConfig.Enabled,
@ -66,7 +66,7 @@ func ConvertToCConfig(jsonConfig *models.JSONConfig) *models.ConfigData {
for i, rule := range jsonConfig.Rules { for i, rule := range jsonConfig.Rules {
if i >= constants.MaxRules { if i >= constants.MaxRules {
logger.WarningLogger.Printf("Exceeded maximum rules limit (%d)", constants.MaxRules) logger.Warn("Exceeded maximum rules limit (%d)", constants.MaxRules)
break break
} }
copy(cConfig.Rules[i].Cmd[:], rule.Cmd) copy(cConfig.Rules[i].Cmd[:], rule.Cmd)
@ -76,13 +76,13 @@ func ConvertToCConfig(jsonConfig *models.JSONConfig) *models.ConfigData {
for j, arg := range rule.Args { for j, arg := range rule.Args {
if j >= constants.MaxArgs { if j >= constants.MaxArgs {
logger.WarningLogger.Printf("Exceeded maximum arguments limit (%d) for rule %d", constants.MaxArgs, i) logger.Warn("Exceeded maximum arguments limit (%d) for rule %d", constants.MaxArgs, i)
break break
} }
copy(cConfig.Rules[i].Args[j][:], arg) copy(cConfig.Rules[i].Args[j][:], arg)
} }
} }
logger.InfoLogger.Println("Successfully converted JSON config to C config") logger.Info("Successfully converted JSON config to C config")
return cConfig return cConfig
} }

View File

@ -37,18 +37,18 @@ func NewConfigManager(configFile string, watchInterval time.Duration) *ConfigMan
// Initialize 加载初始配置并开始监控配置文件的变化 // Initialize 加载初始配置并开始监控配置文件的变化
func (cm *ConfigManager) Initialize() error { func (cm *ConfigManager) Initialize() error {
logger.InfoLogger.Println("Initializing ConfigManager") logger.Info("Initializing ConfigManager")
// 尝试从共享内存中读取现有配置 // 尝试从共享内存中读取现有配置
if config, err := shm.ReadConfigFromSharedMemory(); err == nil { if config, err := shm.ReadConfigFromSharedMemory(); err == nil {
cm.currentConfig = config cm.currentConfig = config
logger.InfoLogger.Printf("Loaded existing configuration from shared memory. Enabled: %v, Rule Count: %d", logger.Info("Loaded existing configuration from shared memory. Enabled: %v, Rule Count: %d",
config.Enabled, config.RuleCount) config.Enabled, config.RuleCount)
if config.RuleCount == 0 { if config.RuleCount == 0 {
cm.ForceSync() // 如果规则数量为 0强制同步配置 cm.ForceSync() // 如果规则数量为 0强制同步配置
} }
} else { } else {
logger.WarningLogger.Printf("Failed to read from shared memory: %v", err) logger.Warn("Failed to read from shared memory: %v", err)
// 如果从共享内存读取失败,则从文件加载 // 如果从共享内存读取失败,则从文件加载
if err := cm.syncFromFile(); err != nil { if err := cm.syncFromFile(); err != nil {
return fmt.Errorf("initial configuration load failed: %w", err) return fmt.Errorf("initial configuration load failed: %w", err)
@ -62,12 +62,12 @@ func (cm *ConfigManager) Initialize() error {
func (cm *ConfigManager) StartWatching() { func (cm *ConfigManager) StartWatching() {
cm.wg.Add(1) cm.wg.Add(1)
go cm.watchConfigFile() go cm.watchConfigFile()
logger.InfoLogger.Println("Started watching configuration file for changes") logger.Info("Started watching configuration file for changes")
} }
// Stop 优雅地停止配置管理器 // Stop 优雅地停止配置管理器
func (cm *ConfigManager) Stop() { func (cm *ConfigManager) Stop() {
logger.InfoLogger.Println("Stopping ConfigManager") logger.Info("Stopping ConfigManager")
close(cm.stopChan) close(cm.stopChan)
cm.wg.Wait() cm.wg.Wait()
} }
@ -81,13 +81,13 @@ func (cm *ConfigManager) GetCurrentConfig() *models.ConfigData {
// ForceSync 强制从文件重新加载配置 // ForceSync 强制从文件重新加载配置
func (cm *ConfigManager) ForceSync() error { func (cm *ConfigManager) ForceSync() error {
logger.InfoLogger.Println("Force syncing configuration from file") logger.Info("Force syncing configuration from file")
return cm.syncFromFile() return cm.syncFromFile()
} }
// ClearSharedMemory 清除共享内存中的配置 // ClearSharedMemory 清除共享内存中的配置
func (cm *ConfigManager) ClearSharedMemory() error { func (cm *ConfigManager) ClearSharedMemory() error {
logger.InfoLogger.Println("Clearing shared memory configuration") logger.Info("Clearing shared memory configuration")
// 这里可以实现实际的清除逻辑 // 这里可以实现实际的清除逻辑
// 当前仅写入一个空配置 // 当前仅写入一个空配置
emptyConfig := &models.ConfigData{ emptyConfig := &models.ConfigData{
@ -104,7 +104,7 @@ func (cm *ConfigManager) syncFromFile() error {
cm.mu.Lock() cm.mu.Lock()
defer cm.mu.Unlock() defer cm.mu.Unlock()
logger.DebugLogger.Printf("Loading configuration from file: %s", cm.configFile) logger.Debug("Loading configuration from file: %s", cm.configFile)
// 从文件加载 JSON 配置 // 从文件加载 JSON 配置
jsonConfig, err := utils.LoadConfigFromFile(cm.configFile) jsonConfig, err := utils.LoadConfigFromFile(cm.configFile)
@ -136,11 +136,11 @@ func (cm *ConfigManager) watchConfigFile() {
for { for {
select { select {
case <-cm.stopChan: case <-cm.stopChan:
logger.InfoLogger.Println("Stopping configuration file watcher") logger.Info("Stopping configuration file watcher")
return return
case <-ticker.C: case <-ticker.C:
if err := cm.checkAndReloadConfig(); err != nil { if err := cm.checkAndReloadConfig(); err != nil {
logger.ErrorLogger.Printf("Error checking/reloading config: %v", err) logger.Error("Error checking/reloading config: %v", err)
} }
} }
} }
@ -159,7 +159,7 @@ func (cm *ConfigManager) checkAndReloadConfig() error {
// 如果文件修改时间更新,则重新加载配置 // 如果文件修改时间更新,则重新加载配置
if fileInfo.ModTime().After(lastMod) { if fileInfo.ModTime().After(lastMod) {
logger.InfoLogger.Println("Configuration file changed, reloading") logger.Info("Configuration file changed, reloading")
return cm.syncFromFile() return cm.syncFromFile()
} }

View File

@ -3,4 +3,7 @@ go 1.24.2
use ( use (
./backend-service ./backend-service
./config-loader ./config-loader
./shared
./tests
./welcome
) )

View File

@ -15,3 +15,43 @@
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 [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.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 2025-04-11 20:19:07.237 [INFO ] shm.go:78 | Configuration successfully written to shared memory
2025-04-11 23:48:43.186 [DEBUG ] logger.go:64 | Initializing...
2025-04-11 23:48:43.186 [DEBUG ] logger.go:64 | Starting daemon...
2025-04-11 23:48:43.186 [INFO ] logger.go:60 | Daemon started with PID: 1837284
2025-04-11 23:48:43.186 [INFO ] logger.go:60 | Starting task: WelcomeTask
2025-04-11 23:48:43.186 [INFO ] logger.go:60 | Starting task: ConfigManagerTask
2025-04-11 23:48:43.186 [INFO ] config_manager.go:40 | Initializing ConfigManager
2025-04-11 23:48:43.186 [DEBUG ] shm.go:84 | Starting to read configuration from shared memory
2025-04-11 23:48:43.186 [INFO ] logger.go:60 | Service started
2025-04-11 23:48:43.188 [INFO ] shm.go:109 | Configuration successfully read from shared memory
2025-04-11 23:48:43.188 [INFO ] config_manager.go:45 | Loaded existing configuration from shared memory. Enabled: true, Rule Count: 8
2025-04-11 23:48:43.188 [INFO ] config_manager.go:65 | Started watching configuration file for changes
2025-04-11 23:48:44.187 [ERROR ] logger.go:68 | Error opening terminal /dev/pts/ptmx: open /dev/pts/ptmx: permission denied
2025-04-11 23:48:44.187 [INFO ] service.go:136 | Welcome message sent to /dev/pts/19
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/6
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/0
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/3
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/7
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/12
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/1
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/8
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/13
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/9
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/2
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/20
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/10
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/21
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/14
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/11
2025-04-11 23:48:44.188 [INFO ] service.go:136 | Welcome message sent to /dev/pts/15
2025-04-11 23:48:48.191 [INFO ] config_manager.go:162 | Configuration file changed, reloading
2025-04-11 23:48:48.191 [DEBUG ] config_manager.go:107 | Loading configuration from file: ./config/execve_rules.json
2025-04-11 23:48:48.191 [DEBUG ] config_loader.go:13 | Loading config from file: ./config/execve_rules.json
2025-04-11 23:48:48.191 [INFO ] config_loader.go:55 | Configuration successfully loaded from file with skip rules added
2025-04-11 23:48:48.191 [DEBUG ] config_loader.go:60 | Converting JSON config to C config
2025-04-11 23:48:48.192 [INFO ] config_loader.go:86 | Successfully converted JSON config to C config
2025-04-11 23:48:48.192 [DEBUG ] shm.go:51 | Starting to write configuration to shared memory
2025-04-11 23:48:48.192 [INFO ] shm.go:78 | Configuration successfully written to shared memory
2025-04-11 23:48:49.431 [INFO ] service.go:136 | Welcome message sent to /dev/pts/4
2025-04-11 23:48:52.535 [INFO ] service.go:136 | Welcome message sent to /dev/pts/5
2025-04-11 23:49:36.800 [INFO ] service.go:136 | Welcome message sent to /dev/pts/18

View File

@ -47,7 +47,7 @@ func (c *Client) Get(uri string, query map[string]string, result interface{}) er
// 构建URL // 构建URL
u, err := url.Parse(c.baseURL) u, err := url.Parse(c.baseURL)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) logger.Error("Failed to parse base URL: %v", err)
return err return err
} }
u.Path = path.Join(u.Path, uri) u.Path = path.Join(u.Path, uri)
@ -62,7 +62,7 @@ func (c *Client) Get(uri string, query map[string]string, result interface{}) er
// 发送请求 // 发送请求
resp, err := c.client.Get(u.String()) resp, err := c.client.Get(u.String())
if err != nil { if err != nil {
logger.ErrorLogger.Printf("GET request failed: %v", err) logger.Error("GET request failed: %v", err)
return err return err
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -70,13 +70,13 @@ func (c *Client) Get(uri string, query map[string]string, result interface{}) er
// 读取响应 // 读取响应
body, err := io.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to read response body: %v", err) logger.Error("Failed to read response body: %v", err)
return err return err
} }
// 解析JSON // 解析JSON
if err := json.Unmarshal(body, result); err != nil { if err := json.Unmarshal(body, result); err != nil {
logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) logger.Error("Failed to unmarshal response: %v", err)
return err return err
} }
@ -87,7 +87,7 @@ func (c *Client) Post(uri string, body interface{}, query map[string]string, res
// 构建URL // 构建URL
u, err := url.Parse(c.baseURL) u, err := url.Parse(c.baseURL)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) logger.Error("Failed to parse base URL: %v", err)
return err return err
} }
u.Path = path.Join(u.Path, uri) u.Path = path.Join(u.Path, uri)
@ -105,14 +105,14 @@ func (c *Client) Post(uri string, body interface{}, query map[string]string, res
payload, err := json.Marshal(body) payload, err := json.Marshal(body)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to marshal request body: %v", err) logger.Error("Failed to marshal request body: %v", err)
return err return err
} }
// 发送请求 // 发送请求
resp, err := c.client.Post(u.String(), "application/json", bytes.NewBuffer(payload)) resp, err := c.client.Post(u.String(), "application/json", bytes.NewBuffer(payload))
if err != nil { if err != nil {
logger.ErrorLogger.Printf("POST request failed: %v", err) logger.Error("POST request failed: %v", err)
return err return err
} }
defer resp.Body.Close() defer resp.Body.Close()
@ -120,16 +120,16 @@ func (c *Client) Post(uri string, body interface{}, query map[string]string, res
// 读取响应 // 读取响应
respBody, err := io.ReadAll(resp.Body) respBody, err := io.ReadAll(resp.Body)
logger.DebugLogger.Printf("Response body: %s", string(respBody)) logger.Debug("Response body: %s", string(respBody))
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to read response body: %v", err) logger.Error("Failed to read response body: %v", err)
return err return err
} }
// 解析JSON // 解析JSON
if err := json.Unmarshal(respBody, result); err != nil { if err := json.Unmarshal(respBody, result); err != nil {
logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) logger.Error("Failed to unmarshal response: %v", err)
return err return err
} }
@ -139,7 +139,7 @@ func (c *Client) Post(uri string, body interface{}, query map[string]string, res
func (c *Client) Put(uri string, body interface{}, query map[string]string, result interface{}) error { func (c *Client) Put(uri string, body interface{}, query map[string]string, result interface{}) error {
u, err := url.Parse(c.baseURL) u, err := url.Parse(c.baseURL)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) logger.Error("Failed to parse base URL: %v", err)
return err return err
} }
u.Path = path.Join(u.Path, uri) u.Path = path.Join(u.Path, uri)
@ -154,32 +154,32 @@ func (c *Client) Put(uri string, body interface{}, query map[string]string, resu
payload, err := json.Marshal(body) payload, err := json.Marshal(body)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to marshal request body: %v", err) logger.Error("Failed to marshal request body: %v", err)
return err return err
} }
req, err := http.NewRequest(http.MethodPut, u.String(), bytes.NewBuffer(payload)) req, err := http.NewRequest(http.MethodPut, u.String(), bytes.NewBuffer(payload))
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to create PUT request: %v", err) logger.Error("Failed to create PUT request: %v", err)
return err return err
} }
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("PUT request failed: %v", err) logger.Error("PUT request failed: %v", err)
return err return err
} }
defer resp.Body.Close() defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body) respBody, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to read response body: %v", err) logger.Error("Failed to read response body: %v", err)
return err return err
} }
if err := json.Unmarshal(respBody, result); err != nil { if err := json.Unmarshal(respBody, result); err != nil {
logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) logger.Error("Failed to unmarshal response: %v", err)
return err return err
} }
@ -189,7 +189,7 @@ func (c *Client) Put(uri string, body interface{}, query map[string]string, resu
func (c *Client) Delete(uri string, query map[string]string, result interface{}) error { func (c *Client) Delete(uri string, query map[string]string, result interface{}) error {
u, err := url.Parse(c.baseURL) u, err := url.Parse(c.baseURL)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to parse base URL: %v", err) logger.Error("Failed to parse base URL: %v", err)
return err return err
} }
u.Path = path.Join(u.Path, uri) u.Path = path.Join(u.Path, uri)
@ -204,25 +204,25 @@ func (c *Client) Delete(uri string, query map[string]string, result interface{})
req, err := http.NewRequest(http.MethodDelete, u.String(), nil) req, err := http.NewRequest(http.MethodDelete, u.String(), nil)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to create DELETE request: %v", err) logger.Error("Failed to create DELETE request: %v", err)
return err return err
} }
resp, err := c.client.Do(req) resp, err := c.client.Do(req)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("DELETE request failed: %v", err) logger.Error("DELETE request failed: %v", err)
return err return err
} }
defer resp.Body.Close() defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body) respBody, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
logger.ErrorLogger.Printf("Failed to read response body: %v", err) logger.Error("Failed to read response body: %v", err)
return err return err
} }
if err := json.Unmarshal(respBody, result); err != nil { if err := json.Unmarshal(respBody, result); err != nil {
logger.ErrorLogger.Printf("Failed to unmarshal response: %v", err) logger.Error("Failed to unmarshal response: %v", err)
return err return err
} }

View File

@ -10,4 +10,7 @@ const (
ColorGray = "\033[37m" ColorGray = "\033[37m"
ColorReset = "\033[0m" ColorReset = "\033[0m"
ColorBold = "\033[1m" ColorBold = "\033[1m"
// 样式
Bold = "\033[1m"
Underline = "\033[4m"
) )

View File

@ -0,0 +1,5 @@
package constants
const (
UtmpDir = "/dev/pts/"
)

View File

@ -12,10 +12,10 @@ import (
) )
var ( var (
InfoLogger *log.Logger infoLogger *log.Logger
DebugLogger *log.Logger debugLogger *log.Logger
ErrorLogger *log.Logger errorLogger *log.Logger
WarningLogger *log.Logger warningLogger *log.Logger
) )
type LogWriter struct { type LogWriter struct {
@ -25,7 +25,7 @@ type LogWriter struct {
func (w *LogWriter) Write(p []byte) (n int, err error) { func (w *LogWriter) Write(p []byte) (n int, err error) {
// 获取调用信息 // 获取调用信息
_, file, line, ok := runtime.Caller(3) // 调整调用深度 _, file, line, ok := runtime.Caller(4) // 调整调用深度
if !ok { if !ok {
file = "???" file = "???"
line = 0 line = 0
@ -49,25 +49,25 @@ func (w *LogWriter) Write(p []byte) (n int, err error) {
} }
func init() { func init() {
InfoLogger = log.New(&LogWriter{prefix: "INFO", color: constants.ColorGreen}, "", 0) infoLogger = log.New(&LogWriter{prefix: "INFO", color: constants.ColorGreen}, "", 0)
DebugLogger = log.New(&LogWriter{prefix: "DEBUG", color: constants.ColorBlue}, "", 0) debugLogger = log.New(&LogWriter{prefix: "DEBUG", color: constants.ColorBlue}, "", 0)
ErrorLogger = log.New(&LogWriter{prefix: "ERROR", color: constants.ColorRed}, "", 0) errorLogger = log.New(&LogWriter{prefix: "ERROR", color: constants.ColorRed}, "", 0)
WarningLogger = log.New(&LogWriter{prefix: "WARN", color: constants.ColorYellow}, "", 0) warningLogger = log.New(&LogWriter{prefix: "WARN", color: constants.ColorYellow}, "", 0)
} }
// 辅助函数封装 // 辅助函数封装
func Info(format string, v ...interface{}) { func Info(format string, v ...interface{}) {
InfoLogger.Printf(format, v...) infoLogger.Printf(format, v...)
} }
func Debug(format string, v ...interface{}) { func Debug(format string, v ...interface{}) {
DebugLogger.Printf(format, v...) debugLogger.Printf(format, v...)
} }
func Error(format string, v ...interface{}) { func Error(format string, v ...interface{}) {
ErrorLogger.Printf(format, v...) errorLogger.Printf(format, v...)
} }
func Warn(format string, v ...interface{}) { func Warn(format string, v ...interface{}) {
WarningLogger.Printf(format, v...) warningLogger.Printf(format, v...)
} }

View File

@ -26,19 +26,19 @@ func main() {
err = client.Post("/users", User{Name: "John"}, nil, &newUser) err = client.Post("/users", User{Name: "John"}, nil, &newUser)
// 输出结果 // 输出结果
logger.InfoLogger.Printf("User: %+v", newUser) logger.Info("User: %+v", newUser)
// PUT请求 // PUT请求
var updatedUser User var updatedUser User
err = client.Put("/users/1", User{Name: "Jane"}, nil, &updatedUser) err = client.Put("/users/1", User{Name: "Jane"}, nil, &updatedUser)
// 输出结果 // 输出结果
logger.InfoLogger.Printf("Updated User: %+v", updatedUser) logger.Info("Updated User: %+v", updatedUser)
// DELETE请求 // DELETE请求
var deletedUser User var deletedUser User
err = client.Delete("/users/1", nil, &deletedUser) err = client.Delete("/users/1", nil, &deletedUser)
// 输出结果 // 输出结果
logger.InfoLogger.Printf("Deleted User: %+v", deletedUser) logger.Info("Deleted User: %+v", deletedUser)
} }

View File

@ -0,0 +1,137 @@
package main
import (
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"github.com/fsnotify/fsnotify"
)
const (
utmpDir = "/dev/pts/"
// ANSI转义序列定义颜色
colorReset = "\033[0m"
colorRed = "\033[31m"
colorGreen = "\033[32m"
colorYellow = "\033[33m"
colorBlue = "\033[34m"
colorPurple = "\033[35m"
colorCyan = "\033[36m"
colorWhite = "\033[37m"
// 样式
bold = "\033[1m"
underline = "\033[4m"
)
func main() {
logFile, err := os.OpenFile("./welcome-service.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer logFile.Close()
log.SetOutput(logFile)
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
err = watcher.Add(utmpDir)
if err != nil {
log.Fatal(err)
}
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
checkExistingTerminals()
log.Println("Service started")
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Create == fsnotify.Create {
go handleNewTerminal(event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Printf("Watcher error: %v", err)
case sig := <-sigChan:
log.Printf("Received signal: %v", sig)
return
}
}
}
func checkExistingTerminals() {
entries, err := os.ReadDir(utmpDir)
if err != nil {
log.Printf("Error reading %s: %v", utmpDir, err)
return
}
for _, entry := range entries {
if !entry.IsDir() {
go handleNewTerminal(filepath.Join(utmpDir, entry.Name()))
}
}
}
func handleNewTerminal(path string) {
time.Sleep(time.Second)
f, err := os.OpenFile(path, os.O_WRONLY, 0)
if err != nil {
log.Printf("Error opening terminal %s: %v", path, err)
return
}
defer f.Close()
// 使用颜色和样式的欢迎信息
welcomeMsg := fmt.Sprintf(`
%s%s%s
%s%s Welcome to the System! %s
%s%s---------------------------------------- %s
%s%s Terminal: %s%s%-30s%s %s
%s%s Time: %s%s%-35s%s %s
%s%s%s
`,
bold, colorCyan, colorReset,
bold, colorCyan, colorReset,
bold, colorCyan, colorReset,
bold, colorCyan, colorGreen, underline, path, colorCyan, colorReset,
bold, colorCyan, colorYellow, underline, time.Now().Format("2006-01-02 15:04:05"), colorCyan, colorReset,
bold, colorCyan, colorReset,
)
// 写入欢迎信息
_, err = f.WriteString(welcomeMsg)
if err != nil {
log.Printf("Error writing to terminal %s: %v", path, err)
return
}
// 模拟按下回车键
_, err = f.Write([]byte{'\n'})
if err != nil {
log.Printf("Error sending newline to terminal %s: %v", path, err)
return
}
log.Printf("Welcome message sent to %s", path)
}

71
welcome-service.log Normal file
View File

@ -0,0 +1,71 @@
2025/04/11 23:18:24 Service started
2025/04/11 23:18:25 Error opening terminal /dev/pts/ptmx: open /dev/pts/ptmx: permission denied
2025/04/11 23:18:25 Welcome message sent to /dev/pts/20
2025/04/11 23:18:25 Welcome message sent to /dev/pts/19
2025/04/11 23:18:25 Welcome message sent to /dev/pts/6
2025/04/11 23:18:25 Welcome message sent to /dev/pts/7
2025/04/11 23:18:25 Welcome message sent to /dev/pts/9
2025/04/11 23:18:25 Welcome message sent to /dev/pts/18
2025/04/11 23:18:25 Welcome message sent to /dev/pts/2
2025/04/11 23:18:25 Welcome message sent to /dev/pts/14
2025/04/11 23:18:25 Welcome message sent to /dev/pts/13
2025/04/11 23:18:25 Welcome message sent to /dev/pts/3
2025/04/11 23:18:25 Welcome message sent to /dev/pts/1
2025/04/11 23:18:25 Welcome message sent to /dev/pts/11
2025/04/11 23:18:25 Welcome message sent to /dev/pts/15
2025/04/11 23:18:25 Welcome message sent to /dev/pts/21
2025/04/11 23:18:25 Welcome message sent to /dev/pts/10
2025/04/11 23:18:25 Welcome message sent to /dev/pts/12
2025/04/11 23:18:25 Welcome message sent to /dev/pts/8
2025/04/11 23:18:25 Welcome message sent to /dev/pts/0
2025/04/11 23:18:28 Welcome message sent to /dev/pts/4
2025/04/11 23:18:34 Welcome message sent to /dev/pts/5
2025/04/11 23:19:45 Welcome message sent to /dev/pts/22
2025/04/11 23:20:00 Welcome message sent to /dev/pts/5
2025/04/11 23:24:13 Received signal: interrupt
2025/04/11 23:24:14 Service started
2025/04/11 23:24:15 Error opening terminal /dev/pts/ptmx: open /dev/pts/ptmx: permission denied
2025/04/11 23:24:15 Welcome message sent to /dev/pts/9
2025/04/11 23:24:15 Welcome message sent to /dev/pts/15
2025/04/11 23:24:15 Welcome message sent to /dev/pts/19
2025/04/11 23:24:15 Welcome message sent to /dev/pts/0
2025/04/11 23:24:15 Welcome message sent to /dev/pts/3
2025/04/11 23:24:15 Welcome message sent to /dev/pts/7
2025/04/11 23:24:15 Welcome message sent to /dev/pts/6
2025/04/11 23:24:15 Welcome message sent to /dev/pts/1
2025/04/11 23:24:15 Welcome message sent to /dev/pts/10
2025/04/11 23:24:15 Welcome message sent to /dev/pts/8
2025/04/11 23:24:15 Welcome message sent to /dev/pts/21
2025/04/11 23:24:15 Welcome message sent to /dev/pts/18
2025/04/11 23:24:15 Welcome message sent to /dev/pts/11
2025/04/11 23:24:15 Welcome message sent to /dev/pts/4
2025/04/11 23:24:15 Welcome message sent to /dev/pts/2
2025/04/11 23:24:15 Welcome message sent to /dev/pts/13
2025/04/11 23:24:15 Welcome message sent to /dev/pts/12
2025/04/11 23:24:15 Welcome message sent to /dev/pts/20
2025/04/11 23:24:15 Welcome message sent to /dev/pts/14
2025/04/11 23:24:24 Welcome message sent to /dev/pts/5
2025/04/11 23:25:50 Received signal: interrupt
2025/04/11 23:25:51 Service started
2025/04/11 23:25:52 Welcome message sent to /dev/pts/11
2025/04/11 23:25:52 Welcome message sent to /dev/pts/18
2025/04/11 23:25:52 Welcome message sent to /dev/pts/4
2025/04/11 23:25:52 Welcome message sent to /dev/pts/10
2025/04/11 23:25:52 Error opening terminal /dev/pts/ptmx: open /dev/pts/ptmx: permission denied
2025/04/11 23:25:52 Welcome message sent to /dev/pts/15
2025/04/11 23:25:52 Welcome message sent to /dev/pts/6
2025/04/11 23:25:52 Welcome message sent to /dev/pts/2
2025/04/11 23:25:52 Welcome message sent to /dev/pts/1
2025/04/11 23:25:52 Welcome message sent to /dev/pts/7
2025/04/11 23:25:52 Welcome message sent to /dev/pts/5
2025/04/11 23:25:52 Welcome message sent to /dev/pts/0
2025/04/11 23:25:52 Welcome message sent to /dev/pts/8
2025/04/11 23:25:52 Welcome message sent to /dev/pts/20
2025/04/11 23:25:52 Welcome message sent to /dev/pts/21
2025/04/11 23:25:52 Welcome message sent to /dev/pts/3
2025/04/11 23:25:52 Welcome message sent to /dev/pts/19
2025/04/11 23:25:52 Welcome message sent to /dev/pts/9
2025/04/11 23:25:52 Welcome message sent to /dev/pts/14
2025/04/11 23:25:52 Welcome message sent to /dev/pts/12
2025/04/11 23:25:52 Welcome message sent to /dev/pts/13
2025/04/11 23:28:16 Received signal: interrupt

10
welcome/go.mod Normal file
View File

@ -0,0 +1,10 @@
module welcome
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

137
welcome/service/service.go Normal file
View File

@ -0,0 +1,137 @@
package welcome
import (
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"bash_go_service/shared/pkg/constants"
"bash_go_service/shared/pkg/logger"
"github.com/fsnotify/fsnotify"
)
type Service struct {
watcher *fsnotify.Watcher
sigChan chan os.Signal
stopChan chan struct{}
}
func NewService() (*Service, error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
return &Service{
watcher: watcher,
sigChan: make(chan os.Signal, 1),
stopChan: make(chan struct{}),
}, nil
}
func (s *Service) checkExistingTerminals() {
entries, err := os.ReadDir(constants.UtmpDir)
if err != nil {
logger.Error("Error reading %s: %v", constants.UtmpDir, err)
return
}
for _, entry := range entries {
if !entry.IsDir() {
go s.handleNewTerminal(filepath.Join(constants.UtmpDir, entry.Name()))
}
}
}
func (s *Service) Start() error {
err := s.watcher.Add(constants.UtmpDir)
if err != nil {
return err
}
signal.Notify(s.sigChan, syscall.SIGINT, syscall.SIGTERM)
s.checkExistingTerminals()
logger.Info("Service started")
go s.watch()
return nil
}
func (s *Service) Stop() {
close(s.stopChan)
s.watcher.Close()
signal.Stop(s.sigChan)
}
func (s *Service) watch() {
for {
select {
case event, ok := <-s.watcher.Events:
if !ok {
return
}
if event.Op&fsnotify.Create == fsnotify.Create {
go s.handleNewTerminal(event.Name)
}
case err, ok := <-s.watcher.Errors:
if !ok {
return
}
logger.Error("Watcher error: %v", err)
case sig := <-s.sigChan:
logger.Debug("Received signal: %v", sig)
return
case <-s.stopChan:
return
}
}
}
func (s *Service) handleNewTerminal(path string) {
time.Sleep(time.Second)
f, err := os.OpenFile(path, os.O_WRONLY, 0)
if err != nil {
logger.Error("Error opening terminal %s: %v", path, err)
return
}
defer f.Close()
welcomeMsg := fmt.Sprintf(`
%s%s%s
%s%s Welcome to the System! %s
%s%s---------------------------------------- %s
%s%s Terminal: %s%s%-30s%s %s
%s%s Time: %s%s%-35s%s %s
%s%s%s
`,
constants.Bold, constants.ColorCyan, constants.ColorReset,
constants.Bold, constants.ColorCyan, constants.ColorReset,
constants.Bold, constants.ColorCyan, constants.ColorReset,
constants.Bold, constants.ColorCyan, constants.ColorGreen, constants.Underline, path, constants.ColorCyan, constants.ColorReset,
constants.Bold, constants.ColorCyan, constants.ColorYellow, constants.Underline, time.Now().Format("2006-01-02 15:04:05"), constants.ColorCyan, constants.ColorReset,
constants.Bold, constants.ColorCyan, constants.ColorReset,
)
if _, err = f.WriteString(welcomeMsg); err != nil {
logger.Error("Error writing to terminal %s: %v", path, err)
return
}
if _, err = f.Write([]byte{'\n'}); err != nil {
logger.Error("Error sending newline to terminal %s: %v", path, err)
return
}
logger.Info("Welcome message sent to %s", path)
}