From 57eed556f29c6ce9a030e35f31e72a8bbdf75b13 Mon Sep 17 00:00:00 2001 From: fordjkhjk Date: Sat, 5 Sep 2026 17:35:01 +0800 Subject: [PATCH] fix(ssr-plus): gRPC serviceName lost after subscription update, crashing xray Two chained bugs causing trojan-grpc / vless-grpc nodes to fail silently after a subscription update: 1. subscribe.lua: query params are stored with lowercased keys (params[string.lower(t[1])]) but read back as camelCase params.serviceName, so serviceName always resolves to nil for every gRPC node parsed from a subscription. 2. gen_config.lua: when serviceName is nil, the grpcSettings table may end up with all fields nil; luci.jsonc then serializes it as a JSON array [] instead of an object, which xray (24.x+) rejects and exits. The UI only shows "not running" with no error log. Fix: - fall back to lowercase/path keys when reading serviceName - default serviceName to empty string so grpcSettings always serializes as a JSON object Verified on a real device (ImmortalWrt, xray 24.x): after re-parsing the subscription, gRPC handshake succeeds and socks5 connectivity test returns 204. --- .../root/usr/share/shadowsocksr/gen_config.lua | 2 +- luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua index 75133640371..adcd0e16f45 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua @@ -636,7 +636,7 @@ Xray.outbounds = { } or nil, grpcSettings = (server.transport == "grpc") and { -- grpc - serviceName = (server.serviceName and server.serviceName ~= "") and server.serviceName or nil, + serviceName = (server.serviceName and server.serviceName ~= "") and server.serviceName or "", multiMode = (server.grpc_mode == "multi") and true or nil, idle_timeout = server.idle_timeout and (tonumber(server.idle_timeout) < 10 and 10 or tonumber(server.idle_timeout)) or nil, health_check_timeout = server.health_check_timeout and tonumber(server.health_check_timeout) or nil, diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index 7f33052c673..89c6ad2e398 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -1379,7 +1379,7 @@ local function processData(szType, content, cfgid) result.quic_security = params.quicSecurity or "none" result.quic_key = params.key elseif result.transport == "grpc" then - result.serviceName = params.serviceName + result.serviceName = params.serviceName or params.servicename or params.path result.grpc_mode = params.mode or "gun" elseif result.transport == "tcp" or result.transport == "raw" then result.tcp_guise = params.headerType or "none" @@ -1714,7 +1714,7 @@ local function processData(szType, content, cfgid) result.quic_security = params.quicSecurity or "none" result.quic_key = params.key elseif result.transport == "grpc" then - result.serviceName = params.serviceName + result.serviceName = params.serviceName or params.servicename or params.path result.grpc_mode = params.mode or "gun" elseif result.transport == "tcp" or result.transport == "raw" then result.tcp_guise = params.headerType and params.headerType ~= "" and params.headerType or "none" @@ -1852,7 +1852,7 @@ local function processData(szType, content, cfgid) result.quic_security = params.quicSecurity or "none" result.quic_key = params.key elseif result.transport == "grpc" then - result.serviceName = params.serviceName + result.serviceName = params.serviceName or params.servicename or params.path result.grpc_mode = params.mode or "gun" elseif result.transport == "raw" then result.tcp_guise = params.headerType or "none"