Initial commit

This commit is contained in:
2026-04-05 20:33:30 +06:00
commit 83fbe7afdd
18 changed files with 3038 additions and 0 deletions

143
internal/vpn/vpn.go Normal file
View File

@@ -0,0 +1,143 @@
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
}