feat(surge): add Surge adapter support and enhance subscription URL handling
This commit is contained in:
parent
224365ce79
commit
b83ce5090a
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/perfect-panel/server/pkg/adapter"
|
"github.com/perfect-panel/server/pkg/adapter"
|
||||||
"github.com/perfect-panel/server/pkg/adapter/shadowrocket"
|
"github.com/perfect-panel/server/pkg/adapter/shadowrocket"
|
||||||
"github.com/perfect-panel/server/pkg/adapter/surfboard"
|
"github.com/perfect-panel/server/pkg/adapter/surfboard"
|
||||||
|
"github.com/perfect-panel/server/pkg/adapter/surge"
|
||||||
|
|
||||||
"github.com/perfect-panel/server/internal/model/server"
|
"github.com/perfect-panel/server/internal/model/server"
|
||||||
|
|
||||||
@ -236,7 +237,7 @@ func (l *SubscribeLogic) buildClientConfig(req *types.SubscribeRequest, userSub
|
|||||||
case "loon":
|
case "loon":
|
||||||
resp = proxyManager.BuildLoon(userSub.UUID)
|
resp = proxyManager.BuildLoon(userSub.UUID)
|
||||||
case "surfboard":
|
case "surfboard":
|
||||||
subsURL := l.getSubscribeURL(userSub.Token)
|
subsURL := l.getSubscribeURL(userSub.Token, "surfboard")
|
||||||
resp = proxyManager.BuildSurfboard(l.svc.Config.Site.SiteName, surfboard.UserInfo{
|
resp = proxyManager.BuildSurfboard(l.svc.Config.Site.SiteName, surfboard.UserInfo{
|
||||||
Upload: userSub.Upload,
|
Upload: userSub.Upload,
|
||||||
Download: userSub.Download,
|
Download: userSub.Download,
|
||||||
@ -248,6 +249,17 @@ func (l *SubscribeLogic) buildClientConfig(req *types.SubscribeRequest, userSub
|
|||||||
l.setSurfboardHeaders()
|
l.setSurfboardHeaders()
|
||||||
case "v2rayn":
|
case "v2rayn":
|
||||||
resp = proxyManager.BuildV2rayN(userSub.UUID)
|
resp = proxyManager.BuildV2rayN(userSub.UUID)
|
||||||
|
case "surge":
|
||||||
|
subsURL := l.getSubscribeURL(userSub.Token, "surge")
|
||||||
|
resp = proxyManager.BuildSurge(l.svc.Config.Site.SiteName, surge.UserInfo{
|
||||||
|
UUID: userSub.UUID,
|
||||||
|
Upload: userSub.Upload,
|
||||||
|
Download: userSub.Download,
|
||||||
|
TotalTraffic: userSub.Traffic,
|
||||||
|
ExpiredDate: userSub.ExpireTime,
|
||||||
|
SubscribeURL: subsURL,
|
||||||
|
})
|
||||||
|
l.setSurgeHeaders()
|
||||||
default:
|
default:
|
||||||
resp = proxyManager.BuildGeneral(userSub.UUID)
|
resp = proxyManager.BuildGeneral(userSub.UUID)
|
||||||
}
|
}
|
||||||
@ -269,14 +281,19 @@ func (l *SubscribeLogic) setSurfboardHeaders() {
|
|||||||
l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8")
|
l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *SubscribeLogic) getSubscribeURL(token string) string {
|
func (l *SubscribeLogic) setSurgeHeaders() {
|
||||||
|
l.ctx.Header("content-disposition", fmt.Sprintf("attachment;filename*=UTF-8''%s.conf", url.QueryEscape(l.svc.Config.Site.SiteName)))
|
||||||
|
l.ctx.Header("Content-Type", "application/octet-stream; charset=UTF-8")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *SubscribeLogic) getSubscribeURL(token, flag string) string {
|
||||||
if l.svc.Config.Subscribe.PanDomain {
|
if l.svc.Config.Subscribe.PanDomain {
|
||||||
return fmt.Sprintf("https://%s", l.ctx.Request.Host)
|
return fmt.Sprintf("https://%s", l.ctx.Request.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.svc.Config.Subscribe.SubscribeDomain != "" {
|
if l.svc.Config.Subscribe.SubscribeDomain != "" {
|
||||||
domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n")
|
domains := strings.Split(l.svc.Config.Subscribe.SubscribeDomain, "\n")
|
||||||
return fmt.Sprintf("https://%s%s?token=%s&flag=surfboard", domains[0], l.svc.Config.Subscribe.SubscribePath, token)
|
return fmt.Sprintf("https://%s%s?token=%s&flag=%s", domains[0], l.svc.Config.Subscribe.SubscribePath, token, flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("https://%s%s?token=%s&flag=surfboard", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token)
|
return fmt.Sprintf("https://%s%s?token=%s&flag=surfboard", l.ctx.Request.Host, l.svc.Config.Subscribe.SubscribePath, token)
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/perfect-panel/server/pkg/adapter/shadowrocket"
|
"github.com/perfect-panel/server/pkg/adapter/shadowrocket"
|
||||||
"github.com/perfect-panel/server/pkg/adapter/singbox"
|
"github.com/perfect-panel/server/pkg/adapter/singbox"
|
||||||
"github.com/perfect-panel/server/pkg/adapter/surfboard"
|
"github.com/perfect-panel/server/pkg/adapter/surfboard"
|
||||||
|
"github.com/perfect-panel/server/pkg/adapter/surge"
|
||||||
"github.com/perfect-panel/server/pkg/adapter/v2rayn"
|
"github.com/perfect-panel/server/pkg/adapter/v2rayn"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,3 +95,8 @@ func (m *Adapter) BuildSurfboard(siteName string, user surfboard.UserInfo) []byt
|
|||||||
func (m *Adapter) BuildV2rayN(uuid string) []byte {
|
func (m *Adapter) BuildV2rayN(uuid string) []byte {
|
||||||
return v2rayn.NewV2rayN(m.Adapter).Build(uuid)
|
return v2rayn.NewV2rayN(m.Adapter).Build(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildSurge generates a Surge configuration for the given UUID and site name.
|
||||||
|
func (m *Adapter) BuildSurge(siteName string, user surge.UserInfo) []byte {
|
||||||
|
return surge.NewSurge(m.Adapter).Build(siteName, user)
|
||||||
|
}
|
||||||
|
|||||||
@ -1,61 +1,79 @@
|
|||||||
#!MANAGED-CONFIG {{ .SubscribeURL }} interval=43200 strict=true
|
#!MANAGED-CONFIG {{.SubscribeURL}} interval=43200 strict=true
|
||||||
# Surge 的规则配置手册: https://manual.nssurge.com/
|
|
||||||
|
|
||||||
[General]
|
[General]
|
||||||
loglevel = notify
|
loglevel = notify
|
||||||
# 从 Surge iOS 4 / Surge Mac 3.3.0 起,工具开始支持 DoH
|
external-controller-access = purinio@0.0.0.0:6170
|
||||||
doh-server = https://doh.pub/dns-query
|
|
||||||
# https://dns.alidns.com/dns-query, https://13800000000.rubyfish.cn/, https://dns.google/dns-query
|
|
||||||
dns-server = 223.5.5.5, 114.114.114.114
|
|
||||||
tun-excluded-routes = 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 192.88.99.0/24, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 255.255.255.255/32
|
|
||||||
skip-proxy = localhost, *.local, injections.adguard.org, local.adguard.org, captive.apple.com, guzzoni.apple.com, 0.0.0.0/8, 10.0.0.0/8, 17.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 192.88.99.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, 255.255.255.255/32
|
|
||||||
|
|
||||||
wifi-assist = true
|
|
||||||
allow-wifi-access = true
|
|
||||||
wifi-access-http-port = 6152
|
|
||||||
wifi-access-socks5-port = 6153
|
|
||||||
http-listen = 0.0.0.0:6152
|
|
||||||
socks5-listen = 0.0.0.0:6153
|
|
||||||
|
|
||||||
external-controller-access = surgepasswd@0.0.0.0:6170
|
|
||||||
replica = false
|
|
||||||
|
|
||||||
tls-provider = openssl
|
|
||||||
network-framework = false
|
|
||||||
exclude-simple-hostnames = true
|
exclude-simple-hostnames = true
|
||||||
|
show-error-page-for-reject = true
|
||||||
|
udp-priority = true
|
||||||
|
udp-policy-not-supported-behaviour = reject
|
||||||
ipv6 = true
|
ipv6 = true
|
||||||
|
ipv6-vif = auto
|
||||||
test-timeout = 4
|
|
||||||
proxy-test-url = http://www.gstatic.com/generate_204
|
proxy-test-url = http://www.gstatic.com/generate_204
|
||||||
geoip-maxmind-url = https://unpkg.zhimg.com/rulestatic@1.0.1/Country.mmdb
|
internet-test-url = http://connectivitycheck.platform.hicloud.com/generate_204
|
||||||
|
test-timeout = 5
|
||||||
|
dns-server = system, 119.29.29.29, 223.5.5.5
|
||||||
|
hijack-dns = 8.8.8.8:53, 8.8.4.4:53, 1.1.1.1:53, 1.0.0.1:53
|
||||||
|
skip-proxy = 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 127.0.0.0/8, localhost, *.local
|
||||||
|
always-real-ip = *.lan, lens.l.google.com, *.srv.nintendo.net, *.stun.playstation.net, *.xboxlive.com, xbox.*.*.microsoft.com, *.msftncsi.com, *.msftconnecttest.com
|
||||||
|
|
||||||
[Replica]
|
# > Surge Mac Parameters
|
||||||
hide-apple-request = true
|
http-listen = 0.0.0.0:6088
|
||||||
hide-crashlytics-request = true
|
socks5-listen = 0.0.0.0:6089
|
||||||
use-keyword-filter = false
|
|
||||||
hide-udp = false
|
# > Surge iOS Parameters
|
||||||
|
allow-wifi-access = true
|
||||||
|
allow-hotspot-access = true
|
||||||
|
wifi-access-http-port = 6088
|
||||||
|
wifi-access-socks5-port = 6089
|
||||||
|
|
||||||
[Panel]
|
[Panel]
|
||||||
SubscribeInfo = {{ .SubscribeInfo }}, style=info
|
SubscribeInfo = {{.SubscribeInfo}}, style=info
|
||||||
|
|
||||||
# -----------------------------
|
|
||||||
# Surge 的几种策略配置规范,请参考 https://manual.nssurge.com/policy/proxy.html
|
|
||||||
# 不同的代理策略有*很多*可选参数,请参考上方连接的 Parameters 一段,根据需求自行添加参数。
|
|
||||||
#
|
|
||||||
# Surge 现已支持 UDP 转发功能,请参考: https://trello.com/c/ugOMxD3u/53-udp-%E8%BD%AC%E5%8F%91
|
|
||||||
# Surge 现已支持 TCP-Fast-Open 技术,请参考: https://trello.com/c/ij65BU6Q/48-tcp-fast-open-troubleshooting-guide
|
|
||||||
# Surge 现已支持 ss-libev 的全部加密方式和混淆,请参考: https://trello.com/c/BTr0vG1O/47-ss-libev-%E7%9A%84%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5
|
|
||||||
# -----------------------------
|
|
||||||
|
|
||||||
[Proxy]
|
[Proxy]
|
||||||
{{ .Proxies }}
|
{{.Proxies}}
|
||||||
|
|
||||||
[Proxy Group]
|
[Proxy Group]
|
||||||
# 代理组列表
|
🚀 Proxy = select, 🌏 Auto, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
{{ .ProxyGroup }}
|
🍎 Apple = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🔍 Google = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🪟 Microsoft = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
📺 GlobalMedia = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🤖 AI = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🪙 Crypto = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🎮 Game = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
📟 Telegram = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🇨🇳 China = select, 🎯 Direct, 🚀 Proxy, include-other-group=🇺🇳 Nodes
|
||||||
|
🐠 Final = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes
|
||||||
|
🌏 Auto = smart, include-other-group=🇺🇳 Nodes
|
||||||
|
🎯 Direct = select, DIRECT, hidden=1
|
||||||
|
🇺🇳 Nodes = select, {{.ProxyGroup}}, hidden=1
|
||||||
|
|
||||||
[Rule]
|
[Rule]
|
||||||
{{ .Rules }}
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Apple/Apple_All.list, 🍎 Apple
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Google/Google.list, 🔍 Google
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/GitHub/GitHub.list, 🪟 Microsoft
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Microsoft/Microsoft.list, 🪟 Microsoft
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/HBO/HBO.list, 📺 GlobalMedia
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Disney/Disney.list, 📺 GlobalMedia
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/TikTok/TikTok.list, 📺 GlobalMedia
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Netflix/Netflix.list, 📺 GlobalMedia
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/GlobalMedia/GlobalMedia_All_No_Resolve.list, 📺 GlobalMedia
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Telegram/Telegram.list, 📟 Telegram
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/OpenAI/OpenAI.list, 🤖 AI
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Gemini/Gemini.list, 🤖 AI
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Copilot/Copilot.list, 🤖 AI
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Claude/Claude.list, 🤖 AI
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Crypto/Crypto.list, 🪙 Crypto
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Cryptocurrency/Cryptocurrency.list, 🪙 Crypto
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Game/Game.list, 🎮 Game
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Global/Global_All_No_Resolve.list, 🚀 Proxy
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/ChinaMax/ChinaMax_All_No_Resolve.list, 🇨🇳 China
|
||||||
|
RULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Lan/Lan.list, 🎯 Direct
|
||||||
|
|
||||||
|
GEOIP, CN, 🇨🇳 China
|
||||||
|
FINAL, 🐠 Final, dns-failed
|
||||||
|
|
||||||
[URL Rewrite]
|
[URL Rewrite]
|
||||||
^https?://(www.)?(g|google).cn https://www.google.com 302
|
^https?:\/\/(www.)?g\.cn https://www.google.com 302
|
||||||
|
^https?:\/\/(www.)?google\.cn https://www.google.com 302
|
||||||
@ -4,14 +4,13 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/perfect-panel/server/pkg/tool"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/perfect-panel/server/pkg/adapter/proxy"
|
"github.com/perfect-panel/server/pkg/adapter/proxy"
|
||||||
"github.com/perfect-panel/server/pkg/logger"
|
"github.com/perfect-panel/server/pkg/logger"
|
||||||
|
"github.com/perfect-panel/server/pkg/tool"
|
||||||
"github.com/perfect-panel/server/pkg/traffic"
|
"github.com/perfect-panel/server/pkg/traffic"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,46 +38,26 @@ func NewSurge(adapter proxy.Adapter) *Surge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Surge) Build(uuid, siteName string, user UserInfo) []byte {
|
func (m *Surge) Build(siteName string, user UserInfo) []byte {
|
||||||
var proxies, proxyGroup, rules string
|
var proxies, proxyGroup string
|
||||||
var removed []string
|
var removed []string
|
||||||
|
var ps []string
|
||||||
|
|
||||||
for _, p := range m.Adapter.Proxies {
|
for _, p := range m.Adapter.Proxies {
|
||||||
switch p.Protocol {
|
switch p.Protocol {
|
||||||
case "shadowsocks":
|
case "shadowsocks":
|
||||||
proxies += buildShadowsocks(p, uuid)
|
proxies += buildShadowsocks(p, user.UUID)
|
||||||
case "trojan":
|
case "trojan":
|
||||||
proxies += buildTrojan(p, uuid)
|
proxies += buildTrojan(p, user.UUID)
|
||||||
case "hysteria2":
|
case "hysteria2":
|
||||||
proxies += buildHysteria2(p, uuid)
|
proxies += buildHysteria2(p, user.UUID)
|
||||||
case "vmess":
|
case "vmess":
|
||||||
proxies += buildVMess(p, uuid)
|
proxies += buildVMess(p, user.UUID)
|
||||||
default:
|
default:
|
||||||
removed = append(removed, p.Name)
|
removed = append(removed, p.Name)
|
||||||
}
|
}
|
||||||
|
ps = append(ps, p.Name)
|
||||||
}
|
}
|
||||||
for _, group := range m.Adapter.Group {
|
|
||||||
if len(removed) > 0 {
|
|
||||||
group.Proxies = tool.RemoveStringElement(group.Proxies, removed...)
|
|
||||||
}
|
|
||||||
if group.Type == proxy.GroupTypeSelect {
|
|
||||||
proxyGroup += fmt.Sprintf("%s = select, %s", group.Name, strings.Join(group.Proxies, ", ")) + "\r\n"
|
|
||||||
} else if group.Type == proxy.GroupTypeURLTest {
|
|
||||||
proxyGroup += fmt.Sprintf("%s = url-test, %s, url=%s, interval=%d", group.Name, strings.Join(group.Proxies, ", "), group.URL, group.Interval) + "\r\n"
|
|
||||||
} else if group.Type == proxy.GroupTypeFallback {
|
|
||||||
proxyGroup += fmt.Sprintf("%s = fallback, %s, url=%s, interval=%d", group.Name, strings.Join(group.Proxies, ", "), group.URL, group.Interval) + "\r\n"
|
|
||||||
} else {
|
|
||||||
logger.Errorf("[BuildSurfboard] unknown group type: %s", group.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, rule := range m.Adapter.Rules {
|
|
||||||
if rule == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rules += rule + "\r\n"
|
|
||||||
}
|
|
||||||
//final rule
|
|
||||||
rules += "\r\n" + "FINAL,手动选择,dns-failed"
|
|
||||||
|
|
||||||
file, err := configFiles.ReadFile("default.tpl")
|
file, err := configFiles.ReadFile("default.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -99,23 +78,21 @@ func (m *Surge) Build(uuid, siteName string, user UserInfo) []byte {
|
|||||||
} else {
|
} else {
|
||||||
expiredAt = user.ExpiredDate.Format("2006-01-02 15:04:05")
|
expiredAt = user.ExpiredDate.Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ps = tool.RemoveStringElement(ps, removed...)
|
||||||
|
proxyGroup = strings.Join(ps, ",")
|
||||||
|
|
||||||
// convert traffic
|
// convert traffic
|
||||||
upload := traffic.AutoConvert(user.Upload, false)
|
upload := traffic.AutoConvert(user.Upload, false)
|
||||||
download := traffic.AutoConvert(user.Download, false)
|
download := traffic.AutoConvert(user.Download, false)
|
||||||
total := traffic.AutoConvert(user.TotalTraffic, false)
|
total := traffic.AutoConvert(user.TotalTraffic, false)
|
||||||
unusedTraffic := traffic.AutoConvert(user.TotalTraffic-user.Upload-user.Download, false)
|
unusedTraffic := traffic.AutoConvert(user.TotalTraffic-user.Upload-user.Download, false)
|
||||||
// query Host
|
// query Host
|
||||||
urlParse, err := url.Parse(user.SubscribeURL)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := tpl.Execute(&buf, map[string]interface{}{
|
if err := tpl.Execute(&buf, map[string]interface{}{
|
||||||
"Proxies": proxies,
|
"Proxies": proxies,
|
||||||
"ProxyGroup": proxyGroup,
|
"ProxyGroup": proxyGroup,
|
||||||
"SubscribeURL": user.SubscribeURL,
|
"SubscribeURL": user.SubscribeURL,
|
||||||
"SubscribeInfo": fmt.Sprintf("title=%s订阅信息, content=上传流量:%s\\n下载流量:%s\\n剩余流量: %s\\n套餐流量:%s\\n到期时间:%s", siteName, upload, download, unusedTraffic, total, expiredAt),
|
"SubscribeInfo": fmt.Sprintf("title=%s订阅信息, content=上传流量:%s\\n下载流量:%s\\n剩余流量: %s\\n套餐流量:%s\\n到期时间:%s", siteName, upload, download, unusedTraffic, total, expiredAt),
|
||||||
"SubscribeDomain": urlParse.Host,
|
|
||||||
"Rules": rules,
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
logger.Errorf("build Surge config error: %v", err.Error())
|
logger.Errorf("build Surge config error: %v", err.Error())
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user