Skip to content

Commit 60b9f7f

Browse files
committed
support mixed of configs wiregaurd and vless
1 parent d8e398e commit 60b9f7f

3 files changed

Lines changed: 147 additions & 50 deletions

File tree

ray2sing/awg.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,13 @@ func AWGSingboxTxt(content string) (*T.Endpoint, error) {
5555
privateKey = val
5656

5757
case "Address":
58-
pfx, err := netip.ParsePrefix(val)
59-
if err != nil {
60-
return nil, fmt.Errorf("invalid Address: %w", err)
58+
for _, add := range strings.Split(val, ",") {
59+
pfx, err := netip.ParsePrefix(strings.TrimSpace(add))
60+
if err != nil {
61+
return nil, fmt.Errorf("invalid Address: %w", err)
62+
}
63+
addresses = append(addresses, pfx)
6164
}
62-
addresses = append(addresses, pfx)
63-
6465
case "Jc":
6566
jc, _ = strconv.Atoi(val)
6667
case "Jmin":
@@ -136,7 +137,7 @@ func AWGSingboxTxt(content string) (*T.Endpoint, error) {
136137
if peer.Address == "" || peer.Port == 0 {
137138
return nil, errors.New("missing peer Endpoint")
138139
}
139-
if jc+jmin+jmax+s1+s2+s3+s4 == 0 && h1+h2+h3+h4+i1+i2+i3+i4 == "" {
140+
if true || jc+jmin+jmax+s1+s2+s3+s4 == 0 && h1+h2+h3+h4+i1+i2+i3+i4 == "" {
140141
// fmt.Println(">>out", C.TypeAwg)
141142
return &T.Endpoint{
142143
Type: C.TypeWireGuard,
@@ -298,7 +299,7 @@ func AWGSingbox(raw string) (*T.Endpoint, error) {
298299
}
299300
}
300301
var out *T.Endpoint
301-
if opts.Jc+opts.Jmin+opts.Jmax+opts.S1+opts.S2+opts.S3+opts.S4 == 0 && opts.H1+opts.H2+opts.H3+opts.H4+opts.I1+opts.I2+opts.I3+opts.I4 == "" {
302+
if true || opts.Jc+opts.Jmin+opts.Jmax+opts.S1+opts.S2+opts.S3+opts.S4 == 0 && opts.H1+opts.H2+opts.H3+opts.H4+opts.I1+opts.I2+opts.I3+opts.I4 == "" {
302303
wgopts := T.WireGuardEndpointOptions{
303304
PrivateKey: opts.PrivateKey,
304305
Address: opts.Address,

ray2sing/convert.go

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var endpointParsers = map[string]EndpointParserFunc{
5050
"wireguard://": AWGSingbox,
5151
"warp://": WarpSingbox,
5252
"awg://": AWGSingbox,
53+
"[Interface]": AWGSingboxTxt,
5354
}
5455
var xrayConfigTypes = map[string]ParserFunc{
5556
"vmess://": VmessXray,
@@ -124,70 +125,65 @@ func processSingleConfig(config string, useXrayWhenPossible bool) (outend *OutEn
124125
// json.MarshalIndent(configSingbox, "", " ")
125126
return outend, nil
126127
}
128+
127129
func GenerateConfigLite(input string, useXrayWhenPossible bool) (*option.Options, error) {
128130

129-
configArray := strings.Split(strings.ReplaceAll(input, "\r", "\n"), "\n")
131+
configArray := expandDecodedConfig(input)
130132

131133
var outbounds []T.Outbound
132134
var endpoints []T.Endpoint
133135
counter := 0
134-
if strings.Contains(input, "[Interface]") {
135-
end, err := AWGSingboxTxt(input)
136-
if err != nil {
137-
return nil, err
138-
}
139-
endpoints = append(endpoints, *end)
140-
} else {
141-
for _, config := range configArray {
142-
if len(config) < 5 || config[0] == '#' || config[0] == '/' {
143-
continue
144-
}
145-
detourTag := ""
146136

147-
chains := strings.Split(config, " -> ")
148-
for i := len(chains) - 1; i >= 0; i-- {
149-
chain1 := chains[i]
150-
151-
// fmt.Printf("%s", chain)
152-
chain, _ := decodeBase64IfNeeded(chain1)
153-
outend, err := processSingleConfig(chain, useXrayWhenPossible)
137+
for _, config := range configArray {
138+
if len(config) < 5 || config[0] == '#' || config[0] == '/' {
139+
continue
140+
}
141+
detourTag := ""
154142

155-
if err != nil {
156-
fmt.Fprintf(os.Stderr, "Error in %s \n %v\n", config, err)
143+
chains := strings.Split(config, " -> ")
144+
for i := len(chains) - 1; i >= 0; i-- {
145+
chain1 := chains[i]
157146

158-
continue
159-
}
147+
// fmt.Printf("%s", chain)
148+
chain, _ := decodeBase64IfNeeded(chain1)
149+
outend, err := processSingleConfig(chain, useXrayWhenPossible)
160150

161-
if outend.outbound != nil {
162-
outend.outbound.Tag += " § " + strconv.Itoa(counter)
163-
if dialerOpt, ok := outend.outbound.Options.(T.DialerOptionsWrapper); ok {
164-
d := dialerOpt.TakeDialerOptions()
165-
d.Detour = detourTag
166-
dialerOpt.ReplaceDialerOptions(d)
167-
}
151+
if err != nil {
152+
fmt.Fprintf(os.Stderr, "Error in %s \n %v\n", config, err)
168153

169-
detourTag = outend.outbound.Tag
170-
outbounds = append(outbounds, *outend.outbound)
154+
continue
155+
}
171156

172-
} else if outend.endpoint != nil {
173-
outend.endpoint.Tag += " § " + strconv.Itoa(counter)
174-
if dialerOpt, ok := outend.endpoint.Options.(T.DialerOptionsWrapper); ok {
175-
d := dialerOpt.TakeDialerOptions()
176-
d.Detour = detourTag
177-
dialerOpt.ReplaceDialerOptions(d)
178-
}
157+
if outend.outbound != nil {
158+
outend.outbound.Tag += " § " + strconv.Itoa(counter)
159+
if dialerOpt, ok := outend.outbound.Options.(T.DialerOptionsWrapper); ok {
160+
d := dialerOpt.TakeDialerOptions()
161+
d.Detour = detourTag
162+
dialerOpt.ReplaceDialerOptions(d)
163+
}
179164

180-
detourTag = outend.endpoint.Tag
181-
endpoints = append(endpoints, *outend.endpoint)
165+
detourTag = outend.outbound.Tag
166+
outbounds = append(outbounds, *outend.outbound)
182167

168+
} else if outend.endpoint != nil {
169+
outend.endpoint.Tag += " § " + strconv.Itoa(counter)
170+
if dialerOpt, ok := outend.endpoint.Options.(T.DialerOptionsWrapper); ok {
171+
d := dialerOpt.TakeDialerOptions()
172+
d.Detour = detourTag
173+
dialerOpt.ReplaceDialerOptions(d)
183174
}
184175

185-
counter += 1
176+
detourTag = outend.endpoint.Tag
177+
endpoints = append(endpoints, *outend.endpoint)
186178

187179
}
188180

181+
counter += 1
182+
189183
}
184+
190185
}
186+
191187
if len(outbounds) == 0 && len(endpoints) == 0 {
192188
return nil, E.New("No outbounds found")
193189
}

ray2sing/spliter.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package ray2sing
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"sort"
7+
"strings"
8+
)
9+
10+
func buildRegex() *regexp.Regexp {
11+
prefixSet := map[string]struct{}{
12+
"#": {},
13+
"//": {},
14+
}
15+
16+
for k := range configTypes {
17+
prefixSet[k] = struct{}{}
18+
}
19+
for k := range endpointParsers {
20+
prefixSet[k] = struct{}{}
21+
}
22+
for k := range xrayConfigTypes {
23+
prefixSet[k] = struct{}{}
24+
}
25+
26+
var prefixes []string
27+
for k := range prefixSet {
28+
prefixes = append(prefixes, ""+regexp.QuoteMeta(k))
29+
}
30+
31+
// IMPORTANT: longest first
32+
sort.Slice(prefixes, func(i, j int) bool {
33+
return len(prefixes[i]) > len(prefixes[j])
34+
})
35+
36+
// pattern := `(` + strings.Join(prefixes, "|") + `)`
37+
pattern := `(?m)^(?:` + strings.Join(prefixes, "|") + `)`
38+
39+
fmt.Println("Split pattern:", pattern)
40+
return regexp.MustCompile(pattern)
41+
}
42+
43+
var splitPattern = buildRegex()
44+
45+
func splitByPrefix(text string) []string {
46+
indexes := splitPattern.FindAllStringIndex(text, -1)
47+
48+
if len(indexes) == 0 {
49+
return []string{text}
50+
}
51+
52+
var result []string
53+
54+
// Preserve header
55+
// if indexes[0][0] > 0 {
56+
// result = append(result, text[:indexes[0][0]])
57+
// }
58+
59+
for i := 0; i < len(indexes); i++ {
60+
start := indexes[i][0]
61+
62+
var end int
63+
if i+1 < len(indexes) {
64+
end = indexes[i+1][0]
65+
} else {
66+
end = len(text)
67+
}
68+
69+
result = append(result, text[start:end])
70+
}
71+
72+
return result
73+
}
74+
func expandDecodedConfig(configs string) []string {
75+
res := []string{}
76+
add := func(config ...string) {
77+
for _, c := range config {
78+
tc := strings.TrimSpace(c)
79+
if tc == "" || tc[0] == '#' || tc[0] == '/' {
80+
continue
81+
}
82+
res = append(res, tc)
83+
}
84+
}
85+
86+
configs2 := []string{}
87+
for _, config := range strings.Split(configs, "\n") {
88+
configDecoded, err := decodeBase64IfNeeded(config)
89+
if err != nil {
90+
configDecoded = config
91+
}
92+
configs2 = append(configs2, strings.Split(strings.ReplaceAll(configDecoded, "\r", "\n"), "\n")...)
93+
}
94+
95+
newConfigs := splitByPrefix(strings.Join(configs2, "\n"))
96+
97+
add(newConfigs...)
98+
99+
return res
100+
}

0 commit comments

Comments
 (0)