package vpn import ( "fmt" "os" "runtime" "syscall" "time" "vpn-client/internal/config" "vpn-client/internal/logger" "vpn-client/internal/wireguard" ) // Disconnect отключает VPN func Disconnect(logsDir string) error { // Загружаем состояние state, err := config.LoadState() if err != nil { return fmt.Errorf("ошибка загрузки состояния: %w", err) } if !state.Connected { return fmt.Errorf("VPN не подключен") } fmt.Printf("Отключение от '%s'...\n", state.ConfigName) // Логируем отключение var logFile string if state.ConfigType == "wireguard" { logFile = logger.GetLogPath(logsDir, "wireguard") } else if state.ConfigType == "vless" { logFile = logger.GetLogPath(logsDir, "vless") } if logFile != "" { logger.LogMessage(logFile, fmt.Sprintf("Начало отключения от '%s'", state.ConfigName)) } // Останавливаем процесс в зависимости от типа if state.ConfigType == "wireguard" { // Отключаем WireGuard if err := wireguard.Disconnect(state.Interface, logsDir); err != nil { fmt.Printf("%s Ошибка отключения WireGuard: %v\n", "⚠", err) } } else if state.ProcessPID > 0 { // Останавливаем процесс VLESS process, err := os.FindProcess(state.ProcessPID) if err == nil { if runtime.GOOS == "windows" { // На Windows используем taskkill process.Kill() } else { // На Unix используем SIGTERM process.Signal(syscall.SIGTERM) } // Ждем завершения процесса time.Sleep(1 * time.Second) if logFile != "" { logger.LogMessage(logFile, fmt.Sprintf("Отключено от '%s' (PID: %d)", state.ConfigName, state.ProcessPID)) } if state.LogFile != "" && logFile != "" { logger.LogMessage(logFile, fmt.Sprintf("Лог трафика сохранен: %s", state.LogFile)) } } } // Сбрасываем состояние newState := &config.ConnectionState{ Connected: false, ConfigName: "", ConfigType: "", StartTime: "", Interface: "", ProcessPID: 0, LogFile: "", } if err := config.SaveState(newState); err != nil { return fmt.Errorf("ошибка сохранения состояния: %w", err) } fmt.Println("✓ Отключено от VPN") return nil } // GetStatus возвращает текущий статус подключения func GetStatus() (*config.ConnectionState, error) { return config.LoadState() } // ShowStatus отображает детальный статус подключения func ShowStatus() error { state, err := GetStatus() if err != nil { return fmt.Errorf("ошибка получения статуса: %w", err) } if !state.Connected { fmt.Println("\n❌ VPN не подключен") return nil } fmt.Println("\n" + "==================================================") fmt.Println("📊 Статус VPN") fmt.Println("==================================================") fmt.Printf("Статус: ✓ Подключено\n") fmt.Printf("Конфиг: %s\n", state.ConfigName) fmt.Printf("Тип: %s\n", state.ConfigType) if state.StartTime != "" { startTime, err := time.Parse(time.RFC3339, state.StartTime) if err == nil { duration := time.Since(startTime) hours := int(duration.Hours()) minutes := int(duration.Minutes()) % 60 seconds := int(duration.Seconds()) % 60 fmt.Printf("Время подключения: %02d:%02d:%02d\n", hours, minutes, seconds) } } if state.ConfigType == "vless" { fmt.Printf("Прокси: 127.0.0.1:10808\n") if state.LogFile != "" { fmt.Printf("Лог трафика: %s\n", state.LogFile) } } else if state.ConfigType == "wireguard" { // Получаем статистику WireGuard stats, err := wireguard.GetStats(state.Interface) if err == nil { fmt.Printf("\nСтатистика трафика:\n") fmt.Printf(" Получено: %s\n", stats["rx"]) fmt.Printf(" Отправлено: %s\n", stats["tx"]) } } fmt.Println("==================================================") return nil }