Skip to content

Commit 0ea022c

Browse files
authored
Merge pull request #117 from ultard/main
refactor config parsing, improve code readability, add tests and CI
2 parents 953cd30 + 67e4402 commit 0ea022c

14 files changed

Lines changed: 1047 additions & 617 deletions

‎.github/workflows/libxray-test.yml‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: libXray tests
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v6
15+
16+
- name: Set up Go
17+
uses: actions/setup-go@v6
18+
with:
19+
go-version-file: go.mod
20+
cache-dependency-path: go.sum
21+
22+
- name: Go test
23+
run: go test ./... -count=1 -timeout 15m

‎build/app/build.py‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,9 @@ def prepare_static_lib(self):
7373
self.fix_package_name()
7474

7575
def copy_template_file(self):
76-
files = ["main.go"]
77-
for file in files:
78-
src_file = os.path.join(self.build_dir, "template", file)
79-
shutil.copy(src_file, self.lib_dir)
76+
src_file = os.path.join(self.build_dir, "template", "main.gotemplate")
77+
dst_file = os.path.join(self.lib_dir, "main.go")
78+
shutil.copy(src_file, dst_file)
8079

8180
def fix_package_name(self):
8281
files = os.listdir(self.lib_dir)

‎share/clash_meta.go‎

Lines changed: 25 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -132,32 +132,23 @@ type ClashProxyXhttpOptsDownloadSettings struct {
132132
}
133133

134134
func tryToParseClashYaml(text string) (*conf.Config, error) {
135-
clashBytes := []byte(text)
136-
clash := ClashYaml{}
137-
138-
err := yaml.Unmarshal(clashBytes, &clash)
139-
if err != nil {
135+
var clash ClashYaml
136+
if err := yaml.Unmarshal([]byte(text), &clash); err != nil {
140137
return nil, err
141138
}
142-
143-
xray := clash.xrayConfig()
144-
return xray, nil
139+
return clash.toXrayConfig(), nil
145140
}
146141

147-
func (clash ClashYaml) xrayConfig() *conf.Config {
148-
xray := &conf.Config{}
149-
150-
var outbounds []conf.OutboundDetourConfig
142+
func (clash ClashYaml) toXrayConfig() *conf.Config {
143+
outbounds := make([]conf.OutboundDetourConfig, 0, len(clash.Proxies))
151144
for _, proxy := range clash.Proxies {
152-
if outbound, err := proxy.outbound(); err == nil {
153-
outbounds = append(outbounds, *outbound)
154-
} else {
155-
fmt.Println(err)
145+
outbound, err := proxy.outbound()
146+
if err != nil {
147+
continue
156148
}
149+
outbounds = append(outbounds, *outbound)
157150
}
158-
xray.OutboundConfigs = outbounds
159-
160-
return xray
151+
return &conf.Config{OutboundConfigs: outbounds}
161152
}
162153

163154
func (proxy ClashProxy) outbound() (*conf.OutboundDetourConfig, error) {
@@ -202,7 +193,7 @@ func (proxy ClashProxy) outbound() (*conf.OutboundDetourConfig, error) {
202193
}
203194
return outbound, nil
204195
}
205-
return nil, fmt.Errorf("unsupport proxy type: %s", proxy.Type)
196+
return nil, fmt.Errorf("unsupported proxy type: %s", proxy.Type)
206197
}
207198

208199
func (proxy ClashProxy) shadowsocksOutbound() (*conf.OutboundDetourConfig, error) {
@@ -236,8 +227,7 @@ func (proxy ClashProxy) shadowsocksOutbound() (*conf.OutboundDetourConfig, error
236227
return nil, fmt.Errorf("unsupport ss plugin-opts mode: %s", proxy.PluginOpts.Mode)
237228
}
238229
streamSetting := &conf.StreamConfig{}
239-
network := conf.TransportProtocol("websocket")
240-
streamSetting.Network = &network
230+
streamSetting.Network = new(conf.TransportProtocol("websocket"))
241231

242232
wsSettings := &conf.WebSocketConfig{}
243233
if len(proxy.PluginOpts.Host) > 0 {
@@ -308,6 +298,8 @@ func (proxy ClashProxy) vlessOutbound() (*conf.OutboundDetourConfig, error) {
308298
settings.Flow = proxy.Flow
309299
if len(proxy.Encryption) > 0 {
310300
settings.Encryption = proxy.Encryption
301+
} else {
302+
settings.Encryption = "none"
311303
}
312304

313305
settingsRawMessage, err := convertJsonToRawMessage(settings)
@@ -418,7 +410,7 @@ func (proxy ClashProxy) streamSettings(outbound conf.OutboundDetourConfig) (*con
418410
// fix hysteria network
419411
if proxy.Type == "hysteria2" {
420412
network = "hysteria"
421-
transportProtocol = conf.TransportProtocol("hysteria")
413+
transportProtocol = "hysteria"
422414
streamSettings.Network = &transportProtocol
423415
}
424416

@@ -452,54 +444,15 @@ func (proxy ClashProxy) streamSettings(outbound conf.OutboundDetourConfig) (*con
452444
hysteriaSettings.Auth = proxy.Password
453445
streamSettings.HysteriaSettings = hysteriaSettings
454446

455-
// Build QuicParams from bandwidth and port-hopping params
456-
var quicParams *conf.QuicParamsConfig
457-
if len(proxy.Up) > 0 || len(proxy.Down) > 0 || len(proxy.Ports) > 0 {
458-
quicParams = &conf.QuicParamsConfig{}
459-
if len(proxy.Up) > 0 || len(proxy.Down) > 0 {
460-
quicParams.Congestion = "brutal"
461-
}
462-
if len(proxy.Up) > 0 {
463-
quicParams.BrutalUp = conf.Bandwidth(proxy.Up)
464-
}
465-
if len(proxy.Down) > 0 {
466-
quicParams.BrutalDown = conf.Bandwidth(proxy.Down)
467-
}
468-
if len(proxy.Ports) > 0 {
469-
udpHop := conf.UdpHop{}
470-
portListRawMessage, err := convertJsonToRawMessage(proxy.Ports)
471-
if err != nil {
472-
return nil, err
473-
}
474-
udpHop.PortList = portListRawMessage
475-
if proxy.HopInterval > 0 {
476-
udpHop.Interval = &conf.Int32Range{Left: proxy.HopInterval, Right: proxy.HopInterval, From: proxy.HopInterval, To: proxy.HopInterval}
477-
}
478-
quicParams.UdpHop = udpHop
479-
}
480-
}
481-
482-
// Build Salamander UDP masks
483-
var udpMasks []conf.Mask
484-
if proxy.Obfs == "salamander" && len(proxy.ObfsPassword) > 0 {
485-
obfs := conf.Mask{}
486-
obfs.Type = "salamander"
487-
488-
settings := &conf.Salamander{}
489-
settings.Password = proxy.ObfsPassword
490-
491-
settingsRawMessage, err := convertJsonToRawMessage(settings)
492-
if err != nil {
493-
return nil, err
494-
}
495-
obfs.Settings = &settingsRawMessage
496-
udpMasks = []conf.Mask{obfs}
447+
var hopPtr *int32
448+
if proxy.HopInterval > 0 {
449+
hopPtr = new(proxy.HopInterval)
497450
}
498-
499-
// Compose FinalMask from QuicParams + Salamander
500-
if quicParams != nil || len(udpMasks) > 0 {
501-
streamSettings.FinalMask = &conf.FinalMask{QuicParams: quicParams, Udp: udpMasks}
451+
fm, err := buildHy2FinalMask(proxy.Up, proxy.Down, proxy.Ports, hopPtr, proxy.Obfs, proxy.ObfsPassword)
452+
if err != nil {
453+
return nil, err
502454
}
455+
streamSettings.FinalMask = fm
503456
}
504457
proxy.parseSecurity(streamSettings, outbound)
505458
return streamSettings, nil
@@ -533,8 +486,7 @@ func (proxy ClashProxy) parseSecurity(streamSettings *conf.StreamConfig, outboun
533486
realitySettings.ServerName = proxy.Sni
534487
}
535488
if len(proxy.Alpn) > 0 {
536-
alpn := conf.StringList(proxy.Alpn)
537-
tlsSettings.ALPN = &alpn
489+
tlsSettings.ALPN = new(conf.StringList(proxy.Alpn))
538490
}
539491
if len(proxy.Fingerprint) > 0 {
540492
tlsSettings.Fingerprint = proxy.Fingerprint
@@ -666,8 +618,7 @@ func parseXHTTPDownloadSettings(downloadSettings *ClashProxyXhttpOptsDownloadSet
666618
streamSettings.Address = parseAddress(downloadSettings.Server)
667619
streamSettings.Port = downloadSettings.Port
668620

669-
network := conf.TransportProtocol("xhttp")
670-
streamSettings.Network = &network
621+
streamSettings.Network = new(conf.TransportProtocol("xhttp"))
671622

672623
xhttpSettings := &conf.SplitHTTPConfig{}
673624
xhttpSettings.Path = downloadSettings.Path
@@ -730,8 +681,7 @@ func parseXHTTPDownloadSettingsSecurity(streamSettings *conf.StreamConfig, proxy
730681
realitySettings.ServerName = proxy.Servername
731682
}
732683
if len(proxy.Alpn) > 0 {
733-
alpn := conf.StringList(proxy.Alpn)
734-
tlsSettings.ALPN = &alpn
684+
tlsSettings.ALPN = new(conf.StringList(proxy.Alpn))
735685
}
736686
if len(proxy.Fingerprint) > 0 {
737687
tlsSettings.Fingerprint = proxy.Fingerprint

0 commit comments

Comments
 (0)