package services import ( "context" "fmt" "strings" "time" "lokideploy/models" "lokideploy/pkg/crypto" "lokideploy/repository" "lokideploy/utils" ) type HostService struct{} func NewHostService() *HostService { return &HostService{} } func (s *HostService) Create(name, hostIP string, port int, user, authType, password, privateKey, keyPhrase, os, arch, labels string) (*models.Host, error) { if port == 0 { port = 22 } host := models.Host{ ID: repository.GetDB().NextID("hosts"), Name: name, HostIP: hostIP, Port: port, User: user, AuthType: authType, OS: os, Arch: arch, Labels: labels, Status: "pending", CreatedAt: time.Now(), UpdatedAt: time.Now(), } if password != "" { enc, err := crypto.EncryptField(password) if err != nil { return nil, fmt.Errorf("密码加密失败: %w", err) } host.Password = enc } if privateKey != "" { enc, err := crypto.EncryptField(privateKey) if err != nil { return nil, fmt.Errorf("私钥加密失败: %w", err) } host.PrivateKey = enc } if keyPhrase != "" { enc, err := crypto.EncryptField(keyPhrase) if err != nil { return nil, fmt.Errorf("私钥口令加密失败: %w", err) } host.KeyPhrase = enc } db := repository.GetDB() db.Lock() db.Hosts = append(db.Hosts, host) db.Unlock() db.RequestSave() go s.Validate(host.ID) return &host, nil } func (s *HostService) Get(id uint) (*models.Host, error) { db := repository.GetDB() db.RLock() defer db.RUnlock() for i := range db.Hosts { if db.Hosts[i].ID == id { h := db.Hosts[i] return &h, nil } } return nil, utils.ErrNotFound } func (s *HostService) List(page, pageSize int) ([]models.Host, int64, error) { db := repository.GetDB() db.RLock() defer db.RUnlock() total := int64(len(db.Hosts)) start := (page - 1) * pageSize if start < 0 || start >= len(db.Hosts) { return []models.Host{}, total, nil } end := start + pageSize if end > len(db.Hosts) { end = len(db.Hosts) } result := make([]models.Host, end-start) copy(result, db.Hosts[start:end]) return result, total, nil } func (s *HostService) Update(id uint, updates map[string]interface{}) error { db := repository.GetDB() db.Lock() defer db.Unlock() for i := range db.Hosts { if db.Hosts[i].ID == id { if v, ok := updates["name"].(string); ok { db.Hosts[i].Name = v } if v, ok := updates["status"].(string); ok { db.Hosts[i].Status = v } if v, ok := updates["os"].(string); ok { db.Hosts[i].OS = v } if v, ok := updates["arch"].(string); ok { db.Hosts[i].Arch = v } db.Hosts[i].UpdatedAt = time.Now() db.RequestSave() return nil } } return utils.ErrNotFound } func (s *HostService) Delete(id uint) error { db := repository.GetDB() db.Lock() defer db.Unlock() for i, h := range db.Hosts { if h.ID == id { db.Hosts = append(db.Hosts[:i], db.Hosts[i+1:]...) db.RequestSave() return nil } } return utils.ErrNotFound } func (s *HostService) Validate(id uint) { host, err := s.Get(id) if err != nil { return } ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() password := host.Password if strings.HasPrefix(password, "ENC:") { password, _ = crypto.Decrypt(password[4:]) } client, err := NewSSHClient(host.HostIP, host.Port, host.User, password) if err != nil { s.Update(id, map[string]interface{}{"status": "error"}) return } defer client.Close() if info, err := client.GetHostInfo(ctx); err == nil { s.Update(id, map[string]interface{}{"status": "active", "os": info.OS, "arch": info.Arch}) } else { s.Update(id, map[string]interface{}{"status": "active"}) } } func (s *HostService) ExecuteCommand(id uint, command string) (string, string, error) { host, err := s.Get(id) if err != nil { return "", "", err } ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() password := host.Password if strings.HasPrefix(password, "ENC:") { password, _ = crypto.Decrypt(password[4:]) } client, err := NewSSHClient(host.HostIP, host.Port, host.User, password) if err != nil { return "", "", err } defer client.Close() return client.Execute(ctx, command) }