Release 3.9.0+1: Remnawave API configs, Remnawave-style UI with flags, Windows build.
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"vpnclient/internal/protocols/hysteria2"
|
||||
"vpnclient/internal/protocols/naive"
|
||||
"vpnclient/internal/protocols/xray"
|
||||
"vpnclient/internal/remnawave"
|
||||
"vpnclient/internal/subscription"
|
||||
"vpnclient/internal/sysproxy"
|
||||
)
|
||||
@@ -417,20 +418,100 @@ func (m *Manager) SubscriptionURL() string {
|
||||
return m.cfg.SubscriptionURL
|
||||
}
|
||||
|
||||
func (m *Manager) RemnawaveSettings() remnawave.Settings {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return remnawave.Settings{
|
||||
BaseURL: m.cfg.RemnawaveBaseURL,
|
||||
Token: m.cfg.RemnawaveToken,
|
||||
ShortUUID: m.cfg.RemnawaveShortUUID,
|
||||
CaddyToken: m.cfg.RemnawaveCaddyToken,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) SaveRemnawaveSettings(s remnawave.Settings) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.cfg.RemnawaveBaseURL = remnawave.NormalizeBase(s.BaseURL)
|
||||
m.cfg.RemnawaveToken = strings.TrimSpace(s.Token)
|
||||
m.cfg.RemnawaveShortUUID = strings.TrimSpace(s.ShortUUID)
|
||||
m.cfg.RemnawaveCaddyToken = strings.TrimSpace(s.CaddyToken)
|
||||
return config.Save(m.cfgPath, *m.cfg)
|
||||
}
|
||||
|
||||
func (m *Manager) ImportSubscription(rawURL string) (int, error) {
|
||||
rawURL = strings.TrimSpace(rawURL)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Remnawave-style URL → persist panel coords and fetch via API helper.
|
||||
if base, short, ok := remnawave.ParseInput(rawURL); ok {
|
||||
s := remnawave.Settings{
|
||||
BaseURL: base,
|
||||
ShortUUID: short,
|
||||
Token: m.RemnawaveSettings().Token,
|
||||
CaddyToken: m.RemnawaveSettings().CaddyToken,
|
||||
}
|
||||
items, used, err := remnawave.Fetch(ctx, s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return m.applySubscriptionItems(items, used, &s)
|
||||
}
|
||||
|
||||
items, err := subscription.Fetch(ctx, rawURL)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return m.applySubscriptionItems(items, rawURL, nil)
|
||||
}
|
||||
|
||||
// ImportRemnawave fetches configs using saved / provided panel settings.
|
||||
func (m *Manager) ImportRemnawave(s remnawave.Settings) (int, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
|
||||
defer cancel()
|
||||
if strings.TrimSpace(s.BaseURL) == "" || strings.TrimSpace(s.ShortUUID) == "" {
|
||||
cur := m.RemnawaveSettings()
|
||||
if strings.TrimSpace(s.BaseURL) == "" {
|
||||
s.BaseURL = cur.BaseURL
|
||||
}
|
||||
if strings.TrimSpace(s.ShortUUID) == "" {
|
||||
s.ShortUUID = cur.ShortUUID
|
||||
}
|
||||
if strings.TrimSpace(s.Token) == "" {
|
||||
s.Token = cur.Token
|
||||
}
|
||||
if strings.TrimSpace(s.CaddyToken) == "" {
|
||||
s.CaddyToken = cur.CaddyToken
|
||||
}
|
||||
}
|
||||
items, used, err := remnawave.Fetch(ctx, s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return m.applySubscriptionItems(items, used, &s)
|
||||
}
|
||||
|
||||
func (m *Manager) applySubscriptionItems(items []subscription.Item, usedURL string, rw *remnawave.Settings) (int, error) {
|
||||
if len(items) == 0 {
|
||||
return 0, fmt.Errorf("в подписке нет поддерживаемых ссылок (naive / hysteria2 / awg / vless / vmess / trojan)")
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.cfg.SubscriptionURL = strings.TrimSpace(rawURL)
|
||||
if usedURL != "" {
|
||||
m.cfg.SubscriptionURL = strings.TrimSpace(usedURL)
|
||||
}
|
||||
if rw != nil {
|
||||
m.cfg.RemnawaveBaseURL = remnawave.NormalizeBase(rw.BaseURL)
|
||||
m.cfg.RemnawaveShortUUID = strings.TrimSpace(rw.ShortUUID)
|
||||
if t := strings.TrimSpace(rw.Token); t != "" {
|
||||
m.cfg.RemnawaveToken = t
|
||||
}
|
||||
if t := strings.TrimSpace(rw.CaddyToken); t != "" {
|
||||
m.cfg.RemnawaveCaddyToken = t
|
||||
}
|
||||
}
|
||||
for _, it := range items {
|
||||
_ = m.cfg.UpsertProfileWithProtocol(it.Name, it.URI, it.Protocol)
|
||||
for i := range m.cfg.Profiles {
|
||||
|
||||
Reference in New Issue
Block a user