Files
Go-VPN-Client/internal/vpn/vpn.go
2026-04-05 20:33:30 +06:00

144 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}