clash - stash subscription #373
This commit is contained in:
@@ -56,6 +56,7 @@ var defaultValueMap = map[string]string{
|
|||||||
"subShowInfo": "false",
|
"subShowInfo": "false",
|
||||||
"subURI": "",
|
"subURI": "",
|
||||||
"subJsonExt": "",
|
"subJsonExt": "",
|
||||||
|
"subClashExt": "",
|
||||||
"config": defaultConfig,
|
"config": defaultConfig,
|
||||||
"version": config.GetVersion(),
|
"version": config.GetVersion(),
|
||||||
}
|
}
|
||||||
@@ -392,6 +393,10 @@ func (s *SettingService) GetSubJsonExt() (string, error) {
|
|||||||
return s.getString("subJsonExt")
|
return s.getString("subJsonExt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetSubClashExt() (string, error) {
|
||||||
|
return s.getString("subClashExt")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SettingService) fileExists(path string) error {
|
func (s *SettingService) fileExists(path string) error {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -0,0 +1,332 @@
|
|||||||
|
package sub
|
||||||
|
|
||||||
|
import (
|
||||||
|
"s-ui/logger"
|
||||||
|
"s-ui/service"
|
||||||
|
"s-ui/util"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClashService struct {
|
||||||
|
service.SettingService
|
||||||
|
JsonService
|
||||||
|
LinkService
|
||||||
|
}
|
||||||
|
|
||||||
|
const basicClashConfig = `mixed-port: 7890
|
||||||
|
allow-lan: false
|
||||||
|
mode: rule
|
||||||
|
log-level: info
|
||||||
|
external-controller: 127.0.0.1:9090
|
||||||
|
tun:
|
||||||
|
enable: true
|
||||||
|
stack: system
|
||||||
|
auto-route: true
|
||||||
|
auto-detect-interface: true
|
||||||
|
dns-hijack:
|
||||||
|
- any:53
|
||||||
|
dns:
|
||||||
|
enable: true
|
||||||
|
ipv6: false
|
||||||
|
enhanced-mode: fake-ip
|
||||||
|
fake-ip-range: 198.18.0.1/16
|
||||||
|
default-nameserver:
|
||||||
|
- 8.8.8.8
|
||||||
|
- 1.1.1.1
|
||||||
|
nameserver:
|
||||||
|
- https://doh.pub/dns-query
|
||||||
|
- https://1.0.0.1/dns-query
|
||||||
|
fallback:
|
||||||
|
- tcp://9.9.9.9:53
|
||||||
|
fake-ip-filter:
|
||||||
|
- "*.lan"
|
||||||
|
- localhost
|
||||||
|
- "*.local"
|
||||||
|
rules:
|
||||||
|
- GEOIP,Private,DIRECT
|
||||||
|
- MATCH,Proxy
|
||||||
|
`
|
||||||
|
|
||||||
|
const ProxyGroups = `- name: Proxy
|
||||||
|
type: select
|
||||||
|
proxies: []
|
||||||
|
- name: Auto
|
||||||
|
type: url-test
|
||||||
|
proxies: []
|
||||||
|
url: http://www.gstatic.com/generate_204
|
||||||
|
interval: 300
|
||||||
|
tolerance: 50
|
||||||
|
`
|
||||||
|
|
||||||
|
func (s *ClashService) GetClash(subId string) (*string, []string, error) {
|
||||||
|
|
||||||
|
client, inDatas, err := s.getData(subId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
outbounds, outTags, err := s.getOutbounds(client.Config, inDatas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
links := s.LinkService.GetLinks(&client.Links, "external", "")
|
||||||
|
for index, link := range links {
|
||||||
|
json, tag, err := util.GetOutbound(link, index)
|
||||||
|
if err == nil && len(tag) > 0 {
|
||||||
|
*outbounds = append(*outbounds, *json)
|
||||||
|
*outTags = append(*outTags, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
othersStr, err := s.getClashConfig()
|
||||||
|
if err != nil || len(othersStr) == 0 {
|
||||||
|
othersStr = basicClashConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := s.ConvertToClashMeta(outbounds)
|
||||||
|
resultStr := othersStr + "\n" + string(result)
|
||||||
|
|
||||||
|
updateInterval, _ := s.SettingService.GetSubUpdates()
|
||||||
|
headers := util.GetHeaders(client, updateInterval)
|
||||||
|
|
||||||
|
return &resultStr, headers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClashService) getClashConfig() (string, error) {
|
||||||
|
subClashExt, err := s.SettingService.GetSubClashExt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return subClashExt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClashService) ConvertToClashMeta(outbounds *[]map[string]interface{}) ([]byte, error) {
|
||||||
|
var proxies []interface{}
|
||||||
|
proxyTags := make([]string, 0)
|
||||||
|
for _, obMap := range *outbounds {
|
||||||
|
|
||||||
|
t, _ := obMap["type"].(string)
|
||||||
|
if t == "selector" || t == "urltest" || t == "direct" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy := make(map[string]interface{})
|
||||||
|
proxy["name"] = obMap["tag"]
|
||||||
|
proxy["type"] = t
|
||||||
|
proxy["server"] = obMap["server"]
|
||||||
|
proxy["port"] = obMap["server_port"]
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case "vmess", "vless", "tuic":
|
||||||
|
proxy["uuid"] = obMap["uuid"]
|
||||||
|
if t == "vmess" {
|
||||||
|
proxy["alterId"] = obMap["alter_id"]
|
||||||
|
proxy["cipher"] = "auto"
|
||||||
|
}
|
||||||
|
if t == "vless" {
|
||||||
|
if flow, ok := obMap["flow"].(string); ok {
|
||||||
|
proxy["flow"] = flow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "trojan":
|
||||||
|
proxy["password"] = obMap["password"]
|
||||||
|
case "socks", "http":
|
||||||
|
if t == "socks" {
|
||||||
|
proxy["type"] = "socks5"
|
||||||
|
}
|
||||||
|
proxy["username"] = obMap["username"]
|
||||||
|
proxy["password"] = obMap["password"]
|
||||||
|
case "hysteria", "hysteria2":
|
||||||
|
if _, ok := obMap["up_mbps"].(float64); ok {
|
||||||
|
proxy["up"] = obMap["up_mbps"]
|
||||||
|
} else {
|
||||||
|
proxy["up"] = 1000
|
||||||
|
}
|
||||||
|
if _, ok := obMap["down_mbps"].(float64); ok {
|
||||||
|
proxy["down"] = obMap["down_mbps"]
|
||||||
|
} else {
|
||||||
|
proxy["down"] = 1000
|
||||||
|
}
|
||||||
|
if t == "hysteria" {
|
||||||
|
proxy["auth-str"] = obMap["auth_str"]
|
||||||
|
if obfs, ok := obMap["obfs"].(string); ok {
|
||||||
|
proxy["obfs"] = obfs
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
proxy["password"] = obMap["password"]
|
||||||
|
if obfs, ok := obMap["obfs"].(map[string]interface{}); ok {
|
||||||
|
proxy["obfs"] = obfs["type"]
|
||||||
|
proxy["obfs-password"] = obfs["password"]
|
||||||
|
}
|
||||||
|
if ports, ok := obMap["server_ports"].([]string); ok {
|
||||||
|
proxy["ports"] = strings.ReplaceAll(strings.Join(ports, ","), ":", "-")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "anytls":
|
||||||
|
proxy["password"] = obMap["password"]
|
||||||
|
if tls, ok := obMap["tls"].(map[string]interface{}); ok {
|
||||||
|
proxy["sni"] = tls["server_name"]
|
||||||
|
proxy["skip-cert-verify"] = tls["insecure"]
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLS params
|
||||||
|
tls, isTls := obMap["tls"].(map[string]interface{})
|
||||||
|
if isTls {
|
||||||
|
tlsEnabled, ok := tls["enabled"].(bool)
|
||||||
|
if ok && !tlsEnabled {
|
||||||
|
isTls = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isTls {
|
||||||
|
// ignore ech outbounds
|
||||||
|
if _, ok := tls["ech"].(interface{}); ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
proxy["tls"] = tls["enabled"]
|
||||||
|
|
||||||
|
// ALPN if exists
|
||||||
|
if alpn, ok := tls["alpn"].([]interface{}); ok {
|
||||||
|
proxy["alpn"] = alpn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add reality if exists
|
||||||
|
if reality, ok := tls["reality"].(map[string]interface{}); ok && reality["enabled"].(bool) {
|
||||||
|
reality_opts := make(map[string]interface{})
|
||||||
|
if pbk, ok := reality["public_key"].(string); ok {
|
||||||
|
reality_opts["public-key"] = pbk
|
||||||
|
}
|
||||||
|
if sid, ok := reality["short_id"].(string); ok {
|
||||||
|
reality_opts["short-id"] = sid
|
||||||
|
}
|
||||||
|
proxy["reality-opts"] = reality_opts
|
||||||
|
}
|
||||||
|
if utls, ok := tls["utls"].(map[string]interface{}); ok {
|
||||||
|
if enabled, ok := utls["enabled"].(bool); ok && enabled {
|
||||||
|
if fp, ok := utls["fingerprint"].(string); ok {
|
||||||
|
proxy["client-fingerprint"] = fp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sni, ok := tls["server_name"].(string); ok {
|
||||||
|
if t == "http" {
|
||||||
|
proxy["sni"] = sni
|
||||||
|
} else {
|
||||||
|
proxy["servername"] = sni
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if insecure, ok := tls["insecure"].(bool); ok && insecure {
|
||||||
|
proxy["skip-cert-verify"] = insecure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transport if exist
|
||||||
|
if transport, ok := obMap["transport"].(map[string]interface{}); ok {
|
||||||
|
tt, _ := transport["type"].(string)
|
||||||
|
switch tt {
|
||||||
|
case "http":
|
||||||
|
httpOpts := make(map[string]interface{})
|
||||||
|
if path, ok := transport["path"].([]interface{}); ok {
|
||||||
|
httpOpts["path"] = path[0]
|
||||||
|
} else if path, ok := transport["path"].(string); ok {
|
||||||
|
httpOpts["path"] = path
|
||||||
|
}
|
||||||
|
if host, ok := transport["host"].([]interface{}); ok {
|
||||||
|
httpOpts["host"] = host[0]
|
||||||
|
}
|
||||||
|
if isTls {
|
||||||
|
proxy["network"] = "h2"
|
||||||
|
proxy["h2-opts"] = httpOpts
|
||||||
|
} else {
|
||||||
|
proxy["network"] = "http"
|
||||||
|
proxy["http-opts"] = httpOpts
|
||||||
|
}
|
||||||
|
case "ws", "httpupgrade":
|
||||||
|
proxy["network"] = "ws"
|
||||||
|
wsOpts := make(map[string]interface{})
|
||||||
|
if path, ok := transport["path"].(string); ok {
|
||||||
|
wsOpts["path"] = path
|
||||||
|
}
|
||||||
|
if headers, ok := transport["headers"].([]interface{}); ok {
|
||||||
|
wsOpts["headers"] = headers
|
||||||
|
}
|
||||||
|
if ed, ok := transport["early_data_header_name"].(string); ok {
|
||||||
|
wsOpts["early-data-header-name"] = ed
|
||||||
|
}
|
||||||
|
if tt == "httpupgrade" {
|
||||||
|
wsOpts["v2ray-http-upgrade"] = true
|
||||||
|
}
|
||||||
|
proxy["ws-opts"] = wsOpts
|
||||||
|
case "grpc":
|
||||||
|
proxy["network"] = "grpc"
|
||||||
|
grpcOpts := make(map[string]interface{})
|
||||||
|
if service_name, ok := transport["service_name"].(string); ok {
|
||||||
|
grpcOpts["grpc-service-name"] = service_name
|
||||||
|
}
|
||||||
|
proxy["grpc-opts"] = grpcOpts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplex
|
||||||
|
if mux, ok := obMap["multiplex"].(map[string]interface{}); ok {
|
||||||
|
if enabled, ok := mux["enabled"].(bool); ok && enabled {
|
||||||
|
smux := make(map[string]interface{})
|
||||||
|
smux["enabled"] = true
|
||||||
|
if protocol, ok := mux["protocol"].(string); ok {
|
||||||
|
smux["protocol"] = protocol
|
||||||
|
}
|
||||||
|
if _, ok := mux["max_connections"].(float64); ok {
|
||||||
|
smux["max-connections"] = mux["max_connections"]
|
||||||
|
}
|
||||||
|
if _, ok := mux["min_streams"].(float64); ok {
|
||||||
|
smux["min-streams"] = mux["min_streams"]
|
||||||
|
}
|
||||||
|
if _, ok := mux["max_streams"].(float64); ok {
|
||||||
|
smux["max-streams"] = mux["max_streams"]
|
||||||
|
}
|
||||||
|
if _, ok := mux["padding"].(bool); ok {
|
||||||
|
smux["padding"] = mux["padding"]
|
||||||
|
}
|
||||||
|
if brutal, ok := mux["brutal"].(map[string]interface{}); ok {
|
||||||
|
if enabled, ok := brutal["enabled"].(bool); ok && enabled {
|
||||||
|
brutalOpts := make(map[string]interface{})
|
||||||
|
brutalOpts["enabled"] = true
|
||||||
|
if _, ok := brutal["up_mbps"].(float64); ok {
|
||||||
|
brutalOpts["up"] = brutal["up_mbps"]
|
||||||
|
}
|
||||||
|
if _, ok := brutal["down_mbps"].(float64); ok {
|
||||||
|
brutalOpts["down"] = brutal["down_mbps"]
|
||||||
|
}
|
||||||
|
smux["brutal-opts"] = brutalOpts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proxy["smux"] = smux
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proxies = append(proxies, proxy)
|
||||||
|
proxyTags = append(proxyTags, obMap["tag"].(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
var proxyGroups []map[string]interface{}
|
||||||
|
err := yaml.Unmarshal([]byte(ProxyGroups), &proxyGroups)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyGroups[1]["proxies"] = proxyTags
|
||||||
|
proxyGroups[0]["proxies"] = append([]string{proxyGroups[1]["name"].(string)}, proxyTags...)
|
||||||
|
|
||||||
|
output := map[string]interface{}{
|
||||||
|
"proxies": proxies,
|
||||||
|
"proxy-groups": proxyGroups,
|
||||||
|
}
|
||||||
|
|
||||||
|
return yaml.Marshal(output)
|
||||||
|
}
|
||||||
+9
-5
@@ -46,17 +46,17 @@ type JsonService struct {
|
|||||||
LinkService
|
LinkService
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *JsonService) GetJson(subId string, format string) (*string, error) {
|
func (j *JsonService) GetJson(subId string, format string) (*string, []string, error) {
|
||||||
var jsonConfig map[string]interface{}
|
var jsonConfig map[string]interface{}
|
||||||
|
|
||||||
client, inDatas, err := j.getData(subId)
|
client, inDatas, err := j.getData(subId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
outbounds, outTags, err := j.getOutbounds(client.Config, inDatas)
|
outbounds, outTags, err := j.getOutbounds(client.Config, inDatas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
links := j.LinkService.GetLinks(&client.Links, "external", "")
|
links := j.LinkService.GetLinks(&client.Links, "external", "")
|
||||||
@@ -72,7 +72,7 @@ func (j *JsonService) GetJson(subId string, format string) (*string, error) {
|
|||||||
|
|
||||||
err = json.Unmarshal([]byte(defaultJson), &jsonConfig)
|
err = json.Unmarshal([]byte(defaultJson), &jsonConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonConfig["outbounds"] = outbounds
|
jsonConfig["outbounds"] = outbounds
|
||||||
@@ -82,7 +82,11 @@ func (j *JsonService) GetJson(subId string, format string) (*string, error) {
|
|||||||
|
|
||||||
result, _ := json.MarshalIndent(jsonConfig, "", " ")
|
result, _ := json.MarshalIndent(jsonConfig, "", " ")
|
||||||
resultStr := string(result)
|
resultStr := string(result)
|
||||||
return &resultStr, nil
|
|
||||||
|
updateInterval, _ := j.SettingService.GetSubUpdates()
|
||||||
|
headers := util.GetHeaders(client, updateInterval)
|
||||||
|
|
||||||
|
return &resultStr, headers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *JsonService) getData(subId string) (*model.Client, []*model.Inbound, error) {
|
func (j *JsonService) getData(subId string) (*model.Client, []*model.Inbound, error) {
|
||||||
|
|||||||
+15
-8
@@ -11,6 +11,7 @@ type SubHandler struct {
|
|||||||
service.SettingService
|
service.SettingService
|
||||||
SubService
|
SubService
|
||||||
JsonService
|
JsonService
|
||||||
|
ClashService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSubHandler(g *gin.RouterGroup) {
|
func NewSubHandler(g *gin.RouterGroup) {
|
||||||
@@ -23,29 +24,35 @@ func (s *SubHandler) initRouter(g *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubHandler) subs(c *gin.Context) {
|
func (s *SubHandler) subs(c *gin.Context) {
|
||||||
|
var headers []string
|
||||||
|
var result *string
|
||||||
|
var err error
|
||||||
subId := c.Param("subid")
|
subId := c.Param("subid")
|
||||||
format, isFormat := c.GetQuery("format")
|
format, isFormat := c.GetQuery("format")
|
||||||
if isFormat {
|
if isFormat {
|
||||||
result, err := s.JsonService.GetJson(subId, format)
|
switch format {
|
||||||
|
case "json":
|
||||||
|
result, headers, err = s.JsonService.GetJson(subId, format)
|
||||||
|
case "clash":
|
||||||
|
result, headers, err = s.ClashService.GetClash(subId)
|
||||||
|
}
|
||||||
if err != nil || result == nil {
|
if err != nil || result == nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
c.String(400, "Error!")
|
c.String(400, "Error!")
|
||||||
} else {
|
return
|
||||||
c.String(200, *result)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result, headers, err := s.SubService.GetSubs(subId)
|
result, headers, err = s.SubService.GetSubs(subId)
|
||||||
if err != nil || result == nil {
|
if err != nil || result == nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
c.String(400, "Error!")
|
c.String(400, "Error!")
|
||||||
} else {
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// Add headers
|
// Add headers
|
||||||
c.Writer.Header().Set("Subscription-Userinfo", headers[0])
|
c.Writer.Header().Set("Subscription-Userinfo", headers[0])
|
||||||
c.Writer.Header().Set("Profile-Update-Interval", headers[1])
|
c.Writer.Header().Set("Profile-Update-Interval", headers[1])
|
||||||
c.Writer.Header().Set("Profile-Title", headers[2])
|
c.Writer.Header().Set("Profile-Title", headers[2])
|
||||||
|
|
||||||
c.String(200, *result)
|
c.String(200, *result)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -6,6 +6,7 @@ import (
|
|||||||
"s-ui/database"
|
"s-ui/database"
|
||||||
"s-ui/database/model"
|
"s-ui/database/model"
|
||||||
"s-ui/service"
|
"s-ui/service"
|
||||||
|
"s-ui/util"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -34,11 +35,8 @@ func (s *SubService) GetSubs(subId string) (*string, []string, error) {
|
|||||||
linksArray := s.LinkService.GetLinks(&client.Links, "all", clientInfo)
|
linksArray := s.LinkService.GetLinks(&client.Links, "all", clientInfo)
|
||||||
result := strings.Join(linksArray, "\n")
|
result := strings.Join(linksArray, "\n")
|
||||||
|
|
||||||
var headers []string
|
|
||||||
updateInterval, _ := s.SettingService.GetSubUpdates()
|
updateInterval, _ := s.SettingService.GetSubUpdates()
|
||||||
headers = append(headers, fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", client.Up, client.Down, client.Volume, client.Expiry))
|
headers := util.GetHeaders(client, updateInterval)
|
||||||
headers = append(headers, fmt.Sprintf("%d", updateInterval))
|
|
||||||
headers = append(headers, subId)
|
|
||||||
|
|
||||||
subEncode, _ := s.SettingService.GetSubEncode()
|
subEncode, _ := s.SettingService.GetSubEncode()
|
||||||
if subEncode {
|
if subEncode {
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ func trojanOut(out *map[string]interface{}, inbound map[string]interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func vmessOut(out *map[string]interface{}, inbound map[string]interface{}) {
|
func vmessOut(out *map[string]interface{}, inbound map[string]interface{}) {
|
||||||
|
(*out)["alter_id"] = 0
|
||||||
delete(*out, "transport")
|
delete(*out, "transport")
|
||||||
if transport, ok := inbound["transport"]; ok {
|
if transport, ok := inbound["transport"]; ok {
|
||||||
(*out)["transport"] = transport
|
(*out)["transport"] = transport
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"s-ui/database/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetHeaders(client *model.Client, updateInterval int) []string {
|
||||||
|
var headers []string
|
||||||
|
headers = append(headers, fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", client.Up, client.Down, client.Volume, client.Expiry))
|
||||||
|
headers = append(headers, fmt.Sprintf("%d", updateInterval))
|
||||||
|
headers = append(headers, client.Name)
|
||||||
|
return headers
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user