Update On Thu Dec 11 19:44:15 CET 2025

This commit is contained in:
github-action[bot]
2025-12-11 19:44:16 +01:00
parent 616e2d9bd9
commit 128874672f
34 changed files with 644 additions and 435 deletions

1
.github/update.log vendored
View File

@@ -1208,3 +1208,4 @@ Update On Sun Dec 7 19:36:46 CET 2025
Update On Mon Dec 8 19:42:31 CET 2025 Update On Mon Dec 8 19:42:31 CET 2025
Update On Tue Dec 9 19:39:21 CET 2025 Update On Tue Dec 9 19:39:21 CET 2025
Update On Wed Dec 10 19:41:17 CET 2025 Update On Wed Dec 10 19:41:17 CET 2025
Update On Thu Dec 11 19:44:07 CET 2025

View File

@@ -1048,7 +1048,7 @@ proxies: # socks5
padding-min: 2 # 最小填充字节数 padding-min: 2 # 最小填充字节数
padding-max: 7 # 最大填充字节数 padding-max: 7 # 最大填充字节数
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3 table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v可随意组合。启用此处则需配置`table-type` # custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
http-mask: true # 是否启用http掩码 http-mask: true # 是否启用http掩码
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与服务端端保持相同(如果此处为false则要求aead不可为none) enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与服务端端保持相同(如果此处为false则要求aead不可为none)
@@ -1590,7 +1590,7 @@ listeners:
padding-min: 1 # 填充最小长度 padding-min: 1 # 填充最小长度
padding-max: 15 # 填充最大长度,均不建议过大 padding-max: 15 # 填充最大长度,均不建议过大
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3 table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v # custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
handshake-timeout: 5 # optional handshake-timeout: 5 # optional
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同(如果此处为false则要求aead不可为none) enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同(如果此处为false则要求aead不可为none)

View File

@@ -1,6 +1,10 @@
package config package config
import "encoding/json" import (
"encoding/json"
"github.com/metacubex/mihomo/listener/sing"
)
// SudokuServer describes a Sudoku inbound server configuration. // SudokuServer describes a Sudoku inbound server configuration.
// It is internal to the listener layer and mainly used for logging and wiring. // It is internal to the listener layer and mainly used for logging and wiring.
@@ -15,6 +19,9 @@ type SudokuServer struct {
HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"` HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"` EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"`
CustomTable string `json:"custom-table,omitempty"` CustomTable string `json:"custom-table,omitempty"`
// mihomo private extension (not the part of standard Sudoku protocol)
MuxOption sing.MuxOption `json:"mux-option,omitempty"`
} }
func (s SudokuServer) String() string { func (s SudokuServer) String() string {

View File

@@ -21,6 +21,9 @@ type SudokuOption struct {
HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"` HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"` EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"`
CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv
// mihomo private extension (not the part of standard Sudoku protocol)
MuxOption MuxOption `inbound:"mux-option,omitempty"`
} }
func (o SudokuOption) Equal(config C.InboundConfig) bool { func (o SudokuOption) Equal(config C.InboundConfig) bool {
@@ -55,6 +58,7 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) {
EnablePureDownlink: options.EnablePureDownlink, EnablePureDownlink: options.EnablePureDownlink,
CustomTable: options.CustomTable, CustomTable: options.CustomTable,
} }
serverConf.MuxOption = options.MuxOption.Build()
return &Sudoku{ return &Sudoku{
Base: base, Base: base,

View File

@@ -50,6 +50,8 @@ func testInboundSudoku(t *testing.T, inboundOptions inbound.SudokuOption, outbou
defer out.Close() defer out.Close()
tunnel.DoTest(t, out) tunnel.DoTest(t, out)
testSingMux(t, tunnel, out)
} }
func TestInboundSudoku_Basic(t *testing.T) { func TestInboundSudoku_Basic(t *testing.T) {

View File

@@ -9,6 +9,7 @@ import (
"github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/adapter/inbound"
C "github.com/metacubex/mihomo/constant" C "github.com/metacubex/mihomo/constant"
LC "github.com/metacubex/mihomo/listener/config" LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/listener/sing"
"github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/transport/socks5" "github.com/metacubex/mihomo/transport/socks5"
"github.com/metacubex/mihomo/transport/sudoku" "github.com/metacubex/mihomo/transport/sudoku"
@@ -19,6 +20,7 @@ type Listener struct {
addr string addr string
closed bool closed bool
protoConf sudoku.ProtocolConfig protoConf sudoku.ProtocolConfig
handler *sing.ListenerHandler
} }
// RawAddress implements C.Listener // RawAddress implements C.Listener
@@ -59,7 +61,8 @@ func (l *Listener) handleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbou
_ = session.Conn.Close() _ = session.Conn.Close()
return return
} }
tunnel.HandleTCPConn(inbound.NewSocket(targetAddr, session.Conn, C.SUDOKU, additions...)) l.handler.HandleSocket(targetAddr, session.Conn, additions...)
//tunnel.HandleTCPConn(inbound.NewSocket(targetAddr, session.Conn, C.SUDOKU, additions...))
} }
} }
@@ -122,6 +125,17 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
} }
} }
// Using sing handler for sing-mux support
h, err := sing.NewListenerHandler(sing.ListenerConfig{
Tunnel: tunnel,
Type: C.SUDOKU,
Additions: additions,
MuxOption: config.MuxOption,
})
if err != nil {
return nil, err
}
l, err := inbound.Listen("tcp", config.Listen) l, err := inbound.Listen("tcp", config.Listen)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -180,6 +194,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
listener: l, listener: l,
addr: config.Listen, addr: config.Listen,
protoConf: protoConf, protoConf: protoConf,
handler: h,
} }
go func() { go func() {

View File

@@ -362,7 +362,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
if err != nil { if err != nil {
return nil, err return nil, err
} }
tlsConn := tlsC.UClient(conn, tlsC.UConfig(config), clientFingerprint) tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil { if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil {
return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) return nil, fmt.Errorf("parse url %s error: %w", c.Path, err)
} }

View File

@@ -2,7 +2,7 @@
"manifest_version": 1, "manifest_version": 1,
"latest": { "latest": {
"mihomo": "v1.19.17", "mihomo": "v1.19.17",
"mihomo_alpha": "alpha-17b8eb8", "mihomo_alpha": "alpha-2211789",
"clash_rs": "v0.9.3", "clash_rs": "v0.9.3",
"clash_premium": "2023-09-05-gdcc8d87", "clash_premium": "2023-09-05-gdcc8d87",
"clash_rs_alpha": "0.9.3-alpha+sha.a6538ac" "clash_rs_alpha": "0.9.3-alpha+sha.a6538ac"
@@ -69,5 +69,5 @@
"linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf"
} }
}, },
"updated_at": "2025-12-09T22:21:41.769Z" "updated_at": "2025-12-10T22:21:46.086Z"
} }

View File

@@ -1,6 +1,6 @@
src-git packages https://github.com/coolsnowwolf/packages src-git packages https://github.com/coolsnowwolf/packages
#src-git luci https://github.com/coolsnowwolf/luci.git #src-git luci https://github.com/coolsnowwolf/luci.git
src-git luci https://github.com/coolsnowwolf/luci.git;openwrt-23.05 src-git luci https://github.com/coolsnowwolf/luci.git;openwrt-25.12
#src-git luci https://github.com/coolsnowwolf/luci.git;openwrt-24.10 #src-git luci https://github.com/coolsnowwolf/luci.git;openwrt-24.10
src-git routing https://github.com/coolsnowwolf/routing src-git routing https://github.com/coolsnowwolf/routing
src-git telephony https://github.com/coolsnowwolf/telephony.git src-git telephony https://github.com/coolsnowwolf/telephony.git

View File

@@ -23,13 +23,13 @@ PKG_CONFIG_DEPENDS += \
sanitize = $(call tolower,$(subst _,-,$(subst $(space),-,$(1)))) sanitize = $(call tolower,$(subst _,-,$(subst $(space),-,$(1))))
VERSION_NUMBER:=$(call qstrip,$(CONFIG_VERSION_NUMBER)) VERSION_NUMBER:=$(call qstrip,$(CONFIG_VERSION_NUMBER))
VERSION_NUMBER:=$(if $(VERSION_NUMBER),$(VERSION_NUMBER),24.10.3) VERSION_NUMBER:=$(if $(VERSION_NUMBER),$(VERSION_NUMBER),25.12-SNAPSHOT)
VERSION_CODE:=$(call qstrip,$(CONFIG_VERSION_CODE)) VERSION_CODE:=$(call qstrip,$(CONFIG_VERSION_CODE))
VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),$(REVISION)) VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),$(REVISION))
VERSION_REPO:=$(call qstrip,$(CONFIG_VERSION_REPO)) VERSION_REPO:=$(call qstrip,$(CONFIG_VERSION_REPO))
VERSION_REPO:=$(if $(VERSION_REPO),$(VERSION_REPO),https://downloads.openwrt.org/releases/24.10.3) VERSION_REPO:=$(if $(VERSION_REPO),$(VERSION_REPO),https://downloads.openwrt.org/releases/25.12-SNAPSHOT)
VERSION_DIST:=$(call qstrip,$(CONFIG_VERSION_DIST)) VERSION_DIST:=$(call qstrip,$(CONFIG_VERSION_DIST))
VERSION_DIST:=$(if $(VERSION_DIST),$(VERSION_DIST),OpenWrt) VERSION_DIST:=$(if $(VERSION_DIST),$(VERSION_DIST),OpenWrt)

View File

@@ -190,7 +190,7 @@ if VERSIONOPT
config VERSION_REPO config VERSION_REPO
string string
prompt "Release repository" prompt "Release repository"
default "https://downloads.openwrt.org/releases/24.10.3" default "https://downloads.openwrt.org/releases/25.12-SNAPSHOT"
help help
This is the repository address embedded in the image, it defaults This is the repository address embedded in the image, it defaults
to the trunk snapshot repo; the url may contain the following placeholders: to the trunk snapshot repo; the url may contain the following placeholders:

View File

@@ -256,6 +256,22 @@ endef
$(eval $(call KernelPackage,i2c-mux-mlxcpld)) $(eval $(call KernelPackage,i2c-mux-mlxcpld))
I2C_MUX_PINCTRL_MODULES:= \
CONFIG_I2C_MUX_PINCTRL:drivers/i2c/muxes/i2c-mux-pinctrl
define KernelPackage/i2c-mux-pinctrl
$(call i2c_defaults,$(I2C_MUX_PINCTRL_MODULES),51)
TITLE:=Pinctrl-based I2C mux/switches
DEPENDS:=@PINCTRL_SUPPORT @USES_DEVICETREE +kmod-i2c-mux
endef
define KernelPackage/i2c-mux-pinctrl/description
Kernel modules for Pinctrl-based I2C bus mux/switching devices
endef
$(eval $(call KernelPackage,i2c-mux-pinctrl))
I2C_MUX_REG_MODULES:= \ I2C_MUX_REG_MODULES:= \
CONFIG_I2C_MUX_REG:drivers/i2c/muxes/i2c-mux-reg CONFIG_I2C_MUX_REG:drivers/i2c/muxes/i2c-mux-reg

View File

@@ -1048,7 +1048,7 @@ proxies: # socks5
padding-min: 2 # 最小填充字节数 padding-min: 2 # 最小填充字节数
padding-max: 7 # 最大填充字节数 padding-max: 7 # 最大填充字节数
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3 table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v可随意组合。启用此处则需配置`table-type` # custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
http-mask: true # 是否启用http掩码 http-mask: true # 是否启用http掩码
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与服务端端保持相同(如果此处为false则要求aead不可为none) enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与服务端端保持相同(如果此处为false则要求aead不可为none)
@@ -1590,7 +1590,7 @@ listeners:
padding-min: 1 # 填充最小长度 padding-min: 1 # 填充最小长度
padding-max: 15 # 填充最大长度,均不建议过大 padding-max: 15 # 填充最大长度,均不建议过大
table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3 table-type: prefer_ascii # 可选值prefer_ascii、prefer_entropy 前者全ascii映射后者保证熵值汉明1低于3
# custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v # custom-table: xpxvvpvv # 可选自定义字节布局必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
handshake-timeout: 5 # optional handshake-timeout: 5 # optional
enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同(如果此处为false则要求aead不可为none) enable-pure-downlink: false # 是否启用混淆下行false的情况下能在保证数据安全的前提下极大提升下行速度与客户端保持相同(如果此处为false则要求aead不可为none)

View File

@@ -1,6 +1,10 @@
package config package config
import "encoding/json" import (
"encoding/json"
"github.com/metacubex/mihomo/listener/sing"
)
// SudokuServer describes a Sudoku inbound server configuration. // SudokuServer describes a Sudoku inbound server configuration.
// It is internal to the listener layer and mainly used for logging and wiring. // It is internal to the listener layer and mainly used for logging and wiring.
@@ -15,6 +19,9 @@ type SudokuServer struct {
HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"` HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"` EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"`
CustomTable string `json:"custom-table,omitempty"` CustomTable string `json:"custom-table,omitempty"`
// mihomo private extension (not the part of standard Sudoku protocol)
MuxOption sing.MuxOption `json:"mux-option,omitempty"`
} }
func (s SudokuServer) String() string { func (s SudokuServer) String() string {

View File

@@ -21,6 +21,9 @@ type SudokuOption struct {
HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"` HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"`
EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"` EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"`
CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv
// mihomo private extension (not the part of standard Sudoku protocol)
MuxOption MuxOption `inbound:"mux-option,omitempty"`
} }
func (o SudokuOption) Equal(config C.InboundConfig) bool { func (o SudokuOption) Equal(config C.InboundConfig) bool {
@@ -55,6 +58,7 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) {
EnablePureDownlink: options.EnablePureDownlink, EnablePureDownlink: options.EnablePureDownlink,
CustomTable: options.CustomTable, CustomTable: options.CustomTable,
} }
serverConf.MuxOption = options.MuxOption.Build()
return &Sudoku{ return &Sudoku{
Base: base, Base: base,

View File

@@ -50,6 +50,8 @@ func testInboundSudoku(t *testing.T, inboundOptions inbound.SudokuOption, outbou
defer out.Close() defer out.Close()
tunnel.DoTest(t, out) tunnel.DoTest(t, out)
testSingMux(t, tunnel, out)
} }
func TestInboundSudoku_Basic(t *testing.T) { func TestInboundSudoku_Basic(t *testing.T) {

View File

@@ -9,6 +9,7 @@ import (
"github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/adapter/inbound"
C "github.com/metacubex/mihomo/constant" C "github.com/metacubex/mihomo/constant"
LC "github.com/metacubex/mihomo/listener/config" LC "github.com/metacubex/mihomo/listener/config"
"github.com/metacubex/mihomo/listener/sing"
"github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/log"
"github.com/metacubex/mihomo/transport/socks5" "github.com/metacubex/mihomo/transport/socks5"
"github.com/metacubex/mihomo/transport/sudoku" "github.com/metacubex/mihomo/transport/sudoku"
@@ -19,6 +20,7 @@ type Listener struct {
addr string addr string
closed bool closed bool
protoConf sudoku.ProtocolConfig protoConf sudoku.ProtocolConfig
handler *sing.ListenerHandler
} }
// RawAddress implements C.Listener // RawAddress implements C.Listener
@@ -59,7 +61,8 @@ func (l *Listener) handleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbou
_ = session.Conn.Close() _ = session.Conn.Close()
return return
} }
tunnel.HandleTCPConn(inbound.NewSocket(targetAddr, session.Conn, C.SUDOKU, additions...)) l.handler.HandleSocket(targetAddr, session.Conn, additions...)
//tunnel.HandleTCPConn(inbound.NewSocket(targetAddr, session.Conn, C.SUDOKU, additions...))
} }
} }
@@ -122,6 +125,17 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
} }
} }
// Using sing handler for sing-mux support
h, err := sing.NewListenerHandler(sing.ListenerConfig{
Tunnel: tunnel,
Type: C.SUDOKU,
Additions: additions,
MuxOption: config.MuxOption,
})
if err != nil {
return nil, err
}
l, err := inbound.Listen("tcp", config.Listen) l, err := inbound.Listen("tcp", config.Listen)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -180,6 +194,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition)
listener: l, listener: l,
addr: config.Listen, addr: config.Listen,
protoConf: protoConf, protoConf: protoConf,
handler: h,
} }
go func() { go func() {

View File

@@ -362,7 +362,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
if err != nil { if err != nil {
return nil, err return nil, err
} }
tlsConn := tlsC.UClient(conn, tlsC.UConfig(config), clientFingerprint) tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint)
if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil { if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil {
return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) return nil, fmt.Errorf("parse url %s error: %w", c.Path, err)
} }

View File

@@ -48,16 +48,15 @@ end
<div id="<%=cbid%>" class="cbi-input-select" style="display:inline-block;"> <div id="<%=cbid%>" class="cbi-input-select" style="display:inline-block;">
<!-- 搜索 --> <!-- 搜索 -->
<input type="text" id="<%=cbid%>.search" class="node_search_input cbi-input-text" placeholder="<%:Search nodes...%>" <input type="text" id="<%=cbid%>.search" class="mv_search_input cbi-input-text" placeholder="<%:Search nodes...%>" />
style="width:100%;padding:6px;margin-bottom:8px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;max-height:36px;" />
<!-- 主容器 --> <!-- 主容器 -->
<div style="max-height:300px;overflow:auto;margin-bottom:8px;white-space:nowrap;"> <div class="mv_list_container">
<ul class="cbi-multi" id="<%=cbid%>.node_list" style="padding:0 !important;margin:0 !important;width:100%;box-sizing:border-box;"> <ul class="cbi-multi mv_node_list" id="<%=cbid%>.node_list">
<% for _, gname in ipairs(group_order) do %> <% for _, gname in ipairs(group_order) do %>
<% local items = groups[gname] %> <% local items = groups[gname] %>
<li class="group-block" data-group="<%=gname%>" style="list-style:none;padding:0;margin:0 0 8px 0;"> <li class="group-block" data-group="<%=gname%>">
<!-- 组标题 --> <!-- 组标题 -->
<div class="group-title" style="cursor:pointer;padding:6px;background:#f0f0f0;border-radius:4px;margin-bottom:4px;display:flex;align-items:center;white-space:nowrap;"> <div class="group-title">
<span id="arrow-<%=self.option%>-<%=gname%>" class="mv-arrow-down-small"></span> <span id="arrow-<%=self.option%>-<%=gname%>" class="mv-arrow-down-small"></span>
<b style="margin-left:8px;"><%=gname%></b> <b style="margin-left:8px;"><%=gname%></b>
<span id="group-count-<%=self.option%>-<%=gname%>" style="margin-left:8px;color:#007bff;"> <span id="group-count-<%=self.option%>-<%=gname%>" style="margin-left:8px;color:#007bff;">
@@ -65,18 +64,17 @@ end
</span> </span>
</div> </div>
<!-- 组内容 --> <!-- 组内容 -->
<ul id="group-<%=self.option%>-<%=gname%>" style="margin:0 0 8px 16px;padding:0;list-style:none;"> <ul id="group-<%=self.option%>-<%=gname%>" class="group-items">
<% for _, item in ipairs(items) do %> <% for _, item in ipairs(items) do %>
<li data-node-name="<%=pcdata(item.label):lower()%>" title="<%=pcdata(item.label)%>" style="list-style:none;padding:0;margin:0;white-space:nowrap;text-align:left;"> <li class="node-item" data-node-name="<%=pcdata(item.label):lower()%>" title="<%=pcdata(item.label)%>">
<div style="display:inline-flex;align-items:center;vertical-align:middle;"> <div class="mv-node-row">
<input type="checkbox" class="cbi-input-checkbox" style="vertical-align:middle;margin:0;margin-right:6px;" <input type="checkbox" class="cbi-input-checkbox mv-node-checkbox"
<%= attr("id", cbid .. "." .. item.key) .. <%= attr("id", cbid .. "." .. item.key) ..
attr("name", cbid) .. attr("name", cbid) ..
attr("value", item.key) .. attr("value", item.key) ..
ifattr(selected[item.key], "checked", "checked") ifattr(selected[item.key], "checked", "checked")
%> /> %> />
<label for="<%=cbid .. "." .. item.key%>" style="vertical-align:middle;margin:0;padding:0;"><%=pcdata(item.label)%></label> <label for="<%=cbid .. "." .. item.key%>" class="mv-node-label"><%=pcdata(item.label)%></label>
</div> </div>
</li> </li>
<% end %> <% end %>
@@ -86,7 +84,7 @@ end
</ul> </ul>
</div> </div>
<!-- 控制栏 --> <!-- 控制栏 -->
<div style="margin-top:4px;display:flex;gap:4px;align-items:center;"> <div class="mv-controls">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',true)" value="<%:Select all%>"> <input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',true)" value="<%:Select all%>">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',false)" value="<%:DeSelect all%>"> <input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',false)" value="<%:DeSelect all%>">
<span id="count-<%=self.option%>" style="color:#666;"></span> <span id="count-<%=self.option%>" style="color:#666;"></span>
@@ -120,6 +118,76 @@ if not _G.__NODES_MULTIVALUE_CSS_JS__ then
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }
.mv_search_input {
width: 100%;
box-sizing: border-box;
padding: 6px;
margin-bottom: 8px;
border: 1px solid #ccc;
border-radius: 4px;
max-height: 36px;
}
.mv_list_container {
max-height: 300px;
overflow: auto;
margin-bottom: 8px;
white-space: nowrap;
}
.mv_node_list {
width: 100%;
box-sizing: border-box;
padding: 0 !important;
margin: 0 !important;
}
.mv_node_list li.group-block {
list-style: none;
padding: 0;
margin: 0 0 8px 0;
}
.mv_node_list .group-title {
cursor: pointer;
display: flex;
align-items: center;
padding: 6px;
margin-bottom: 4px;
background: #f0f0f0;
border-radius: 4px;
white-space: nowrap;
}
.mv_node_list ul.group-items {
margin: 0 0 8px 16px;
padding: 0;
list-style: none;
}
.mv_node_list ul.group-items li.node-item {
list-style: none;
padding: 0;
margin: 0;
white-space: nowrap;
text-align: left;
}
.mv-node-row {
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.mv-node-checkbox {
margin: 0;
vertical-align: middle;
margin-right: 6px;
}
.mv-node-label {
margin: 0;
padding: 0;
vertical-align: middle;
cursor: pointer;
}
.mv-controls {
margin-top: 4px;
display: flex;
gap: 4px;
align-items: center;
}
</style> </style>
<script type="text/javascript"> <script type="text/javascript">

View File

@@ -204,7 +204,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -227,9 +227,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.8.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a"
[[package]] [[package]]
name = "bindgen" name = "bindgen"
@@ -246,7 +246,7 @@ dependencies = [
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -371,7 +371,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -410,22 +410,22 @@ dependencies = [
[[package]] [[package]]
name = "c2rust-bitfields" name = "c2rust-bitfields"
version = "0.20.0" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46dc7d2bffa0d0b3d47eb2dc69973466858281446c2ac9f6d8a10e92ab1017df" checksum = "dcee50917f9de1a018e3f4f9a8f2ff3d030a288cffa4b18d9b391e97c12e4cfb"
dependencies = [ dependencies = [
"c2rust-bitfields-derive", "c2rust-bitfields-derive",
] ]
[[package]] [[package]]
name = "c2rust-bitfields-derive" name = "c2rust-bitfields-derive"
version = "0.20.0" version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebe1117afa5937ce280034e31fa1e84ed1824a252f75380327eed438535333f8" checksum = "3b457277798202ccd365b9c112ebee08ddd57f1033916c8b8ea52f222e5b715d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn",
] ]
[[package]] [[package]]
@@ -440,9 +440,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.46" version = "1.2.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@@ -537,7 +537,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [ dependencies = [
"glob", "glob",
"libc", "libc",
"libloading", "libloading 0.8.9",
] ]
[[package]] [[package]]
@@ -733,7 +733,7 @@ dependencies = [
"proc-macro-error2", "proc-macro-error2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -766,22 +766,23 @@ dependencies = [
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "2.0.1" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618"
dependencies = [ dependencies = [
"derive_more-impl", "derive_more-impl",
] ]
[[package]] [[package]]
name = "derive_more-impl" name = "derive_more-impl"
version = "2.0.1" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "rustc_version",
"syn",
"unicode-xid", "unicode-xid",
] ]
@@ -820,7 +821,7 @@ dependencies = [
"libc", "libc",
"option-ext", "option-ext",
"redox_users", "redox_users",
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -831,7 +832,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -851,7 +852,7 @@ checksum = "0b0713d5c1d52e774c5cd7bb8b043d7c0fc4f921abfb678556140bfbe6ab2364"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -888,7 +889,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -927,7 +928,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -974,9 +975,9 @@ checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.1.7" version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2152dbcb980c05735e2a651d96011320a949eb31a0c8b38b72645ce97dec676" checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
@@ -1093,7 +1094,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -1237,9 +1238,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.16.0" version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]] [[package]]
name = "heapless" name = "heapless"
@@ -1453,9 +1454,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.18" version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
@@ -1469,7 +1470,7 @@ dependencies = [
"libc", "libc",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"socket2 0.5.10", "socket2 0.6.1",
"system-configuration", "system-configuration",
"tokio", "tokio",
"tower-service", "tower-service",
@@ -1549,9 +1550,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
[[package]] [[package]]
name = "icu_properties" name = "icu_properties"
version = "2.1.1" version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
dependencies = [ dependencies = [
"icu_collections", "icu_collections",
"icu_locale_core", "icu_locale_core",
@@ -1563,9 +1564,9 @@ dependencies = [
[[package]] [[package]]
name = "icu_properties_data" name = "icu_properties_data"
version = "2.1.1" version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
[[package]] [[package]]
name = "icu_provider" name = "icu_provider"
@@ -1605,9 +1606,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.12.0" version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
@@ -1741,7 +1742,7 @@ checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -1756,9 +1757,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.82" version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
@@ -1816,6 +1817,16 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "libloading"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60"
dependencies = [
"cfg-if",
"windows-link",
]
[[package]] [[package]]
name = "libmimalloc-sys" name = "libmimalloc-sys"
version = "0.1.44" version = "0.1.44"
@@ -2116,7 +2127,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -2188,7 +2199,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -2286,7 +2297,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -2409,7 +2420,7 @@ dependencies = [
"proc-macro-error-attr2", "proc-macro-error-attr2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -2441,7 +2452,7 @@ dependencies = [
"quinn-udp", "quinn-udp",
"rustc-hash", "rustc-hash",
"rustls", "rustls",
"socket2 0.5.10", "socket2 0.6.1",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing", "tracing",
@@ -2478,9 +2489,9 @@ dependencies = [
"cfg_aliases", "cfg_aliases",
"libc", "libc",
"once_cell", "once_cell",
"socket2 0.5.10", "socket2 0.6.1",
"tracing", "tracing",
"windows-sys 0.59.0", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@@ -2747,7 +2758,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -2779,9 +2790,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.13.0" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
dependencies = [ dependencies = [
"web-time", "web-time",
"zeroize", "zeroize",
@@ -2842,7 +2853,7 @@ checksum = "22f968c5ea23d555e670b449c1c5e7b2fc399fdaec1d304a17cd48e288abc107"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -2944,7 +2955,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -2998,7 +3009,7 @@ dependencies = [
[[package]] [[package]]
name = "shadowsocks" name = "shadowsocks"
version = "1.23.2" version = "1.24.0"
dependencies = [ dependencies = [
"aes", "aes",
"arc-swap", "arc-swap",
@@ -3065,7 +3076,7 @@ dependencies = [
[[package]] [[package]]
name = "shadowsocks-rust" name = "shadowsocks-rust"
version = "1.23.5" version = "1.24.0"
dependencies = [ dependencies = [
"base64", "base64",
"build-time", "build-time",
@@ -3106,7 +3117,7 @@ dependencies = [
[[package]] [[package]]
name = "shadowsocks-service" name = "shadowsocks-service"
version = "1.23.6" version = "1.24.0"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"brotli", "brotli",
@@ -3173,9 +3184,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.6" version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -3188,9 +3199,9 @@ checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.7" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
[[package]] [[package]]
name = "simdutf8" name = "simdutf8"
@@ -3317,20 +3328,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -3354,7 +3354,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -3432,7 +3432,7 @@ dependencies = [
"getrandom 0.3.4", "getrandom 0.3.4",
"once_cell", "once_cell",
"rustix", "rustix",
"windows-sys 0.59.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -3462,7 +3462,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -3567,7 +3567,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -3697,7 +3697,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -3748,7 +3748,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -3874,13 +3874,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.18.1" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
dependencies = [ dependencies = [
"getrandom 0.3.4", "getrandom 0.3.4",
"js-sys", "js-sys",
"serde", "serde_core",
"wasm-bindgen", "wasm-bindgen",
] ]
@@ -3938,9 +3938,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.105" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@@ -3951,9 +3951,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.55" version = "0.4.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@@ -3964,9 +3964,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.105" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -3974,31 +3974,31 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.105" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.105" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.82" version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@@ -4060,7 +4060,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@@ -4090,7 +4090,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -4101,7 +4101,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -4403,17 +4403,17 @@ dependencies = [
[[package]] [[package]]
name = "wintun-bindings" name = "wintun-bindings"
version = "0.7.32" version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b88303b411e20a1319b368dcd04db1480003ed46ac35193e139f542720b15fbf" checksum = "7aa9a8b4f13b95910be074d9511bec854656620ced2cccb6de08a75a56906b03"
dependencies = [ dependencies = [
"blocking", "blocking",
"c2rust-bitfields", "c2rust-bitfields",
"futures", "futures",
"libloading", "libloading 0.9.0",
"log", "log",
"thiserror", "thiserror",
"windows-sys 0.60.2", "windows-sys 0.61.2",
"winreg 0.55.0", "winreg 0.55.0",
] ]
@@ -4463,28 +4463,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
"synstructure", "synstructure",
] ]
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.27" version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.8.27" version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]
@@ -4504,7 +4504,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
"synstructure", "synstructure",
] ]
@@ -4544,7 +4544,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.110", "syn",
] ]
[[package]] [[package]]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "shadowsocks-rust" name = "shadowsocks-rust"
version = "1.23.5" version = "1.24.0"
authors = ["Shadowsocks Contributors"] authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust" repository = "https://github.com/shadowsocks/shadowsocks-rust"
@@ -126,11 +126,11 @@ dns-over-h3 = ["shadowsocks-service/dns-over-h3"]
# Enable logging output # Enable logging output
logging = [ logging = [
"log4rs", "log4rs",
"syslog-tracing",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"time", "time",
"tracing-appender", "tracing-appender",
"tracing-syslog",
] ]
# Enable DNS-relay # Enable DNS-relay
@@ -204,6 +204,9 @@ replay-attack-detect = [
"security-replay-attack-detect", "security-replay-attack-detect",
] # Backward compatibility. DO NOT USE. ] # Backward compatibility. DO NOT USE.
# Logging to syslog (Unix only)
tracing-syslog = ["dep:syslog-tracing"]
[dependencies] [dependencies]
log = "0.4" log = "0.4"
log4rs = { version = "1.2", optional = true } log4rs = { version = "1.2", optional = true }
@@ -216,6 +219,7 @@ tracing-subscriber = { version = "0.3", optional = true, features = [
"local-time", "local-time",
] } ] }
tracing-appender = { version = "0.2.3", optional = true, default-features = false } tracing-appender = { version = "0.2.3", optional = true, default-features = false }
syslog-tracing = { version = "0.3", optional = true }
time = { version = "0.3", optional = true } time = { version = "0.3", optional = true }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
@@ -244,13 +248,12 @@ jemallocator = { version = "0.5", optional = true }
snmalloc-rs = { version = "0.3", optional = true } snmalloc-rs = { version = "0.3", optional = true }
rpmalloc = { version = "0.2", optional = true } rpmalloc = { version = "0.2", optional = true }
shadowsocks-service = { version = "1.23.5", path = "./crates/shadowsocks-service", default-features = false } shadowsocks-service = { version = "1.24.0", path = "./crates/shadowsocks-service", default-features = false }
windows-service = { version = "0.8", optional = true } windows-service = { version = "0.8", optional = true }
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
xdg = "3.0" xdg = "3.0"
syslog-tracing = { version = "0.3", optional = true }
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] [target.'cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))'.dependencies]
reqwest = { version = "0.12", features = [ reqwest = { version = "0.12", features = [

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "shadowsocks-service" name = "shadowsocks-service"
version = "1.23.6" version = "1.24.0"
authors = ["Shadowsocks Contributors"] authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust" repository = "https://github.com/shadowsocks/shadowsocks-rust"
@@ -199,7 +199,7 @@ json5 = "1.3"
serde_json = "1.0" serde_json = "1.0"
bson = { version = "3.0.0", features = ["serde"], optional = true } bson = { version = "3.0.0", features = ["serde"], optional = true }
shadowsocks = { version = "1.23.2", path = "../shadowsocks", default-features = false } shadowsocks = { version = "1.24.0", path = "../shadowsocks", default-features = false }
# Just for the ioctl call macro # Just for the ioctl call macro
[target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd"))'.dependencies] [target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd"))'.dependencies]

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "shadowsocks" name = "shadowsocks"
version = "1.23.2" version = "1.24.0"
authors = ["Shadowsocks Contributors"] authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust" repository = "https://github.com/shadowsocks/shadowsocks-rust"

View File

@@ -131,7 +131,7 @@ async fn tcp_tunnel_example(
let mut client = TcpStream::connect(local_addr).await?; let mut client = TcpStream::connect(local_addr).await?;
const HTTP_REQUEST: &[u8] = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\nConnection: close\r\n\r\n"; const HTTP_REQUEST: &[u8] = b"GET / HTTP/1.1\r\nHost: www.example.com\r\nAccept: */*\r\nConnection: close\r\n\r\n";
client.write_all(HTTP_REQUEST).await?; client.write_all(HTTP_REQUEST).await?;
let mut reader = BufReader::new(client); let mut reader = BufReader::new(client);
@@ -141,7 +141,7 @@ async fn tcp_tunnel_example(
println!("{:?}", ByteStr::new(&buffer)); println!("{:?}", ByteStr::new(&buffer));
const HTTP_RESPONSE_STATUS: &[u8] = b"HTTP/1.0 200 OK\r\n"; const HTTP_RESPONSE_STATUS: &[u8] = b"HTTP/1.1 200 OK\r\n";
assert!(buffer.starts_with(HTTP_RESPONSE_STATUS)); assert!(buffer.starts_with(HTTP_RESPONSE_STATUS));
Ok(()) Ok(())

View File

@@ -86,7 +86,7 @@ async fn tcp_tunnel_tfo() {
.unwrap(); .unwrap();
client client
.write_all(b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\nConnection: close\r\n\r\n") .write_all(b"GET / HTTP/1.1\r\nHost: www.example.com\r\nAccept: */*\r\nConnection: close\r\n\r\n")
.await .await
.unwrap(); .unwrap();
@@ -97,6 +97,6 @@ async fn tcp_tunnel_tfo() {
println!("{:?}", ByteStr::new(&buffer)); println!("{:?}", ByteStr::new(&buffer));
const HTTP_RESPONSE_STATUS: &[u8] = b"HTTP/1.0 200 OK\r\n"; const HTTP_RESPONSE_STATUS: &[u8] = b"HTTP/1.1 200 OK\r\n";
assert!(buffer.starts_with(HTTP_RESPONSE_STATUS)); assert!(buffer.starts_with(HTTP_RESPONSE_STATUS));
} }

View File

@@ -1,3 +1,17 @@
shadowsocks-rust (1.24.0) unstable; urgency=medium
## Features
- #1993, #2044 Support logging to file and syslog
- #2026 HTTP Client support auto retry if cached connection was lost
## Miscellaneous
- RUSTSEC-2025-0120, `json5` upgraded to v1.3
- MSRV bumps to v1.88
-- ty <zonyitoo@gmail.com> Thur, 11 Dec 2025 07:37:00 +0800
shadowsocks-rust (1.23.5) unstable; urgency=medium shadowsocks-rust (1.23.5) unstable; urgency=medium
## Features ## Features

View File

@@ -99,7 +99,7 @@ async fn socks5_relay_stream() {
.await .await
.unwrap(); .unwrap();
let req = b"GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n"; let req = b"GET / HTTP/1.1\r\nHost: www.example.com\r\nAccept: */*\r\nConnection: close\r\n\r\n";
c.write_all(req).await.unwrap(); c.write_all(req).await.unwrap();
c.flush().await.unwrap(); c.flush().await.unwrap();
@@ -108,8 +108,8 @@ async fn socks5_relay_stream() {
let mut buf = Vec::new(); let mut buf = Vec::new();
r.read_until(b'\n', &mut buf).await.unwrap(); r.read_until(b'\n', &mut buf).await.unwrap();
let http_status = b"HTTP/1.0 200 OK\r\n"; let http_status = b"HTTP/1.1 200 OK\r\n";
assert!(buf.starts_with(http_status)); assert!(buf.starts_with(http_status), "buf: {:?}", str::from_utf8(&buf));
} }
#[tokio::test] #[tokio::test]

View File

@@ -2,10 +2,11 @@
set -xeuo pipefail set -xeuo pipefail
TARGET="$1" TARGET="$1"
VERSION="$2"
# Download musl-cross toolchain from musl.cc # Download musl-cross toolchain from cross-tools/musl-cross GitHub releases
cd "$HOME" cd "$HOME"
wget -q "https://musl.cc/${TARGET}-cross.tgz" curl -Lo "${TARGET}.tar.xz" "https://github.com/cross-tools/musl-cross/releases/download/${VERSION}/${TARGET}.tar.xz"
mkdir -p musl-cross mkdir -p musl-cross
tar -xf "${TARGET}-cross.tgz" -C musl-cross --strip-components=1 tar -xf "${TARGET}.tar.xz" -C musl-cross --strip-components=1
rm "${TARGET}-cross.tgz" rm "${TARGET}.tar.xz"

View File

@@ -62,7 +62,7 @@ jobs:
echo "version=$version" >> "$GITHUB_OUTPUT" echo "version=$version" >> "$GITHUB_OUTPUT"
build: build:
name: Build binary name: Build binary
if: false # TODO: temporarily disabled for testing if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- calculate_version - calculate_version
@@ -71,31 +71,31 @@ jobs:
include: include:
# Linux with naive outbound (CGO enabled with Debian Bullseye sysroot) # Linux with naive outbound (CGO enabled with Debian Bullseye sysroot)
- { os: linux, arch: amd64, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64", sysroot_sha: "36a164623d03f525e3dfb783a5e9b8a00e98e1ddd2b5cff4e449bd016dd27e50", cc_target: "x86_64-linux-gnu" } - { os: linux, arch: amd64, naive: true, debian: amd64, rpm: x86_64, pacman: x86_64, openwrt: "x86_64", sysroot_sha: "36a164623d03f525e3dfb783a5e9b8a00e98e1ddd2b5cff4e449bd016dd27e50", cc_target: "x86_64-linux-gnu" }
- { os: linux, arch: arm64, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic", sysroot_sha: "2f915d821eec27515c0c6d21b69898e23762908d8d7ccc1aa2a8f5f25e8b7e18", cc_target: "aarch64-linux-gnu", cross_pkg: "libc6-dev-arm64-cross" } - { os: linux, arch: arm64, naive: true, debian: arm64, rpm: aarch64, pacman: aarch64, openwrt: "aarch64_cortex-a53 aarch64_cortex-a72 aarch64_cortex-a76 aarch64_generic", sysroot_sha: "2f915d821eec27515c0c6d21b69898e23762908d8d7ccc1aa2a8f5f25e8b7e18", cc_target: "aarch64-linux-gnu", cross_pkg: "libc6-dev-arm64-cross", linker: "bfd" }
- { os: linux, arch: "386", naive: true, go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4", sysroot_sha: "63f0e5128b84f7b0421956a4a40affa472be8da0e58caf27e9acbc84072daee7", cc_target: "i686-linux-gnu", cross_pkg: "libc6-dev-i386-cross" } - { os: linux, arch: "386", naive: true, go386: sse2, debian: i386, rpm: i386, openwrt: "i386_pentium4", sysroot_sha: "63f0e5128b84f7b0421956a4a40affa472be8da0e58caf27e9acbc84072daee7", cc_target: "i686-linux-gnu", cross_pkg: "libc6-dev-i386-cross" }
- { os: linux, arch: arm, naive: true, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4", sysroot_sha: "47b3a0b161ca011b2b33d4fc1ef6ef269b8208a0b7e4c900700c345acdfd1814", cc_target: "arm-linux-gnueabihf", cross_pkg: "libc6-dev-armhf-cross", linker: "bfd" } - { os: linux, arch: arm, naive: true, goarm: "7", debian: armhf, rpm: armv7hl, pacman: armv7hl, openwrt: "arm_cortex-a5_vfpv4 arm_cortex-a7_neon-vfpv4 arm_cortex-a7_vfpv4 arm_cortex-a8_vfpv3 arm_cortex-a9_neon arm_cortex-a9_vfpv3-d16 arm_cortex-a15_neon-vfpv4", sysroot_sha: "47b3a0b161ca011b2b33d4fc1ef6ef269b8208a0b7e4c900700c345acdfd1814", cc_target: "arm-linux-gnueabihf", cross_pkg: "libc6-dev-armhf-cross binutils-arm-linux-gnueabihf", linker: "bfd" }
# Linux without naive outbound (no CGO) # Linux without naive outbound (no CGO)
- { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" } # - { os: linux, arch: "386", go386: softfloat, openwrt: "i386_pentium-mmx" }
- { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" } # - { os: linux, arch: arm, goarm: "5", openwrt: "arm_arm926ej-s arm_cortex-a7 arm_cortex-a9 arm_fa526 arm_xscale" }
- { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl, openwrt: "arm_arm1176jzf-s_vfp" } # - { os: linux, arch: arm, goarm: "6", debian: armel, rpm: armv6hl, openwrt: "arm_arm1176jzf-s_vfp" }
- { os: linux, arch: mips, gomips: softfloat, openwrt: "mips_24kc mips_4kec mips_mips32" } # - { os: linux, arch: mips, gomips: softfloat, openwrt: "mips_24kc mips_4kec mips_mips32" }
- { os: linux, arch: mipsle, gomips: hardfloat, debian: mipsel, rpm: mipsel, openwrt: "mipsel_24kc_24kf" } # - { os: linux, arch: mipsle, gomips: hardfloat, debian: mipsel, rpm: mipsel, openwrt: "mipsel_24kc_24kf" }
- { os: linux, arch: mipsle, gomips: softfloat, openwrt: "mipsel_24kc mipsel_74kc mipsel_mips32" } # - { os: linux, arch: mipsle, gomips: softfloat, openwrt: "mipsel_24kc mipsel_74kc mipsel_mips32" }
- { os: linux, arch: mips64, gomips: softfloat, openwrt: "mips64_mips64r2 mips64_octeonplus" } # - { os: linux, arch: mips64, gomips: softfloat, openwrt: "mips64_mips64r2 mips64_octeonplus" }
- { os: linux, arch: mips64le, gomips: hardfloat, debian: mips64el, rpm: mips64el } # - { os: linux, arch: mips64le, gomips: hardfloat, debian: mips64el, rpm: mips64el }
- { os: linux, arch: mips64le, gomips: softfloat, openwrt: "mips64el_mips64r2" } # - { os: linux, arch: mips64le, gomips: softfloat, openwrt: "mips64el_mips64r2" }
- { os: linux, arch: s390x, debian: s390x, rpm: s390x } # - { os: linux, arch: s390x, debian: s390x, rpm: s390x }
- { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le } # - { os: linux, arch: ppc64le, debian: ppc64el, rpm: ppc64le }
- { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64, openwrt: "riscv64_generic" } # - { os: linux, arch: riscv64, debian: riscv64, rpm: riscv64, openwrt: "riscv64_generic" }
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" } # - { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" }
# Windows 7 legacy (no naive, no CGO) # Windows 7 legacy (no naive, no CGO)
- { os: windows, arch: amd64, legacy_win7: true, legacy_name: "windows-7" } # - { os: windows, arch: amd64, legacy_win7: true, legacy_name: "windows-7" }
- { os: windows, arch: "386", legacy_win7: true, legacy_name: "windows-7" } # - { os: windows, arch: "386", legacy_win7: true, legacy_name: "windows-7" }
# Android (naive enabled) # Android (naive enabled)
- { os: android, arch: arm64, ndk: "aarch64-linux-android21" } # - { os: android, arch: arm64, ndk: "aarch64-linux-android21" }
- { os: android, arch: arm, ndk: "armv7a-linux-androideabi21" } # - { os: android, arch: arm, ndk: "armv7a-linux-androideabi21" }
- { os: android, arch: amd64, ndk: "x86_64-linux-android21" } # - { os: android, arch: amd64, ndk: "x86_64-linux-android21" }
- { os: android, arch: "386", ndk: "i686-linux-android21" } # - { os: android, arch: "386", ndk: "i686-linux-android21" }
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
@@ -390,16 +390,16 @@ jobs:
path: "dist" path: "dist"
build_windows: build_windows:
name: Build Windows binaries name: Build Windows binaries
if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary' if: false # TODO: temporarily disabled for testing
runs-on: windows-latest runs-on: windows-latest
needs: needs:
- calculate_version - calculate_version
strategy: strategy:
matrix: matrix:
include: include:
- { arch: amd64, cc: x86_64-w64-mingw32-clang } - { arch: amd64 }
- { arch: "386", cc: i686-w64-mingw32-clang } - { arch: "386" }
- { arch: arm64, cc: aarch64-w64-mingw32-clang } - { arch: arm64 }
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
@@ -409,26 +409,6 @@ jobs:
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: ^1.25.4 go-version: ^1.25.4
- name: Cache llvm-mingw
id: cache-llvm-mingw
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/llvm-mingw
key: llvm-mingw-ucrt-x86_64
- name: Setup llvm-mingw
if: steps.cache-llvm-mingw.outputs.cache-hit != 'true'
run: |
$headers = @{ Authorization = "Bearer $env:GITHUB_TOKEN" }
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/mstorsjo/llvm-mingw/releases/latest" -Headers $headers
$asset = $release.assets | Where-Object { $_.name -like "llvm-mingw-*-ucrt-x86_64.zip" }
curl -Lo llvm-mingw.zip $asset.browser_download_url
Expand-Archive llvm-mingw.zip -DestinationPath $env:RUNNER_TEMP/llvm-mingw
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Setup llvm-mingw PATH
run: |
$extractedDir = Get-ChildItem -Path $env:RUNNER_TEMP/llvm-mingw -Directory | Where-Object { $_.Name -like "llvm-mingw-*" } | Select-Object -First 1
echo "$($extractedDir.FullName)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Set tag - name: Set tag
run: |- run: |-
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$env:GITHUB_ENV" git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$env:GITHUB_ENV"
@@ -436,16 +416,13 @@ jobs:
- name: Build - name: Build
run: | run: |
mkdir -p dist mkdir -p dist
go build -v -trimpath -o dist/sing-box.exe -tags "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,badlinkname,tfogo_checklinkname0" ` go build -v -trimpath -o dist/sing-box.exe -tags "with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0" `
-ldflags "-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0" ` -ldflags "-s -buildid= -X github.com/sagernet/sing-box/constant.Version=${{ needs.calculate_version.outputs.version }} -checklinkname=0" `
./cmd/sing-box ./cmd/sing-box
env: env:
CGO_ENABLED: "1" CGO_ENABLED: "0"
CGO_LDFLAGS_ALLOW: "-Wl,-Xlink=.*"
GOOS: windows GOOS: windows
GOARCH: ${{ matrix.arch }} GOARCH: ${{ matrix.arch }}
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cc }}++
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Archive - name: Archive
run: | run: |
@@ -464,17 +441,17 @@ jobs:
path: "dist" path: "dist"
build_linux_musl: build_linux_musl:
name: Build Linux musl static binaries name: Build Linux musl static binaries
if: false # TODO: temporarily disabled for testing if: github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Binary'
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: needs:
- calculate_version - calculate_version
strategy: strategy:
matrix: matrix:
include: include:
- { arch: amd64, cc_target: "x86_64-linux-musl" } - { arch: amd64, cc_target: "x86_64-unknown-linux-musl" }
- { arch: arm64, cc_target: "aarch64-linux-musl" } - { arch: arm64, cc_target: "aarch64-unknown-linux-musl" }
- { arch: "386", cc_target: "i686-linux-musl" } - { arch: "386", cc_target: "i686-unknown-linux-musl" }
- { arch: arm, goarm: "7", cc_target: "arm-linux-musleabihf" } - { arch: arm, goarm: "7", cc_target: "arm-unknown-linux-musleabihf" }
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
@@ -488,11 +465,26 @@ jobs:
run: |- run: |-
git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV" git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV"
git tag v${{ needs.calculate_version.outputs.version }} -f git tag v${{ needs.calculate_version.outputs.version }} -f
- name: Get musl-cross version
id: musl-cross-version
run: |
MUSL_CROSS_VERSION=$(curl -s https://api.github.com/repos/cross-tools/musl-cross/releases/latest | jq -r '.tag_name')
echo "version=$MUSL_CROSS_VERSION" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Cache musl cross compiler
id: cache-musl-cross
uses: actions/cache@v4
with:
path: ~/musl-cross
key: musl-cross-${{ steps.musl-cross-version.outputs.version }}-${{ matrix.cc_target }}
- name: Install musl cross compiler - name: Install musl cross compiler
if: steps.cache-musl-cross.outputs.cache-hit != 'true'
run: | run: |
set -xeuo pipefail set -xeuo pipefail
.github/setup_musl_cross.sh "${{ matrix.cc_target }}" .github/setup_musl_cross.sh "${{ matrix.cc_target }}" "${{ steps.musl-cross-version.outputs.version }}"
echo "PATH=$HOME/musl-cross/bin:$PATH" >> $GITHUB_ENV - name: Setup musl cross compiler PATH
run: echo "PATH=$HOME/musl-cross/bin:$PATH" >> $GITHUB_ENV
- name: Build - name: Build
run: | run: |
set -xeuo pipefail set -xeuo pipefail

View File

@@ -25,8 +25,8 @@ require (
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
github.com/sagernet/cors v1.2.1 github.com/sagernet/cors v1.2.1
github.com/sagernet/cronet-go v0.0.0-20251210132647-15dd6a9ee4bc github.com/sagernet/cronet-go v0.0.0-20251211071908-d994f13571ba
github.com/sagernet/cronet-go/all v0.0.0-20251210133029-b0d1058a9fcf github.com/sagernet/cronet-go/all v0.0.0-20251211072252-8f77f5c5848f
github.com/sagernet/fswatch v0.1.1 github.com/sagernet/fswatch v0.1.1
github.com/sagernet/gomobile v0.1.8 github.com/sagernet/gomobile v0.1.8
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
@@ -75,6 +75,7 @@ require (
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 // indirect
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect
github.com/ebitengine/purego v0.9.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gaissmai/bart v0.18.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect
@@ -106,24 +107,24 @@ require (
github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/prometheus-community/pro-bing v0.4.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect
github.com/safchain/ethtool v0.3.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251210132647-15dd6a9ee4bc // indirect github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251211071908-d994f13571ba // indirect
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect
github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/pflag v1.0.6 // indirect

View File

@@ -41,6 +41,8 @@ github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbY
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q=
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A=
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
@@ -150,46 +152,46 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
github.com/sagernet/cronet-go v0.0.0-20251210132647-15dd6a9ee4bc h1:TeUwtjNOirI7QW6RUGmzovZHiImdyysxdXii8tj2pjE= github.com/sagernet/cronet-go v0.0.0-20251211071908-d994f13571ba h1:uEZ645opD3gDssWu8VH7x2Rgb9ezHE2ECnhNHASEdvI=
github.com/sagernet/cronet-go v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:l5IZJLEWpDGJbrF0qBHgxAVBPsAxKOLa1BYDh6B2sdI= github.com/sagernet/cronet-go v0.0.0-20251211071908-d994f13571ba/go.mod h1:DzcRxPQdpy5y2bbabpFXotAzPfY2P4HKZ8rQj3dSClo=
github.com/sagernet/cronet-go/all v0.0.0-20251210133029-b0d1058a9fcf h1:9HfW4vwWSXSOBcxT3s7MAyxGnAxPpcFiRHW/9ImtlFA= github.com/sagernet/cronet-go/all v0.0.0-20251211072252-8f77f5c5848f h1:eNJ50vQ6ZDiNEaGlgHi7xW7q1NMXvA+0XTY3XqQ5ZUw=
github.com/sagernet/cronet-go/all v0.0.0-20251210133029-b0d1058a9fcf/go.mod h1:hljs4OQivwLEGy9ijqAQ7/bKfdfIOnudIuBKVWGpuNU= github.com/sagernet/cronet-go/all v0.0.0-20251211072252-8f77f5c5848f/go.mod h1:x15eluLV7eszr9QM9LB1msVSvt9Ec35FJzrDAWktzPk=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251210132647-15dd6a9ee4bc h1:7RwE5fT6D/bH8g/Sp/+bFPTTgYEHk8mI3wcP9nfOkfc= github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251211071908-d994f13571ba h1:TXY0fuTlfKC0+87QyW/Zc/sCrEYuwtLaIUyuY6T/ntg=
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw= github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251211071908-d994f13571ba/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:5ABO0dzl0FREp4yOj8tRUil8Rnr+UxAbgHm6/1/GaUs= github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251211071908-d994f13571ba h1:g/zisDHC/rur4BcZPU0hiIFIotmvzW1QpdKBTUJHQGo=
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM= github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251210132647-15dd6a9ee4bc h1:6RWqk2JxL/JoyxeahfV6nWj0HpRJXKM42hAZAobprLk= github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251211071908-d994f13571ba h1:bLZEGfnO0ZLi5wQ/F53p184iwp3CjwsBv8OXdO5XtU8=
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc= github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251211071908-d994f13571ba/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:GHUnWWlndwxHw4pEvw40ISO7xrMq+h+P+FQ3KrGlghQ= github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251211071908-d994f13571ba h1:WJYMPsC22fPYJwcmxpwqLgfITOwvqZq1h/DAW/gwzMk=
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ= github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:urmRC1HxIetnZuyaPkHketyrhWBhwvRr74XXEHmqgLc= github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251211071908-d994f13571ba h1:pHAqbKMEZbpy2l3z/4vfmigKHZU4JAg/Lmvjw8065ac=
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs= github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:EN57YqGy2cbeQexLBb6vf1IcCEjNmz6sSoMNOik8DJQ= github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251211071908-d994f13571ba h1:FU9JW6n20iSXYPYKhEwAwt0KM2zsRIGo4U4HRNEsa0c=
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0= github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:aRFCWKVFt5aTbcHQ7rUWLtfpxVtUbB1t1VDEgMm1LdY= github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251211071908-d994f13571ba h1:+X+fSmuU0omwBmGFkbQsRABGdEJuPt3yIgKXcn7R46w=
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4= github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251210132647-15dd6a9ee4bc h1:txzvlKqPSL3yUVQs0DOx1bc0ONEuiWqIEoaQvMJNqdk= github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251211071908-d994f13571ba h1:cFw2hkY4rvyqbrDWHOqdZJVNJIzTRmqE56rn9fNgJ+0=
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ= github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251211071908-d994f13571ba/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:DdYm5omtBr6/0DyCG5cTS4fK8hXoPXeEWiaBhDdUqac= github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251211071908-d994f13571ba h1:lnQAAKRO5sKmmj91DbPcbTN1Zz5SnRfSik+hYySKUI0=
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU= github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251211071908-d994f13571ba/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:qZ5koP16Y5Wbzi89bRA3c2C9vUlZPk7uz5ZLBAd/4h4= github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251211071908-d994f13571ba h1:iDCEnpbjDGlPX4sKXpQqUnvMoB2Ly8WPquN7AVJXW30=
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI= github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:nz3DMrICKuhS9ht7Hx1Hc1Al4LtfPADK/SbKrJ/UXKc= github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251211071908-d994f13571ba h1:pih/YmfyihzRVXIvKRumLk7/yIFG75GKJ11dzY66f2c=
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ= github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251211071908-d994f13571ba/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251210132647-15dd6a9ee4bc h1:5OLCnge+qhMLS1HBz/KY803Pd3IRC7Q9KP71GZMM+p0= github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251211071908-d994f13571ba h1:fkYcplf4fGEUpL15nfot25LW7qlEcfTspVZcPt2pJyU=
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0= github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251211071908-d994f13571ba/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:pg9jxoJQsiSxRBCTsFHXATGmSLMpsdvdCvVNhpMEdDA= github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251211071908-d994f13571ba h1:jKhRxlzLFtyLbS3q2Linq0NlBIN2G9cvkbZQhqfZCV4=
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s= github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:gAnasnvsCH8seCtYsfFoWsHeldBZUKPvarSjt9bKIak= github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251211071908-d994f13571ba h1:lkIHvbG6vbTdZTfmgJd7owEA1TaTU2r72D6EWTPLY/Q=
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ= github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251211071908-d994f13571ba/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251210132647-15dd6a9ee4bc h1:YVBUW8D3w/c0F5N3F+5rnXyNPNDODFPVw1NAWfsQv2Q= github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251211071908-d994f13571ba h1:hhi9W43vZ+4F+lo70f+pCxF20KTEwUWFSuFp4EC/WDo=
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow= github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251211071908-d994f13571ba/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251210132647-15dd6a9ee4bc h1:8w1wlyIpIcH3/1LPe6NMxZxLpsTq+00FEoSrMl+o03o= github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251211071908-d994f13571ba h1:oj6hb5uIDMF4CNgWxTxD9IrCfPidILKfWH/3TVBVAvU=
github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk= github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251211071908-d994f13571ba/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251210132647-15dd6a9ee4bc h1:Qwof0qMpoRXycadI1OWgwj7OTaCZQqoYbwqVAKd4rrs= github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251211071908-d994f13571ba h1:89MTTjIGU1vJjmuc+wB9rv+lUcVc2F5SPb9LL3f3wK4=
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251210132647-15dd6a9ee4bc h1:/2D4fyTJjYwf5NzgnOuTElGpX6fFN2dFAf/x0L0w1pI= github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251211071908-d994f13571ba h1:rCbyVr847cAASpo5qBrqRNrH3hQhVpFFtH3GUuWQVhA=
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251210132647-15dd6a9ee4bc/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251211071908-d994f13571ba/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
github.com/sagernet/gomobile v0.1.8 h1:vXgoN0pjsMONAaYCTdsKBX2T1kxuS7sbT/mZ7PElGoo= github.com/sagernet/gomobile v0.1.8 h1:vXgoN0pjsMONAaYCTdsKBX2T1kxuS7sbT/mZ7PElGoo=

View File

@@ -1,5 +1,10 @@
<%+cbi/valueheader%> <%+cbi/valueheader%>
<% <%
-- Template Developers:
-- - lwb1978
-- Copyright: copyright(c)20252027
-- Description: Passwall(2) UI template
local cbid = "cbid." .. self.config .. "." .. section .. "." .. self.option local cbid = "cbid." .. self.config .. "." .. section .. "." .. self.option
-- 读取 MultiValue -- 读取 MultiValue
@@ -41,69 +46,36 @@ for _, item in ipairs(values) do
end end
%> %>
<style> <div id="<%=cbid%>" class="cbi-input-select" style="display:inline-block;">
/* 组标题的右箭头(折叠) */
.lv-arrow-right {
width: 0;
height: 0;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid #555;
display: inline-block;
vertical-align: middle;
}
/* 组标题的下箭头(展开) */
.lv-arrow-down-small {
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid #555;
display: inline-block;
vertical-align: middle;
}
</style>
<div id="<%=cbid%>" class="cbi-input-select" style="display: inline-block;">
<!-- 搜索 --> <!-- 搜索 -->
<input type="text" <input type="text" id="<%=cbid%>.search" class="mv_search_input cbi-input-text" placeholder="<%:Search nodes...%>" />
id="<%=cbid%>.search"
class="node-search-input cbi-input-text"
placeholder="<%:Search nodes...%>"
oninput="filterGroups_<%=self.option%>(this.value)"
style="width:100%;padding:6px;margin-bottom:8px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box;max-height:36px;" />
<!-- 主容器 --> <!-- 主容器 -->
<div style="max-height:300px; overflow:auto; margin-bottom:8px; white-space:nowrap;"> <div class="mv_list_container">
<ul class="cbi-multi" id="<%=cbid%>.node_list" style="padding:0 !important;margin:0 !important;width:100%;box-sizing:border-box;"> <ul class="cbi-multi mv_node_list" id="<%=cbid%>.node_list">
<% for _, gname in ipairs(group_order) do %> <% for _, gname in ipairs(group_order) do %>
<% local items = groups[gname] %> <% local items = groups[gname] %>
<li class="group-block" data-group="<%=gname%>" style="list-style:none; padding:0; margin:0 0 8px 0;"> <li class="group-block" data-group="<%=gname%>">
<!-- 组标题 --> <!-- 组标题 -->
<div class="group-title" <div class="group-title">
onclick="toggleGroup_<%=self.option%>('<%=gname%>')" <span id="arrow-<%=self.option%>-<%=gname%>" class="mv-arrow-down-small"></span>
style="cursor:pointer;padding:6px;background:#f0f0f0;border-radius:4px;margin-bottom:4px;display:flex;align-items:center;white-space:nowrap;">
<span id="arrow-<%=self.option%>-<%=gname%>" class="lv-arrow-down-small"></span>
<b style="margin-left:8px;"><%=gname%></b> <b style="margin-left:8px;"><%=gname%></b>
<span id="group-count-<%=self.option%>-<%=gname%>" style="margin-left:8px;color:#007bff;"> <span id="group-count-<%=self.option%>-<%=gname%>" style="margin-left:8px;color:#007bff;">
(0/<%=#items%>) (0/<%=#items%>)
</span> </span>
</div> </div>
<!-- 组内容(可折叠)--> <!-- 组内容 -->
<ul id="group-<%=self.option%>-<%=gname%>" style="margin:0 0 8px 16px; padding:0; list-style:none;"> <ul id="group-<%=self.option%>-<%=gname%>" class="group-items">
<% for _, item in ipairs(items) do %> <% for _, item in ipairs(items) do %>
<li data-node-name="<%=pcdata(item.label):lower()%>" style="list-style:none;padding:0;margin:0;white-space:nowrap;" title="<%=pcdata(item.label)%>"> <li class="node-item" data-node-name="<%=pcdata(item.label):lower()%>" title="<%=pcdata(item.label)%>">
<input <div class="mv-node-row">
type="checkbox" <input type="checkbox" class="cbi-input-checkbox mv-node-checkbox"
class="cbi-input-checkbox" <%= attr("id", cbid .. "." .. item.key) ..
style="vertical-align: middle; margin-right:6px;" attr("name", cbid) ..
<%= attr("id", cbid .. "." .. item.key) .. attr("value", item.key) ..
attr("name", cbid) .. ifattr(selected[item.key], "checked", "checked")
attr("value", item.key) .. %> />
ifattr(selected[item.key], "checked", "checked") <label for="<%=cbid .. "." .. item.key%>" class="mv-node-label"><%=pcdata(item.label)%></label>
%> /> </div>
<label for="<%=cbid .. "." .. item.key%>"><%=pcdata(item.label)%></label>
</li> </li>
<% end %> <% end %>
</ul> </ul>
@@ -112,73 +84,173 @@ end
</ul> </ul>
</div> </div>
<!-- 控制栏 --> <!-- 控制栏 -->
<div style="margin-top:4px;display:flex;gap:4px;align-items:center;"> <div class="mv-controls">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="selectAll_<%=self.option%>(true)" value="<%:Select all%>"> <input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',true)" value="<%:Select all%>">
<input class="btn cbi-button cbi-button-edit" type="button" onclick="selectAll_<%=self.option%>(false)" value="<%:DeSelect all%>"> <input class="btn cbi-button cbi-button-edit" type="button" onclick="mv_selectAll('<%=cbid%>','<%=self.option%>',false)" value="<%:DeSelect all%>">
<span id="count-<%=self.option%>" style="color:#666;"></span> <span id="count-<%=self.option%>" style="color:#666;"></span>
</div> </div>
</div> </div>
<%+cbi/valuefooter%> <%+cbi/valuefooter%>
<%
-- 公共部分(只加载一次)
if not _G.__NODES_MULTIVALUE_CSS_JS__ then
_G.__NODES_MULTIVALUE_CSS_JS__ = true
%>
<style>
/* 组标题的右箭头 */
.mv-arrow-right {
width: 0;
height: 0;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid #555;
display: inline-block;
vertical-align: middle;
}
/* 组标题的下箭头 */
.mv-arrow-down-small {
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 5px solid #555;
display: inline-block;
vertical-align: middle;
}
.mv_search_input {
width: 100%;
box-sizing: border-box;
padding: 6px;
margin-bottom: 8px;
border: 1px solid #ccc;
border-radius: 4px;
max-height: 36px;
}
.mv_list_container {
max-height: 300px;
overflow: auto;
margin-bottom: 8px;
white-space: nowrap;
}
.mv_node_list {
width: 100%;
box-sizing: border-box;
padding: 0 !important;
margin: 0 !important;
}
.mv_node_list li.group-block {
list-style: none;
padding: 0;
margin: 0 0 8px 0;
}
.mv_node_list .group-title {
cursor: pointer;
display: flex;
align-items: center;
padding: 6px;
margin-bottom: 4px;
background: #f0f0f0;
border-radius: 4px;
white-space: nowrap;
}
.mv_node_list ul.group-items {
margin: 0 0 8px 16px;
padding: 0;
list-style: none;
}
.mv_node_list ul.group-items li.node-item {
list-style: none;
padding: 0;
margin: 0;
white-space: nowrap;
text-align: left;
}
.mv-node-row {
display: inline-flex;
align-items: center;
vertical-align: middle;
}
.mv-node-checkbox {
margin: 0;
vertical-align: middle;
margin-right: 6px;
}
.mv-node-label {
margin: 0;
padding: 0;
vertical-align: middle;
cursor: pointer;
}
.mv-controls {
margin-top: 4px;
display: flex;
gap: 4px;
align-items: center;
}
</style>
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
(function(){
const cbid = "<%=cbid%>";
const opt = "<%=self.option%>";
const listId = cbid + ".node_list";
// 折叠组 // 折叠组
window["toggleGroup_" + opt] = function(g){ function mv_toggleGroup(opt, nodeList, searchInput, g) {
const ul = document.getElementById("group-" + opt + "-" + g); const ul = nodeList.querySelector("#group-" + opt + "-" + g);
const arrow = document.getElementById("arrow-" + opt + "-" + g); const arrow = nodeList.querySelector("#arrow-" + opt + "-" + g);
if (!ul) return; if (!ul) return;
// 判断是否在搜索状态 // 判断是否在搜索状态
const keyword = document.getElementById(cbid + ".search").value.trim().toLowerCase(); const keyword = searchInput.value.trim().toLowerCase();
const isSearching = keyword.length > 0; const isSearching = keyword.length > 0;
// 搜索状态下,仅切换当前组,不处理其他组 // 搜索状态下,仅切换当前组,不处理其他组
if (isSearching) { if (isSearching){
if (ul.style.display === "none") { ul.style.display = ul.style.display === "none" ? "block" : "none";
ul.style.display = ""; if (arrow) arrow.className = ul.style.display === "none" ? "mv-arrow-right" : "mv-arrow-down-small";
if (arrow) arrow.className = "lv-arrow-down-small";
} else {
ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
}
return; return;
} }
// 非搜索模式:先折叠其他组 // 非搜索模式:先折叠其他组
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block"); nodeList.querySelectorAll(".group-block").forEach(group=>{
groups.forEach(group=>{
const gname = group.getAttribute("data-group"); const gname = group.getAttribute("data-group");
const gul = document.getElementById("group-" + opt + "-" + gname); const gul = document.getElementById("group-" + opt + "-" + gname);
const garrow = document.getElementById("arrow-" + opt + "-" + gname); const garrow = document.getElementById("arrow-" + opt + "-" + gname);
if (gname !== g) { if (gname !== g) {
if (gul) gul.style.display = "none"; if (gul) gul.style.display = "none";
if (garrow) arrow.className = "lv-arrow-right"; if (garrow) garrow.className = "mv-arrow-right";
} }
}); });
document.getElementById(listId).parentNode.scrollTop = 0; nodeList.parentNode.scrollTop = 0;
// 切换当前组 // 切换当前组
if (ul.style.display === "none") { ul.style.display = ul.style.display === "none" ? "block" : "none";
ul.style.display = ""; if (arrow) arrow.className = ul.style.display === "none" ? "mv-arrow-right" : "mv-arrow-down-small";
if (arrow) arrow.className = "lv-arrow-down-small";
} else {
ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
}
}; };
// 计数
function mv_updateCount(opt, nodeList) {
// 当前实例下的所有 checkbox
const cbs = nodeList.querySelectorAll("input[type=checkbox]");
let checked = 0;
cbs.forEach(cb => { if(cb.checked) checked++; });
// 更新总计
const totalSpan = document.getElementById("count-" + opt);
if (totalSpan) {
totalSpan.innerHTML = "<%:Selected:%> <span style='color:red;'>" + checked + " / " + cbs.length + "</span>";
}
// 更新每个组计数
nodeList.querySelectorAll(".group-block").forEach(group => {
const gname = group.getAttribute("data-group");
const groupCbs = group.querySelectorAll("li[data-node-name] input[type=checkbox]");
let groupChecked = 0;
groupCbs.forEach(cb => { if(cb.checked) groupChecked++; });
const span = document.getElementById("group-count-" + opt + "-" + gname);
if(span) span.textContent = "(" + groupChecked + "/" + groupCbs.length + ")";
});
}
// 搜索 // 搜索
window["filterGroups_" + opt] = function(keyword){ function mv_filterGroups(keyword, opt, nodeList) {
keyword = keyword.toLowerCase().trim(); keyword = (keyword || "").toLowerCase().trim();
nodeList.querySelectorAll(".group-block").forEach(group => {
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group=>{
const items = group.querySelectorAll("li[data-node-name]"); const items = group.querySelectorAll("li[data-node-name]");
let matchCount = 0; let matchCount = 0;
items.forEach(li => {
items.forEach(li=>{
const name = li.getAttribute("data-node-name"); const name = li.getAttribute("data-node-name");
if (!keyword || name.indexOf(keyword) !== -1) { if (!keyword || name.indexOf(keyword) !== -1) {
li.style.display = ""; li.style.display = "";
@@ -187,7 +259,7 @@ end
li.style.display = "none"; li.style.display = "none";
} }
}); });
// 搜索时自动展开所有 // 搜索时自动展开组
const gname = group.getAttribute("data-group"); const gname = group.getAttribute("data-group");
const ul = document.getElementById("group-" + opt + "-" + gname); const ul = document.getElementById("group-" + opt + "-" + gname);
const arrow = document.getElementById("arrow-" + opt + "-" + gname); const arrow = document.getElementById("arrow-" + opt + "-" + gname);
@@ -196,88 +268,71 @@ end
group.style.display = "none"; group.style.display = "none";
} else { } else {
group.style.display = ""; group.style.display = "";
if (keyword) { if (keyword && ul && arrow) {
ul.style.display = ""; ul.style.display = "";
arrow.className = "lv-arrow-down-small"; arrow.className = "mv-arrow-down-small";
} }
} }
}); });
mv_updateCount(opt, nodeList);
updateCount();
// 清空搜索后恢复全部折叠 // 清空搜索后恢复全部折叠
if (!keyword) { if (!keyword) {
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block"); mv_collapseAllGroups(opt, nodeList);
groups.forEach(group=>{
const gname = group.getAttribute("data-group");
const ul = document.getElementById("group-" + opt + "-" + gname);
const arrow = document.getElementById("arrow-" + opt + "-" + gname);
if (ul) ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right";
});
} }
}; }
// 全选 / 全不选 // 全选 / 全不选
window["selectAll_" + opt] = function(flag){ function mv_selectAll(cbid, opt, flag) {
const cbs = document.querySelectorAll("[id='" + listId + "'] input[type=checkbox]"); const nodeList = document.getElementById(cbid + ".node_list");
const cbs = nodeList.querySelectorAll("input[type=checkbox]");
cbs.forEach(cb=>{ cbs.forEach(cb=>{
if (cb.offsetParent !== null) cb.checked = flag; if (cb.offsetParent !== null) cb.checked = flag;
}); });
updateCount(); mv_updateCount(opt, nodeList);
}; };
// 计数 // 折叠所有组
function updateCount(){ function mv_collapseAllGroups(opt, nodeList) {
const cbs = document.querySelectorAll("[id='" + listId + "'] input[type=checkbox]"); nodeList.querySelectorAll(".group-block").forEach(group => {
let checked = 0;
cbs.forEach(cb=>{ if (cb.checked) checked++; });
// 更新总计
document.getElementById("count-" + opt).innerHTML =
"<%:Selected:%> <span style='color:red;'>" + checked + " / " + cbs.length + "</span>";
// 更新每个组
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group=>{
const gname = group.getAttribute("data-group");
const groupCbs = group.querySelectorAll("li[data-node-name] input[type=checkbox]");
let groupChecked = 0;
groupCbs.forEach(cb=>{ if(cb.checked) groupChecked++; });
const span = document.getElementById("group-count-" + opt + "-" + gname);
if(span) span.textContent = "(" + groupChecked + "/" + groupCbs.length + ")";
});
}
document.getElementById(listId)?.addEventListener("change", updateCount);
// 初始化折叠所有组和计数
const initObserver = new MutationObserver(() => {
const list = document.getElementById(listId);
if (!list) return;
if (list.offsetParent === null) return;
if (list.dataset.initDone === "1") return;
list.dataset.initDone = "1";
const groups = document.querySelectorAll("[id='" + listId + "'] .group-block");
groups.forEach(group => {
const gname = group.getAttribute("data-group"); const gname = group.getAttribute("data-group");
const ul = document.getElementById("group-" + opt + "-" + gname); const ul = document.getElementById("group-" + opt + "-" + gname);
const arrow = document.getElementById("arrow-" + opt + "-" + gname); const arrow = document.getElementById("arrow-" + opt + "-" + gname);
if (ul) ul.style.display = "none"; if (ul) ul.style.display = "none";
if (arrow) arrow.className = "lv-arrow-right"; if (arrow) arrow.className = "mv-arrow-right";
}); });
}
//]]>
</script>
<% end %>
updateCount(); <script type="text/javascript">
//<![CDATA[
(function(){
const cbid = "<%=cbid%>";
const opt = "<%=self.option%>";
const searchInput = document.getElementById(cbid + ".search");
const nodeList = document.getElementById(cbid + ".node_list");
nodeList.querySelectorAll(".group-title").forEach(title => {
title.addEventListener("click", function() {
const g = this.closest(".group-block")?.getAttribute("data-group");
if (g) mv_toggleGroup(opt, nodeList, searchInput, g);
});
}); });
initObserver.observe(document.body, { searchInput.addEventListener("input", function() {
attributes: true, mv_filterGroups(this.value, opt, nodeList);
subtree: true, })
attributeFilter: ["style", "class"]
// checkbox 改变时更新计数
nodeList.addEventListener("change", () => {
mv_updateCount(opt, nodeList);
}); });
// 初始化折叠所有组和计数
mv_collapseAllGroups(opt, nodeList)
mv_updateCount(opt, nodeList);
})(); })();
//]]> //]]>
</script> </script>

View File

@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=shadowsocks-rust PKG_NAME:=shadowsocks-rust
PKG_VERSION:=1.23.5 PKG_VERSION:=1.24.0
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_SOURCE_HEADER:=shadowsocks-v$(PKG_VERSION) PKG_SOURCE_HEADER:=shadowsocks-v$(PKG_VERSION)
@@ -21,29 +21,29 @@ endif
ifeq ($(ARCH),aarch64) ifeq ($(ARCH),aarch64)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).aarch64-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).aarch64-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=42ec15a594dd61b5eae9feb6d7819405e7bd261b8c4cceeda0b6bc7f8b05395f PKG_HASH:=e00b6551f40bb2d61adb2503909e0df6550c022372c812f3f34350510797ef2f
else ifeq ($(ARCH),arm) else ifeq ($(ARCH),arm)
# Referred to golang/golang-values.mk # Referred to golang/golang-values.mk
ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE)))) ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE))))
ifeq ($(ARM_CPU_FEATURES),) ifeq ($(ARM_CPU_FEATURES),)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).arm-$(PKG_SOURCE_BODY)eabi.$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).arm-$(PKG_SOURCE_BODY)eabi.$(PKG_SOURCE_FOOTER)
PKG_HASH:=dd57f2500fb165dcad52604ad368d311d7d7e8072384866c4e93107af7ceed0c PKG_HASH:=b00694ac484eaf994408c874c70e1d3392d1654cf3d9391ddf2b589bbee9106c
else else
PKG_SOURCE:=$(PKG_SOURCE_HEADER).arm-$(PKG_SOURCE_BODY)eabihf.$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).arm-$(PKG_SOURCE_BODY)eabihf.$(PKG_SOURCE_FOOTER)
PKG_HASH:=596f3984841b7d83af45120b7a52f0bb671f08996aa16464bd4280d13e1554cd PKG_HASH:=db56c8e64ce3651907c31fe6a585a68e4c4576c8379f50d82be31d79ba8d00ad
endif endif
else ifeq ($(ARCH),i386) else ifeq ($(ARCH),i386)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).i686-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).i686-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=4f2104e4b914af0e720aa5f8254d35e83baea7c86193a676d97b0d007d0d8071 PKG_HASH:=a9aabb4209a8f29afabddb2aaaa8a38d8f604fd0075250d61bd594bb10ae38c7
else ifeq ($(ARCH),x86_64) else ifeq ($(ARCH),x86_64)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).x86_64-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).x86_64-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=d37e9f6484aced51188ed6c8beea3538be7a73b072259b65a47e91ebf6530dfc PKG_HASH:=0d84f5f350ec99396867d718f146fc3810975b2a7cd06192f158d96bdef460e7
else ifeq ($(ARCH),mips) else ifeq ($(ARCH),mips)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).mips-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).mips-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=4d2fd31e627103d630603ea0df82de877d8a5c4cc2a92e233ddfe73ac6b815a9 PKG_HASH:=40319c20934121e8d5df90e54cd2b41e064a3487f180f6924ac42ba3cbcebe4f
else ifeq ($(ARCH),mipsel) else ifeq ($(ARCH),mipsel)
PKG_SOURCE:=$(PKG_SOURCE_HEADER).mipsel-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER) PKG_SOURCE:=$(PKG_SOURCE_HEADER).mipsel-$(PKG_SOURCE_BODY).$(PKG_SOURCE_FOOTER)
PKG_HASH:=ffb65d2750f99d7f1777d2f00d30bb58f826f8a50d6b1b2ed9e827db197a5564 PKG_HASH:=d51792a5b4f6a28bb2e8b07e2f39a60535d1ede9d1973a257c5751a991e26ac8
# Set the default value to make OpenWrt Package Checker happy # Set the default value to make OpenWrt Package Checker happy
else else
PKG_SOURCE:=dummy PKG_SOURCE:=dummy

View File

@@ -21,13 +21,13 @@ define Download/geoip
HASH:=6878dbacfb1fcb1ee022f63ed6934bcefc95a3c4ba10c88f1131fb88dbf7c337 HASH:=6878dbacfb1fcb1ee022f63ed6934bcefc95a3c4ba10c88f1131fb88dbf7c337
endef endef
GEOSITE_VER:=20251209063354 GEOSITE_VER:=20251211093703
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE) FILE:=$(GEOSITE_FILE)
HASH:=1132da7e8906a97a5d94a0c3c9eb716386abdbec5e3742babe2409fcfd3810dc HASH:=d5d61275d4f8a2edbc19a0078b7f8c5bfd8381655b56025f7d6b32e207e971f7
endef endef
GEOSITE_IRAN_VER:=202512080042 GEOSITE_IRAN_VER:=202512080042