- Add settings menu to switch between Xray and V2Ray cores for VLESS connections - Implement core type persistence in configuration with LoadSettings/SaveSettings - Add VLESS error and access log viewer showing last 30 and 20 lines respectively - Display current core type and system time in main menu - Update VLESS connection to use selected core dynamically - Refactor monitor.go to accept 'q' key input for graceful exit instead of signal handling - Add proxy platform-specific implementations (proxy_unix.go, proxy_windows.go) - Add downloader module for managing binary resources - Include V2Ray and Xray configuration files and geodata (geoip.dat, geosite.dat) - Update CLI imports to include path/filepath and time packages - Improve user experience with core selection visibility and log diagnostics
213 lines
5.1 KiB
Go
213 lines
5.1 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
var (
|
|
ConfigDir string
|
|
SubscriptionsFile string
|
|
ConfigsFile string
|
|
StateFile string
|
|
SettingsFile string
|
|
LogsDir string
|
|
XrayDir string
|
|
V2RayDir string
|
|
)
|
|
|
|
type WireGuardConfig struct {
|
|
Name string `json:"name"`
|
|
Config string `json:"config"`
|
|
}
|
|
|
|
type VLESSConfig struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Protocol string `json:"protocol,omitempty"`
|
|
Subscription string `json:"subscription,omitempty"`
|
|
}
|
|
|
|
type Configs struct {
|
|
WireGuard []WireGuardConfig `json:"wireguard"`
|
|
VLESS []VLESSConfig `json:"vless"`
|
|
}
|
|
|
|
type Subscription struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
type Subscriptions struct {
|
|
Subscriptions []Subscription `json:"subscriptions"`
|
|
}
|
|
|
|
type ConnectionState struct {
|
|
Connected bool `json:"connected"`
|
|
ConfigName string `json:"config_name"`
|
|
ConfigType string `json:"config_type"`
|
|
StartTime string `json:"start_time"`
|
|
Interface string `json:"interface"`
|
|
ProcessPID int `json:"process_pid"`
|
|
LogFile string `json:"log_file"`
|
|
}
|
|
|
|
type Settings struct {
|
|
CoreType string `json:"core_type"` // "xray" или "v2ray"
|
|
}
|
|
|
|
// Init инициализирует конфигурационные директории и файлы
|
|
func Init() error {
|
|
// Получаем рабочую директорию
|
|
workDir, err := os.Getwd()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ConfigDir = filepath.Join(workDir, ".vpn_client")
|
|
SubscriptionsFile = filepath.Join(ConfigDir, "subscriptions.json")
|
|
ConfigsFile = filepath.Join(ConfigDir, "configs.json")
|
|
StateFile = filepath.Join(ConfigDir, "state.json")
|
|
SettingsFile = filepath.Join(ConfigDir, "settings.json")
|
|
LogsDir = filepath.Join(workDir, "logs")
|
|
XrayDir = filepath.Join(workDir, "xray")
|
|
V2RayDir = filepath.Join(workDir, "v2ray")
|
|
|
|
// Создаем директории
|
|
if err := os.MkdirAll(ConfigDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
if err := os.MkdirAll(LogsDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Инициализируем файлы если их нет
|
|
if err := initFileIfNotExists(SubscriptionsFile, Subscriptions{Subscriptions: []Subscription{}}); err != nil {
|
|
return err
|
|
}
|
|
if err := initFileIfNotExists(ConfigsFile, Configs{WireGuard: []WireGuardConfig{}, VLESS: []VLESSConfig{}}); err != nil {
|
|
return err
|
|
}
|
|
if err := initFileIfNotExists(StateFile, ConnectionState{}); err != nil {
|
|
return err
|
|
}
|
|
if err := initFileIfNotExists(SettingsFile, Settings{CoreType: "xray"}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func initFileIfNotExists(path string, defaultData interface{}) error {
|
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
data, err := json.MarshalIndent(defaultData, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(path, data, 0644)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// LoadConfigs загружает конфигурации
|
|
func LoadConfigs() (*Configs, error) {
|
|
data, err := os.ReadFile(ConfigsFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var configs Configs
|
|
if err := json.Unmarshal(data, &configs); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &configs, nil
|
|
}
|
|
|
|
// SaveConfigs сохраняет конфигурации
|
|
func SaveConfigs(configs *Configs) error {
|
|
data, err := json.MarshalIndent(configs, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(ConfigsFile, data, 0644)
|
|
}
|
|
|
|
// LoadSubscriptions загружает подписки
|
|
func LoadSubscriptions() (*Subscriptions, error) {
|
|
data, err := os.ReadFile(SubscriptionsFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var subs Subscriptions
|
|
if err := json.Unmarshal(data, &subs); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &subs, nil
|
|
}
|
|
|
|
// SaveSubscriptions сохраняет подписки
|
|
func SaveSubscriptions(subs *Subscriptions) error {
|
|
data, err := json.MarshalIndent(subs, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(SubscriptionsFile, data, 0644)
|
|
}
|
|
|
|
// LoadState загружает состояние подключения
|
|
func LoadState() (*ConnectionState, error) {
|
|
data, err := os.ReadFile(StateFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var state ConnectionState
|
|
if err := json.Unmarshal(data, &state); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &state, nil
|
|
}
|
|
|
|
// SaveState сохраняет состояние подключения
|
|
func SaveState(state *ConnectionState) error {
|
|
data, err := json.MarshalIndent(state, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(StateFile, data, 0644)
|
|
}
|
|
|
|
// LoadSettings загружает настройки
|
|
func LoadSettings() (*Settings, error) {
|
|
data, err := os.ReadFile(SettingsFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var settings Settings
|
|
if err := json.Unmarshal(data, &settings); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// По умолчанию xray
|
|
if settings.CoreType == "" {
|
|
settings.CoreType = "xray"
|
|
}
|
|
|
|
return &settings, nil
|
|
}
|
|
|
|
// SaveSettings сохраняет настройки
|
|
func SaveSettings(settings *Settings) error {
|
|
data, err := json.MarshalIndent(settings, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(SettingsFile, data, 0644)
|
|
}
|