120 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package surfboard
import (
"bytes"
"embed"
"fmt"
"net/url"
"strings"
"text/template"
"time"
"github.com/perfect-panel/server/pkg/adapter/proxy"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/tool"
"github.com/perfect-panel/server/pkg/traffic"
)
//go:embed *.tpl
var configFiles embed.FS
var shadowsocksSupportMethod = []string{"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305"}
func BuildSurfboard(servers proxy.Adapter, siteName string, user UserInfo) []byte {
var proxies, proxyGroup string
var removed []string
for _, node := range servers.Proxies {
if uri := buildProxy(node, user.UUID); uri != "" {
proxies += uri
} else {
removed = append(removed, node.Name)
}
}
for _, group := range servers.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)
}
}
var rules string
for _, rule := range servers.Rules {
if rule == "" {
continue
}
rules += rule + "\r\n"
}
//final rule
rules += "FINAL, 手动选择"
file, err := configFiles.ReadFile("default.tpl")
if err != nil {
logger.Errorf("read default surfboard config error: %v", err.Error())
return nil
}
// replace template
tpl, err := template.New("default").Parse(string(file))
if err != nil {
logger.Errorf("read default surfboard config error: %v", err.Error())
return nil
}
var buf bytes.Buffer
var expiredAt string
if user.ExpiredDate.Before(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)) {
expiredAt = "长期有效"
} else {
expiredAt = user.ExpiredDate.Format("2006-01-02 15:04:05")
}
// convert traffic
upload := traffic.AutoConvert(user.Upload, false)
download := traffic.AutoConvert(user.Download, false)
total := traffic.AutoConvert(user.TotalTraffic, false)
unusedTraffic := traffic.AutoConvert(user.TotalTraffic-user.Upload-user.Download, false)
// query Host
urlParse, err := url.Parse(user.SubscribeURL)
if err != nil {
return nil
}
if err := tpl.Execute(&buf, map[string]interface{}{
"Proxies": proxies,
"ProxyGroup": proxyGroup,
"SubscribeURL": user.SubscribeURL,
"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 {
logger.Errorf("build surfboard config error: %v", err.Error())
return nil
}
return buf.Bytes()
}
func buildProxy(data proxy.Proxy, uuid string) string {
var p string
switch data.Protocol {
case "vmess":
p = buildVMess(data, uuid)
case "shadowsocks":
if !tool.Contains(shadowsocksSupportMethod, data.Option.(proxy.Shadowsocks).Method) {
return ""
}
p = buildShadowsocks(data, uuid)
case "trojan":
p = buildTrojan(data, uuid)
}
return p
}