Initial commit
This commit is contained in:
184
internal/subscription/subscription.go
Normal file
184
internal/subscription/subscription.go
Normal file
@@ -0,0 +1,184 @@
|
||||
package subscription
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"vpn-client/internal/config"
|
||||
"vpn-client/internal/logger"
|
||||
)
|
||||
|
||||
// FetchConfigs загружает конфигурации из подписки
|
||||
func FetchConfigs(subscriptionURL, logsDir string) ([]config.VLESSConfig, error) {
|
||||
logFile := logger.GetLogPath(logsDir, "subscription")
|
||||
logger.LogMessage(logFile, fmt.Sprintf("Начало загрузки подписки: %s", subscriptionURL))
|
||||
|
||||
// Создаем HTTP клиент с таймаутом
|
||||
client := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
resp, err := client.Get(subscriptionURL)
|
||||
if err != nil {
|
||||
logger.LogMessage(logFile, fmt.Sprintf("Ошибка загрузки подписки: %v", err))
|
||||
return nil, fmt.Errorf("ошибка загрузки подписки: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("ошибка HTTP: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ошибка чтения ответа: %w", err)
|
||||
}
|
||||
|
||||
// Пытаемся декодировать base64
|
||||
content := string(body)
|
||||
if decoded, err := base64.StdEncoding.DecodeString(content); err == nil {
|
||||
content = string(decoded)
|
||||
}
|
||||
|
||||
// Парсим конфигурации
|
||||
var configs []config.VLESSConfig
|
||||
lines := strings.Split(content, "\n")
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
var protocol string
|
||||
var name string
|
||||
var configURL string
|
||||
|
||||
// VLESS конфиги
|
||||
if strings.HasPrefix(line, "vless://") {
|
||||
protocol = "VLESS"
|
||||
configURL = line
|
||||
if parsed, err := url.Parse(line); err == nil && parsed.Fragment != "" {
|
||||
name, _ = url.QueryUnescape(parsed.Fragment)
|
||||
} else {
|
||||
name = fmt.Sprintf("VLESS_%d", len(configs)+1)
|
||||
}
|
||||
configs = append(configs, config.VLESSConfig{
|
||||
Name: name,
|
||||
URL: configURL,
|
||||
Protocol: protocol,
|
||||
})
|
||||
} else if strings.HasPrefix(line, "vmess://") {
|
||||
protocol = "VMess"
|
||||
configURL = line
|
||||
if parsed, err := url.Parse(line); err == nil && parsed.Fragment != "" {
|
||||
name, _ = url.QueryUnescape(parsed.Fragment)
|
||||
} else {
|
||||
name = fmt.Sprintf("VMess_%d", len(configs)+1)
|
||||
}
|
||||
configs = append(configs, config.VLESSConfig{
|
||||
Name: name,
|
||||
URL: configURL,
|
||||
Protocol: protocol,
|
||||
})
|
||||
} else if strings.HasPrefix(line, "trojan://") {
|
||||
protocol = "Trojan"
|
||||
configURL = line
|
||||
if parsed, err := url.Parse(line); err == nil && parsed.Fragment != "" {
|
||||
name, _ = url.QueryUnescape(parsed.Fragment)
|
||||
} else {
|
||||
name = fmt.Sprintf("Trojan_%d", len(configs)+1)
|
||||
}
|
||||
configs = append(configs, config.VLESSConfig{
|
||||
Name: name,
|
||||
URL: configURL,
|
||||
Protocol: protocol,
|
||||
})
|
||||
} else if strings.HasPrefix(line, "ss://") {
|
||||
protocol = "Shadowsocks"
|
||||
configURL = line
|
||||
if parsed, err := url.Parse(line); err == nil && parsed.Fragment != "" {
|
||||
name, _ = url.QueryUnescape(parsed.Fragment)
|
||||
} else {
|
||||
name = fmt.Sprintf("SS_%d", len(configs)+1)
|
||||
}
|
||||
configs = append(configs, config.VLESSConfig{
|
||||
Name: name,
|
||||
URL: configURL,
|
||||
Protocol: protocol,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogMessage(logFile, fmt.Sprintf("Успешно загружено %d конфигов", len(configs)))
|
||||
return configs, nil
|
||||
}
|
||||
|
||||
// UpdateSubscription обновляет конфигурации из подписки
|
||||
func UpdateSubscription(subscriptionName, logsDir string) error {
|
||||
// Загружаем подписки
|
||||
subs, err := config.LoadSubscriptions()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ошибка загрузки подписок: %w", err)
|
||||
}
|
||||
|
||||
// Ищем подписку
|
||||
var sub *config.Subscription
|
||||
for i := range subs.Subscriptions {
|
||||
if subs.Subscriptions[i].Name == subscriptionName {
|
||||
sub = &subs.Subscriptions[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if sub == nil {
|
||||
return fmt.Errorf("подписка '%s' не найдена", subscriptionName)
|
||||
}
|
||||
|
||||
fmt.Printf("Загрузка конфигов из '%s'...\n", subscriptionName)
|
||||
|
||||
// Загружаем конфиги
|
||||
newConfigs, err := FetchConfigs(sub.URL, logsDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ошибка загрузки конфигов: %w", err)
|
||||
}
|
||||
|
||||
if len(newConfigs) == 0 {
|
||||
return fmt.Errorf("не удалось загрузить конфиги")
|
||||
}
|
||||
|
||||
// Загружаем текущие конфигурации
|
||||
allConfigs, err := config.LoadConfigs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("ошибка загрузки конфигураций: %w", err)
|
||||
}
|
||||
|
||||
// Удаляем старые конфиги из этой подписки
|
||||
var filteredConfigs []config.VLESSConfig
|
||||
for _, cfg := range allConfigs.VLESS {
|
||||
if cfg.Subscription != subscriptionName {
|
||||
filteredConfigs = append(filteredConfigs, cfg)
|
||||
}
|
||||
}
|
||||
allConfigs.VLESS = filteredConfigs
|
||||
|
||||
// Добавляем новые конфиги с префиксом подписки
|
||||
for _, cfg := range newConfigs {
|
||||
cfg.Name = fmt.Sprintf("[%s] %s", subscriptionName, cfg.Name)
|
||||
cfg.Subscription = subscriptionName
|
||||
allConfigs.VLESS = append(allConfigs.VLESS, cfg)
|
||||
}
|
||||
|
||||
// Сохраняем
|
||||
if err := config.SaveConfigs(allConfigs); err != nil {
|
||||
return fmt.Errorf("ошибка сохранения конфигураций: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✓ Обновлено %d конфигов из подписки\n", len(newConfigs))
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user