865 lines
22 KiB
Go
865 lines
22 KiB
Go
package cli
|
||
|
||
import (
|
||
"bufio"
|
||
"fmt"
|
||
"os"
|
||
"os/exec"
|
||
"runtime"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"vpn-client/internal/config"
|
||
"vpn-client/internal/subscription"
|
||
"vpn-client/internal/vless"
|
||
"vpn-client/internal/vpn"
|
||
"vpn-client/internal/wireguard"
|
||
|
||
"github.com/fatih/color"
|
||
)
|
||
|
||
var (
|
||
green = color.New(color.FgGreen).SprintFunc()
|
||
red = color.New(color.FgRed).SprintFunc()
|
||
yellow = color.New(color.FgYellow).SprintFunc()
|
||
cyan = color.New(color.FgCyan).SprintFunc()
|
||
bold = color.New(color.Bold).SprintFunc()
|
||
)
|
||
|
||
// Run запускает CLI интерфейс
|
||
func Run() error {
|
||
for {
|
||
clearScreen()
|
||
showMainMenu()
|
||
|
||
choice := readInput("Выберите действие: ")
|
||
|
||
switch choice {
|
||
case "1":
|
||
wireguardMenu()
|
||
case "2":
|
||
vlessMenu()
|
||
case "3":
|
||
subscriptionsMenu()
|
||
case "4":
|
||
if err := vpn.ShowStatus(); err != nil {
|
||
fmt.Printf("%s %v\n", red("✗"), err)
|
||
}
|
||
pause()
|
||
case "5":
|
||
if err := vpn.Disconnect(config.LogsDir); err != nil {
|
||
fmt.Printf("%s %v\n", red("✗"), err)
|
||
}
|
||
pause()
|
||
case "0":
|
||
fmt.Println("До свидания!")
|
||
return nil
|
||
default:
|
||
fmt.Printf("%s Неверный выбор\n", red("✗"))
|
||
pause()
|
||
}
|
||
}
|
||
}
|
||
|
||
func showMainMenu() {
|
||
state, _ := vpn.GetStatus()
|
||
|
||
statusIcon := "○"
|
||
statusText := "Не подключено"
|
||
if state != nil && state.Connected {
|
||
statusIcon = "✓"
|
||
statusText = fmt.Sprintf("Подключено: %s", state.ConfigName)
|
||
}
|
||
|
||
fmt.Println("\n" + strings.Repeat("=", 50))
|
||
fmt.Println(bold("VPN Клиент (Go)"))
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
fmt.Printf("Статус: %s %s\n", statusIcon, statusText)
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
fmt.Println("1. WireGuard")
|
||
fmt.Println("2. VLESS")
|
||
fmt.Println("3. Управление подписками")
|
||
fmt.Println("4. Показать статус подключения")
|
||
fmt.Println("5. Отключиться от VPN")
|
||
fmt.Println("0. Выход")
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
}
|
||
|
||
func vlessMenu() {
|
||
for {
|
||
clearScreen()
|
||
fmt.Println("\n" + strings.Repeat("=", 50))
|
||
fmt.Println(bold("VLESS"))
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
fmt.Println("1. Список конфигураций")
|
||
fmt.Println("2. Добавить конфиг")
|
||
fmt.Println("3. Удалить конфиг")
|
||
fmt.Println("4. Подключиться")
|
||
fmt.Println("5. Тестировать конфиг (пинг)")
|
||
fmt.Println("0. Назад")
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
|
||
choice := readInput("\nВыберите действие: ")
|
||
|
||
switch choice {
|
||
case "0":
|
||
return
|
||
case "1":
|
||
listVLESSConfigs()
|
||
pause()
|
||
case "2":
|
||
addVLESSConfig()
|
||
pause()
|
||
case "3":
|
||
deleteVLESSConfig()
|
||
pause()
|
||
case "4":
|
||
connectVLESS()
|
||
pause()
|
||
case "5":
|
||
testVLESSConfig()
|
||
pause()
|
||
default:
|
||
fmt.Printf("%s Неверный выбор\n", red("✗"))
|
||
pause()
|
||
}
|
||
}
|
||
}
|
||
|
||
func listVLESSConfigs() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== VLESS конфиги ===")
|
||
if len(configs.VLESS) == 0 {
|
||
fmt.Println("Нет конфигов")
|
||
return
|
||
}
|
||
|
||
for i, cfg := range configs.VLESS {
|
||
protocol := cfg.Protocol
|
||
if protocol == "" {
|
||
protocol = "VLESS"
|
||
}
|
||
fmt.Printf("%d. [%s] %s\n", i+1, protocol, cfg.Name)
|
||
}
|
||
}
|
||
|
||
func addVLESSConfig() {
|
||
name := readInput("Имя конфига: ")
|
||
if name == "" {
|
||
fmt.Printf("%s Имя не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
vlessURL := readInput("VLESS URL: ")
|
||
if vlessURL == "" {
|
||
fmt.Printf("%s URL не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
configs.VLESS = append(configs.VLESS, config.VLESSConfig{
|
||
Name: name,
|
||
URL: vlessURL,
|
||
Protocol: "VLESS",
|
||
})
|
||
|
||
if err := config.SaveConfigs(configs); err != nil {
|
||
fmt.Printf("%s Ошибка сохранения конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s VLESS конфиг '%s' добавлен\n", green("✓"), name)
|
||
}
|
||
|
||
func deleteVLESSConfig() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(configs.VLESS) == 0 {
|
||
fmt.Println("Нет конфигов для удаления")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== VLESS конфиги ===")
|
||
for i, cfg := range configs.VLESS {
|
||
fmt.Printf("%d. %s\n", i+1, cfg.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер конфига для удаления: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(configs.VLESS) {
|
||
fmt.Printf("%s Неверный номер конфига\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
name := configs.VLESS[num-1].Name
|
||
configs.VLESS = append(configs.VLESS[:num-1], configs.VLESS[num:]...)
|
||
|
||
if err := config.SaveConfigs(configs); err != nil {
|
||
fmt.Printf("%s Ошибка сохранения конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s Конфиг '%s' удален\n", green("✓"), name)
|
||
}
|
||
|
||
func connectVLESS() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(configs.VLESS) == 0 {
|
||
fmt.Println("Нет конфигов для подключения")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== VLESS конфиги ===")
|
||
for i, cfg := range configs.VLESS {
|
||
protocol := cfg.Protocol
|
||
if protocol == "" {
|
||
protocol = "VLESS"
|
||
}
|
||
fmt.Printf("%d. [%s] %s\n", i+1, protocol, cfg.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер конфига для подключения: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(configs.VLESS) {
|
||
fmt.Printf("%s Неверный номер конфига\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
configName := configs.VLESS[num-1].Name
|
||
|
||
fmt.Printf("\nПодключение к '%s' через Xray...\n", configName)
|
||
|
||
if err := vless.Connect(configName, config.LogsDir, config.XrayDir); err != nil {
|
||
fmt.Printf("%s Ошибка подключения: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
}
|
||
|
||
func testVLESSConfig() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(configs.VLESS) == 0 {
|
||
fmt.Println("Нет конфигов для тестирования")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== VLESS конфиги ===")
|
||
for i, cfg := range configs.VLESS {
|
||
fmt.Printf("%d. %s\n", i+1, cfg.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер конфига для тестирования: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(configs.VLESS) {
|
||
fmt.Printf("%s Неверный номер конфига\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
cfg := configs.VLESS[num-1]
|
||
|
||
fmt.Printf("\nТестирование '%s'...\n", cfg.Name)
|
||
fmt.Println("Проверка доступности сервера...")
|
||
|
||
success, ping, err := vless.PingServer(cfg.URL, 5000000000) // 5 секунд
|
||
if err != nil || !success {
|
||
fmt.Printf("%s Сервер недоступен\n", red("✗"))
|
||
if err != nil {
|
||
fmt.Printf(" Ошибка: %v\n", err)
|
||
}
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s Сервер доступен\n", green("✓"))
|
||
fmt.Printf(" Пинг: %.2f мс\n", ping)
|
||
|
||
// Оценка качества
|
||
var quality string
|
||
if ping < 50 {
|
||
quality = green("Отлично")
|
||
} else if ping < 100 {
|
||
quality = cyan("Хорошо")
|
||
} else if ping < 200 {
|
||
quality = yellow("Средне")
|
||
} else {
|
||
quality = red("Плохо")
|
||
}
|
||
fmt.Printf(" Качество: %s\n", quality)
|
||
}
|
||
|
||
func subscriptionsMenu() {
|
||
for {
|
||
clearScreen()
|
||
fmt.Println("\n" + strings.Repeat("=", 50))
|
||
fmt.Println(bold("Управление подписками"))
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
fmt.Println("1. Список подписок")
|
||
fmt.Println("2. Добавить подписку")
|
||
fmt.Println("3. Удалить подписку")
|
||
fmt.Println("4. Обновить конфиги из подписки")
|
||
fmt.Println("5. Показать конфиги из подписки")
|
||
fmt.Println("6. Тестировать конфиги из подписки (пинг)")
|
||
fmt.Println("0. Назад")
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
|
||
choice := readInput("\nВыберите действие: ")
|
||
|
||
switch choice {
|
||
case "0":
|
||
return
|
||
case "1":
|
||
listSubscriptions()
|
||
pause()
|
||
case "2":
|
||
addSubscription()
|
||
pause()
|
||
case "3":
|
||
deleteSubscription()
|
||
pause()
|
||
case "4":
|
||
updateSubscription()
|
||
pause()
|
||
case "5":
|
||
showSubscriptionConfigs()
|
||
pause()
|
||
case "6":
|
||
testSubscriptionConfigs()
|
||
pause()
|
||
default:
|
||
fmt.Printf("%s Неверный выбор\n", red("✗"))
|
||
pause()
|
||
}
|
||
}
|
||
}
|
||
|
||
func listSubscriptions() {
|
||
subs, err := config.LoadSubscriptions()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Println("\nПодписки:")
|
||
if len(subs.Subscriptions) == 0 {
|
||
fmt.Println("Нет подписок")
|
||
return
|
||
}
|
||
|
||
for i, sub := range subs.Subscriptions {
|
||
fmt.Printf("%d. %s - %s\n", i+1, sub.Name, sub.URL)
|
||
}
|
||
}
|
||
|
||
func addSubscription() {
|
||
name := readInput("Имя подписки: ")
|
||
if name == "" {
|
||
fmt.Printf("%s Имя не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
url := readInput("URL подписки: ")
|
||
if url == "" {
|
||
fmt.Printf("%s URL не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
subs, err := config.LoadSubscriptions()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
subs.Subscriptions = append(subs.Subscriptions, config.Subscription{
|
||
Name: name,
|
||
URL: url,
|
||
})
|
||
|
||
if err := config.SaveSubscriptions(subs); err != nil {
|
||
fmt.Printf("%s Ошибка сохранения подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s Подписка '%s' добавлена\n", green("✓"), name)
|
||
}
|
||
|
||
func deleteSubscription() {
|
||
subs, err := config.LoadSubscriptions()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(subs.Subscriptions) == 0 {
|
||
fmt.Println("Нет подписок для удаления")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\nПодписки:")
|
||
for i, sub := range subs.Subscriptions {
|
||
fmt.Printf("%d. %s\n", i+1, sub.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер подписки для удаления: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(subs.Subscriptions) {
|
||
fmt.Printf("%s Неверный номер подписки\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
name := subs.Subscriptions[num-1].Name
|
||
subs.Subscriptions = append(subs.Subscriptions[:num-1], subs.Subscriptions[num:]...)
|
||
|
||
if err := config.SaveSubscriptions(subs); err != nil {
|
||
fmt.Printf("%s Ошибка сохранения подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s Подписка '%s' удалена\n", green("✓"), name)
|
||
}
|
||
|
||
func updateSubscription() {
|
||
subs, err := config.LoadSubscriptions()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(subs.Subscriptions) == 0 {
|
||
fmt.Println("Нет подписок")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\nПодписки:")
|
||
for i, sub := range subs.Subscriptions {
|
||
fmt.Printf("%d. %s\n", i+1, sub.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер подписки для обновления: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(subs.Subscriptions) {
|
||
fmt.Printf("%s Неверный номер подписки\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
name := subs.Subscriptions[num-1].Name
|
||
|
||
if err := subscription.UpdateSubscription(name, config.LogsDir); err != nil {
|
||
fmt.Printf("%s Ошибка обновления: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
}
|
||
|
||
func showSubscriptionConfigs() {
|
||
subs, err := config.LoadSubscriptions()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(subs.Subscriptions) == 0 {
|
||
fmt.Println("Нет подписок")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\nПодписки:")
|
||
for i, sub := range subs.Subscriptions {
|
||
fmt.Printf("%d. %s\n", i+1, sub.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер подписки: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(subs.Subscriptions) {
|
||
fmt.Printf("%s Неверный номер подписки\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
subName := subs.Subscriptions[num-1].Name
|
||
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("\n=== Конфиги из подписки '%s' ===\n", subName)
|
||
count := 0
|
||
for _, cfg := range configs.VLESS {
|
||
if cfg.Subscription == subName {
|
||
count++
|
||
protocol := cfg.Protocol
|
||
if protocol == "" {
|
||
protocol = "Unknown"
|
||
}
|
||
displayName := strings.TrimPrefix(cfg.Name, fmt.Sprintf("[%s] ", subName))
|
||
fmt.Printf("%d. [%s] %s\n", count, protocol, displayName)
|
||
}
|
||
}
|
||
|
||
if count == 0 {
|
||
fmt.Println("Нет конфигов из этой подписки")
|
||
fmt.Println("Сначала обновите конфиги из подписки (пункт 4)")
|
||
}
|
||
}
|
||
|
||
func testSubscriptionConfigs() {
|
||
subs, err := config.LoadSubscriptions()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки подписок: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(subs.Subscriptions) == 0 {
|
||
fmt.Println("Нет подписок")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\nПодписки:")
|
||
for i, sub := range subs.Subscriptions {
|
||
fmt.Printf("%d. %s\n", i+1, sub.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер подписки: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(subs.Subscriptions) {
|
||
fmt.Printf("%s Неверный номер подписки\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
subName := subs.Subscriptions[num-1].Name
|
||
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
var subConfigs []config.VLESSConfig
|
||
for _, cfg := range configs.VLESS {
|
||
if cfg.Subscription == subName {
|
||
subConfigs = append(subConfigs, cfg)
|
||
}
|
||
}
|
||
|
||
if len(subConfigs) == 0 {
|
||
fmt.Println("Нет конфигов из этой подписки")
|
||
return
|
||
}
|
||
|
||
fmt.Printf("\n=== Тестирование конфигов из '%s' ===\n", subName)
|
||
fmt.Printf("Найдено конфигов: %d\n\n", len(subConfigs))
|
||
|
||
type result struct {
|
||
name string
|
||
protocol string
|
||
ping float64
|
||
success bool
|
||
}
|
||
|
||
var results []result
|
||
|
||
for i, cfg := range subConfigs {
|
||
protocol := cfg.Protocol
|
||
if protocol == "" {
|
||
protocol = "Unknown"
|
||
}
|
||
displayName := strings.TrimPrefix(cfg.Name, fmt.Sprintf("[%s] ", subName))
|
||
|
||
fmt.Printf("%d/%d Тестирование [%s] %s...", i+1, len(subConfigs), protocol, truncate(displayName, 50))
|
||
|
||
success, ping, _ := vless.PingServer(cfg.URL, 3000000000) // 3 секунды
|
||
|
||
if success {
|
||
fmt.Printf(" %s %.2f мс\n", green("✓"), ping)
|
||
results = append(results, result{
|
||
name: displayName,
|
||
protocol: protocol,
|
||
ping: ping,
|
||
success: true,
|
||
})
|
||
} else {
|
||
fmt.Printf(" %s Недоступен\n", red("✗"))
|
||
results = append(results, result{
|
||
name: displayName,
|
||
protocol: protocol,
|
||
success: false,
|
||
})
|
||
}
|
||
}
|
||
|
||
// Сортируем по пингу
|
||
var successful []result
|
||
var failed []result
|
||
for _, r := range results {
|
||
if r.success {
|
||
successful = append(successful, r)
|
||
} else {
|
||
failed = append(failed, r)
|
||
}
|
||
}
|
||
|
||
// Простая сортировка пузырьком
|
||
for i := 0; i < len(successful); i++ {
|
||
for j := i + 1; j < len(successful); j++ {
|
||
if successful[i].ping > successful[j].ping {
|
||
successful[i], successful[j] = successful[j], successful[i]
|
||
}
|
||
}
|
||
}
|
||
|
||
fmt.Println("\n" + strings.Repeat("=", 60))
|
||
fmt.Println("РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ")
|
||
fmt.Println(strings.Repeat("=", 60))
|
||
|
||
if len(successful) > 0 {
|
||
fmt.Printf("\n%s Доступно: %d\n", green("✓"), len(successful))
|
||
fmt.Println("\nЛучшие серверы:")
|
||
for i, r := range successful {
|
||
if i >= 5 {
|
||
break
|
||
}
|
||
fmt.Printf(" %d. [%s] %s - %.2f мс\n", i+1, r.protocol, truncate(r.name, 35), r.ping)
|
||
}
|
||
}
|
||
|
||
if len(failed) > 0 {
|
||
fmt.Printf("\n%s Недоступно: %d\n", red("✗"), len(failed))
|
||
}
|
||
|
||
fmt.Println(strings.Repeat("=", 60))
|
||
}
|
||
|
||
func clearScreen() {
|
||
if runtime.GOOS == "windows" {
|
||
cmd := exec.Command("cmd", "/c", "cls")
|
||
cmd.Stdout = os.Stdout
|
||
cmd.Run()
|
||
} else {
|
||
cmd := exec.Command("clear")
|
||
cmd.Stdout = os.Stdout
|
||
cmd.Run()
|
||
}
|
||
}
|
||
|
||
func readInput(prompt string) string {
|
||
fmt.Print(prompt)
|
||
reader := bufio.NewReader(os.Stdin)
|
||
input, _ := reader.ReadString('\n')
|
||
return strings.TrimSpace(input)
|
||
}
|
||
|
||
func pause() {
|
||
fmt.Print("\nНажмите Enter для продолжения...")
|
||
bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||
}
|
||
|
||
func truncate(s string, maxLen int) string {
|
||
if len(s) <= maxLen {
|
||
return s
|
||
}
|
||
return s[:maxLen] + "..."
|
||
}
|
||
|
||
|
||
func wireguardMenu() {
|
||
for {
|
||
clearScreen()
|
||
fmt.Println("\n" + strings.Repeat("=", 50))
|
||
fmt.Println(bold("WireGuard"))
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
fmt.Println("1. Список конфигураций")
|
||
fmt.Println("2. Добавить конфиг (вручную)")
|
||
fmt.Println("3. Добавить конфиг (из файла)")
|
||
fmt.Println("4. Удалить конфиг")
|
||
fmt.Println("5. Подключиться")
|
||
fmt.Println("0. Назад")
|
||
fmt.Println(strings.Repeat("=", 50))
|
||
|
||
choice := readInput("\nВыберите действие: ")
|
||
|
||
switch choice {
|
||
case "0":
|
||
return
|
||
case "1":
|
||
listWireGuardConfigs()
|
||
pause()
|
||
case "2":
|
||
addWireGuardConfigManual()
|
||
pause()
|
||
case "3":
|
||
addWireGuardConfigFromFile()
|
||
pause()
|
||
case "4":
|
||
deleteWireGuardConfig()
|
||
pause()
|
||
case "5":
|
||
connectWireGuard()
|
||
pause()
|
||
default:
|
||
fmt.Printf("%s Неверный выбор\n", red("✗"))
|
||
pause()
|
||
}
|
||
}
|
||
}
|
||
|
||
func listWireGuardConfigs() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== WireGuard конфиги ===")
|
||
if len(configs.WireGuard) == 0 {
|
||
fmt.Println("Нет конфигов")
|
||
return
|
||
}
|
||
|
||
for i, cfg := range configs.WireGuard {
|
||
fmt.Printf("%d. %s\n", i+1, cfg.Name)
|
||
}
|
||
}
|
||
|
||
func addWireGuardConfigManual() {
|
||
name := readInput("Имя конфига: ")
|
||
if name == "" {
|
||
fmt.Printf("%s Имя не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
fmt.Println("Вставьте конфиг WireGuard (завершите пустой строкой):")
|
||
|
||
var lines []string
|
||
reader := bufio.NewReader(os.Stdin)
|
||
for {
|
||
line, _ := reader.ReadString('\n')
|
||
line = strings.TrimRight(line, "\r\n")
|
||
if line == "" {
|
||
break
|
||
}
|
||
lines = append(lines, line)
|
||
}
|
||
|
||
if len(lines) == 0 {
|
||
fmt.Printf("%s Конфиг не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
configText := strings.Join(lines, "\n")
|
||
|
||
if err := wireguard.AddConfig(name, configText); err != nil {
|
||
fmt.Printf("%s Ошибка добавления конфига: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s WireGuard конфиг '%s' добавлен\n", green("✓"), name)
|
||
}
|
||
|
||
func addWireGuardConfigFromFile() {
|
||
name := readInput("Имя конфига: ")
|
||
if name == "" {
|
||
fmt.Printf("%s Имя не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
filePath := readInput("Путь к файлу конфига: ")
|
||
if filePath == "" {
|
||
fmt.Printf("%s Путь не может быть пустым\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
if err := wireguard.AddConfigFromFile(name, filePath); err != nil {
|
||
fmt.Printf("%s Ошибка добавления конфига: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s WireGuard конфиг '%s' добавлен из файла\n", green("✓"), name)
|
||
}
|
||
|
||
func deleteWireGuardConfig() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(configs.WireGuard) == 0 {
|
||
fmt.Println("Нет конфигов для удаления")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== WireGuard конфиги ===")
|
||
for i, cfg := range configs.WireGuard {
|
||
fmt.Printf("%d. %s\n", i+1, cfg.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер конфига для удаления: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(configs.WireGuard) {
|
||
fmt.Printf("%s Неверный номер конфига\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
name := configs.WireGuard[num-1].Name
|
||
|
||
if err := wireguard.DeleteConfig(name); err != nil {
|
||
fmt.Printf("%s Ошибка удаления конфига: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
fmt.Printf("%s Конфиг '%s' удален\n", green("✓"), name)
|
||
}
|
||
|
||
func connectWireGuard() {
|
||
configs, err := config.LoadConfigs()
|
||
if err != nil {
|
||
fmt.Printf("%s Ошибка загрузки конфигураций: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
|
||
if len(configs.WireGuard) == 0 {
|
||
fmt.Println("Нет конфигов для подключения")
|
||
return
|
||
}
|
||
|
||
fmt.Println("\n=== WireGuard конфиги ===")
|
||
for i, cfg := range configs.WireGuard {
|
||
fmt.Printf("%d. %s\n", i+1, cfg.Name)
|
||
}
|
||
|
||
numStr := readInput("\nНомер конфига для подключения: ")
|
||
num, err := strconv.Atoi(numStr)
|
||
if err != nil || num < 1 || num > len(configs.WireGuard) {
|
||
fmt.Printf("%s Неверный номер конфига\n", red("✗"))
|
||
return
|
||
}
|
||
|
||
configName := configs.WireGuard[num-1].Name
|
||
|
||
if err := wireguard.Connect(configName, config.LogsDir); err != nil {
|
||
fmt.Printf("%s Ошибка подключения: %v\n", red("✗"), err)
|
||
return
|
||
}
|
||
}
|