geodata: skip reflection for matcher calls

This commit is contained in:
Meo597
2026-10-05 04:01:08 +08:00
parent d74b8b1ba5
commit e73fb0d500
3 changed files with 257 additions and 2 deletions
+103 -2
View File
@@ -1,6 +1,8 @@
package geodata
import (
xlua "github.com/xtls/xray-core/common/lua"
"github.com/xtls/xray-core/common/net"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
@@ -21,7 +23,10 @@ func RegisterLua(L *lua.LState) {
L.RaiseError("%v", err)
return 0
}
L.Push(luar.New(L, matcher))
xlua.PushWithDirectMethods(L, matcher, map[string]xlua.DirectMethod{
"Match": luaDomainMatch,
"MatchAny": luaDomainMatchAny,
})
return 1
}))
@@ -36,7 +41,12 @@ func RegisterLua(L *lua.LState) {
L.RaiseError("%v", err)
return 0
}
L.Push(luar.New(L, matcher))
xlua.PushWithDirectMethods(L, matcher, map[string]xlua.DirectMethod{
"Match": luaIPMatch,
"AnyMatch": luaIPAnyMatch,
"Matches": luaIPMatches,
"FilterIPs": luaIPFilterIPs,
})
return 1
}))
L.Push(module)
@@ -44,6 +54,97 @@ func RegisterLua(L *lua.LState) {
})
}
// Read native Go values by type assertion; slices keep their original storage.
func readLuaIPMatcherArgs[T any](L *lua.LState) (IPMatcher, T, bool) {
var input T
if L.GetTop() != 2 {
return nil, input, false
}
value, ok := L.Get(1).(*lua.LUserData)
if !ok {
return nil, input, false
}
matcher, ok := value.Value.(IPMatcher)
if !ok {
return nil, input, false
}
if L.Get(2) == lua.LNil {
return matcher, input, true
}
value, ok = L.Get(2).(*lua.LUserData)
if !ok {
return nil, input, false
}
input, ok = value.Value.(T)
return matcher, input, ok
}
func luaIPMatch(L *lua.LState) (int, bool) {
matcher, ip, ok := readLuaIPMatcherArgs[net.IP](L)
if !ok {
return 0, false
}
L.Push(lua.LBool(matcher.Match(ip)))
return 1, true
}
func luaIPAnyMatch(L *lua.LState) (int, bool) {
matcher, ips, ok := readLuaIPMatcherArgs[[]net.IP](L)
if !ok {
return 0, false
}
L.Push(lua.LBool(matcher.AnyMatch(ips)))
return 1, true
}
func luaIPMatches(L *lua.LState) (int, bool) {
matcher, ips, ok := readLuaIPMatcherArgs[[]net.IP](L)
if !ok {
return 0, false
}
L.Push(lua.LBool(matcher.Matches(ips)))
return 1, true
}
func luaIPFilterIPs(L *lua.LState) (int, bool) {
matcher, ips, ok := readLuaIPMatcherArgs[[]net.IP](L)
if !ok {
return 0, false
}
matched, unmatched := matcher.FilterIPs(ips)
L.Push(luar.New(L, matched))
L.Push(luar.New(L, unmatched))
return 2, true
}
func luaDomainMatch(L *lua.LState) (int, bool) {
if L.GetTop() == 2 {
if value, ok := L.Get(1).(*lua.LUserData); ok {
matcher, validMatcher := value.Value.(DomainMatcher)
domain, validDomain := L.Get(2).(lua.LString)
if validMatcher && validDomain {
L.Push(luar.New(L, matcher.Match(string(domain))))
return 1, true
}
}
}
return 0, false
}
func luaDomainMatchAny(L *lua.LState) (int, bool) {
if L.GetTop() == 2 {
if value, ok := L.Get(1).(*lua.LUserData); ok {
matcher, validMatcher := value.Value.(DomainMatcher)
domain, validDomain := L.Get(2).(lua.LString)
if validMatcher && validDomain {
L.Push(lua.LBool(matcher.MatchAny(string(domain))))
return 1, true
}
}
}
return 0, false
}
func luaRules(L *lua.LState) []string {
rules := make([]string, L.GetTop())
for i := range rules {