mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-18 13:04:37 +03:00
feat: full test for nekobox
This commit is contained in:
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/matsuridayo/libneko/neko_common"
|
||||
@@ -18,7 +19,32 @@ func setupCore() {
|
||||
boxmain.DisableColor()
|
||||
//
|
||||
neko_log.SetupLog(50*1024, "./neko.log")
|
||||
neko_common.GetProxyHttpClient = func() *http.Client {
|
||||
//
|
||||
neko_common.GetCurrentInstance = func() interface{} {
|
||||
return instance
|
||||
}
|
||||
neko_common.DialContext = func(ctx context.Context, specifiedInstance interface{}, network, addr string) (net.Conn, error) {
|
||||
if i, ok := specifiedInstance.(*boxbox.Box); ok {
|
||||
return boxapi.DialContext(ctx, i, network, addr)
|
||||
}
|
||||
if instance != nil {
|
||||
return boxapi.DialContext(ctx, instance, network, addr)
|
||||
}
|
||||
return neko_common.DialContextSystem(ctx, network, addr)
|
||||
}
|
||||
neko_common.DialUDP = func(ctx context.Context, specifiedInstance interface{}) (net.PacketConn, error) {
|
||||
if i, ok := specifiedInstance.(*boxbox.Box); ok {
|
||||
return boxapi.DialUDP(ctx, i)
|
||||
}
|
||||
if instance != nil {
|
||||
return boxapi.DialUDP(ctx, instance)
|
||||
}
|
||||
return neko_common.DialUDPSystem(ctx)
|
||||
}
|
||||
neko_common.CreateProxyHttpClient = func(specifiedInstance interface{}) *http.Client {
|
||||
if i, ok := specifiedInstance.(*boxbox.Box); ok {
|
||||
return boxapi.CreateProxyHttpClient(i)
|
||||
}
|
||||
return boxapi.CreateProxyHttpClient(instance)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,11 +95,13 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp,
|
||||
|
||||
if in.Mode == gen.TestMode_UrlTest {
|
||||
var i *boxbox.Box
|
||||
var cancel context.CancelFunc
|
||||
if in.Config != nil {
|
||||
// Test instance
|
||||
i, instance_cancel, err = boxmain.Create([]byte(in.Config.CoreConfig))
|
||||
if instance_cancel != nil {
|
||||
defer instance_cancel()
|
||||
i, cancel, err = boxmain.Create([]byte(in.Config.CoreConfig))
|
||||
if i != nil {
|
||||
defer i.Close()
|
||||
defer cancel()
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
@@ -115,8 +117,16 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp,
|
||||
out.Ms, err = speedtest.UrlTest(boxapi.CreateProxyHttpClient(i), in.Url, in.Timeout)
|
||||
} else if in.Mode == gen.TestMode_TcpPing {
|
||||
out.Ms, err = speedtest.TcpPing(in.Address, in.Timeout)
|
||||
} else {
|
||||
err = fmt.Errorf("not available")
|
||||
} else if in.Mode == gen.TestMode_FullTest {
|
||||
i, cancel, err := boxmain.Create([]byte(in.Config.CoreConfig))
|
||||
if i != nil {
|
||||
defer i.Close()
|
||||
defer cancel()
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return grpc_server.DoFullTest(ctx, in, i)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -69,29 +69,51 @@ func setupCore() {
|
||||
return resolver_go.LookupIP(context.Background(), network, host)
|
||||
})
|
||||
//
|
||||
neko_common.GetProxyHttpClient = func() *http.Client {
|
||||
return getProxyHttpClient(instance)
|
||||
neko_common.GetCurrentInstance = func() interface{} {
|
||||
return instance
|
||||
}
|
||||
neko_common.DialContext = func(ctx context.Context, specifiedInstance interface{}, network, addr string) (net.Conn, error) {
|
||||
dest, err := v2rayNet.ParseDestination(fmt.Sprintf("%s:%s", network, addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i, ok := specifiedInstance.(*NekoV2RayInstance); ok {
|
||||
return core.Dial(ctx, i.Instance, dest)
|
||||
}
|
||||
if instance != nil {
|
||||
return core.Dial(ctx, instance.Instance, dest)
|
||||
}
|
||||
return neko_common.DialContextSystem(ctx, network, addr)
|
||||
}
|
||||
neko_common.DialUDP = func(ctx context.Context, specifiedInstance interface{}) (net.PacketConn, error) {
|
||||
if i, ok := specifiedInstance.(*NekoV2RayInstance); ok {
|
||||
return core.DialUDP(ctx, i.Instance)
|
||||
}
|
||||
if instance != nil {
|
||||
return core.DialUDP(ctx, instance.Instance)
|
||||
}
|
||||
return neko_common.DialUDPSystem(ctx)
|
||||
}
|
||||
neko_common.CreateProxyHttpClient = func(specifiedInstance interface{}) *http.Client {
|
||||
if i, ok := specifiedInstance.(*NekoV2RayInstance); ok {
|
||||
return createProxyHttpClient(i)
|
||||
}
|
||||
return createProxyHttpClient(instance)
|
||||
}
|
||||
}
|
||||
|
||||
// PROXY
|
||||
|
||||
func getProxyHttpClient(_instance *NekoV2RayInstance) *http.Client {
|
||||
dailContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
dest, err := v2rayNet.ParseDestination(fmt.Sprintf("%s:%s", network, addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return core.Dial(ctx, _instance.Instance, dest)
|
||||
}
|
||||
|
||||
func createProxyHttpClient(i *NekoV2RayInstance) *http.Client {
|
||||
transport := &http.Transport{
|
||||
TLSHandshakeTimeout: time.Second * 3,
|
||||
ResponseHeaderTimeout: time.Second * 3,
|
||||
}
|
||||
|
||||
if _instance != nil {
|
||||
transport.DialContext = dailContext
|
||||
if i != nil {
|
||||
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return neko_common.DialContext(ctx, i, network, addr)
|
||||
}
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
|
||||
@@ -2,22 +2,15 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"grpc_server"
|
||||
"grpc_server/gen"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/matsuridayo/libneko/neko_common"
|
||||
"github.com/matsuridayo/libneko/speedtest"
|
||||
|
||||
core "github.com/v2fly/v2ray-core/v5"
|
||||
"github.com/v2fly/v2ray-core/v5/nekoutils"
|
||||
)
|
||||
|
||||
@@ -120,7 +113,7 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp,
|
||||
|
||||
// Latency
|
||||
var t int32
|
||||
t, err = speedtest.UrlTest(getProxyHttpClient(i), in.Url, in.Timeout)
|
||||
t, err = speedtest.UrlTest(createProxyHttpClient(i), in.Url, in.Timeout)
|
||||
out.Ms = t // sn: ms==0 是错误
|
||||
} else if in.Mode == gen.TestMode_TcpPing {
|
||||
out.Ms, err = speedtest.TcpPing(in.Address, in.Timeout)
|
||||
@@ -140,123 +133,7 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp,
|
||||
return
|
||||
}
|
||||
|
||||
// Latency
|
||||
var latency string
|
||||
if in.FullLatency {
|
||||
t, _ := speedtest.UrlTest(getProxyHttpClient(i), in.Url, in.Timeout)
|
||||
out.Ms = t
|
||||
if t > 0 {
|
||||
latency = fmt.Sprint(t, "ms")
|
||||
} else {
|
||||
latency = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
// UDP Latency
|
||||
var udpLatency string
|
||||
if in.FullUdpLatency {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
result := make(chan string)
|
||||
|
||||
go func() {
|
||||
var startTime = time.Now()
|
||||
pc, err := core.DialUDP(ctx, i.Instance)
|
||||
if err == nil {
|
||||
defer pc.Close()
|
||||
dnsPacket, _ := hex.DecodeString("0000010000010000000000000377777706676f6f676c6503636f6d0000010001")
|
||||
addr := &net.UDPAddr{
|
||||
IP: net.ParseIP("8.8.8.8"),
|
||||
Port: 53,
|
||||
}
|
||||
_, err = pc.WriteTo(dnsPacket, addr)
|
||||
if err == nil {
|
||||
var buf [1400]byte
|
||||
_, _, err = pc.ReadFrom(buf[:])
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
var endTime = time.Now()
|
||||
result <- fmt.Sprint(endTime.Sub(startTime).Abs().Milliseconds(), "ms")
|
||||
} else {
|
||||
result <- "Error"
|
||||
}
|
||||
close(result)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
udpLatency = "Timeout"
|
||||
case r := <-result:
|
||||
udpLatency = r
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
|
||||
// 入口 IP
|
||||
var in_ip string
|
||||
if in.FullInOut {
|
||||
_in_ip, err := net.ResolveIPAddr("ip", in.InAddress)
|
||||
if err == nil {
|
||||
in_ip = _in_ip.String()
|
||||
} else {
|
||||
in_ip = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
client := getProxyHttpClient(i)
|
||||
|
||||
// 出口 IP
|
||||
var out_ip string
|
||||
if in.FullInOut {
|
||||
resp, err := client.Get("https://httpbin.org/get")
|
||||
if err == nil {
|
||||
v := make(map[string]interface{})
|
||||
json.NewDecoder(resp.Body).Decode(&v)
|
||||
if a, ok := v["origin"]; ok {
|
||||
if s, ok := a.(string); ok {
|
||||
out_ip = s
|
||||
}
|
||||
}
|
||||
resp.Body.Close()
|
||||
} else {
|
||||
out_ip = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
// 下载
|
||||
var speed string
|
||||
if in.FullSpeed {
|
||||
resp, err := client.Get("http://cachefly.cachefly.net/10mb.test")
|
||||
if err == nil {
|
||||
time_start := time.Now()
|
||||
n, _ := io.Copy(io.Discard, resp.Body)
|
||||
time_end := time.Now()
|
||||
|
||||
speed = fmt.Sprintf("%.2fMiB/s", (float64(n)/time_end.Sub(time_start).Seconds())/1048576)
|
||||
resp.Body.Close()
|
||||
} else {
|
||||
speed = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
fr := make([]string, 0)
|
||||
if latency != "" {
|
||||
fr = append(fr, fmt.Sprintf("Latency: %s", latency))
|
||||
}
|
||||
if udpLatency != "" {
|
||||
fr = append(fr, fmt.Sprintf("UDPLatency: %s", udpLatency))
|
||||
}
|
||||
if speed != "" {
|
||||
fr = append(fr, fmt.Sprintf("Speed: %s", speed))
|
||||
}
|
||||
if in_ip != "" {
|
||||
fr = append(fr, fmt.Sprintf("In: %s", in_ip))
|
||||
}
|
||||
if out_ip != "" {
|
||||
fr = append(fr, fmt.Sprintf("Out: %s", out_ip))
|
||||
}
|
||||
|
||||
out.FullReport = strings.Join(fr, " / ")
|
||||
return grpc_server.DoFullTest(ctx, in, i)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
137
go/grpc_server/fulltest.go
Normal file
137
go/grpc_server/fulltest.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package grpc_server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"grpc_server/gen"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/matsuridayo/libneko/neko_common"
|
||||
"github.com/matsuridayo/libneko/speedtest"
|
||||
)
|
||||
|
||||
func DoFullTest(ctx context.Context, in *gen.TestReq, instance interface{}) (out *gen.TestResp, _ error) {
|
||||
out = &gen.TestResp{}
|
||||
httpClient := neko_common.CreateProxyHttpClient(instance)
|
||||
|
||||
// Latency
|
||||
var latency string
|
||||
if in.FullLatency {
|
||||
t, _ := speedtest.UrlTest(httpClient, in.Url, in.Timeout)
|
||||
out.Ms = t
|
||||
if t > 0 {
|
||||
latency = fmt.Sprint(t, "ms")
|
||||
} else {
|
||||
latency = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
// UDP Latency
|
||||
var udpLatency string
|
||||
if in.FullUdpLatency {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
result := make(chan string)
|
||||
|
||||
go func() {
|
||||
var startTime = time.Now()
|
||||
pc, err := neko_common.DialContext(ctx, instance, "udp", "8.8.8.8:53")
|
||||
if err == nil {
|
||||
defer pc.Close()
|
||||
dnsPacket, _ := hex.DecodeString("0000010000010000000000000377777706676f6f676c6503636f6d0000010001")
|
||||
_, err = pc.Write(dnsPacket)
|
||||
if err == nil {
|
||||
var buf [1400]byte
|
||||
_, err = pc.Read(buf[:])
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
var endTime = time.Now()
|
||||
result <- fmt.Sprint(endTime.Sub(startTime).Abs().Milliseconds(), "ms")
|
||||
} else {
|
||||
log.Println("UDP Latency test error:", err)
|
||||
result <- "Error"
|
||||
}
|
||||
close(result)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
udpLatency = "Timeout"
|
||||
case r := <-result:
|
||||
udpLatency = r
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
|
||||
// 入口 IP
|
||||
var in_ip string
|
||||
if in.FullInOut {
|
||||
_in_ip, err := net.ResolveIPAddr("ip", in.InAddress)
|
||||
if err == nil {
|
||||
in_ip = _in_ip.String()
|
||||
} else {
|
||||
in_ip = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
// 出口 IP
|
||||
var out_ip string
|
||||
if in.FullInOut {
|
||||
resp, err := httpClient.Get("https://httpbin.org/get")
|
||||
if err == nil {
|
||||
v := make(map[string]interface{})
|
||||
json.NewDecoder(resp.Body).Decode(&v)
|
||||
if a, ok := v["origin"]; ok {
|
||||
if s, ok := a.(string); ok {
|
||||
out_ip = s
|
||||
}
|
||||
}
|
||||
resp.Body.Close()
|
||||
} else {
|
||||
out_ip = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
// 下载
|
||||
var speed string
|
||||
if in.FullSpeed {
|
||||
resp, err := httpClient.Get("http://cachefly.cachefly.net/10mb.test")
|
||||
if err == nil {
|
||||
time_start := time.Now()
|
||||
n, _ := io.Copy(io.Discard, resp.Body)
|
||||
time_end := time.Now()
|
||||
|
||||
speed = fmt.Sprintf("%.2fMiB/s", (float64(n)/time_end.Sub(time_start).Seconds())/1048576)
|
||||
resp.Body.Close()
|
||||
} else {
|
||||
speed = "Error"
|
||||
}
|
||||
}
|
||||
|
||||
fr := make([]string, 0)
|
||||
if latency != "" {
|
||||
fr = append(fr, fmt.Sprintf("Latency: %s", latency))
|
||||
}
|
||||
if udpLatency != "" {
|
||||
fr = append(fr, fmt.Sprintf("UDPLatency: %s", udpLatency))
|
||||
}
|
||||
if speed != "" {
|
||||
fr = append(fr, fmt.Sprintf("Speed: %s", speed))
|
||||
}
|
||||
if in_ip != "" {
|
||||
fr = append(fr, fmt.Sprintf("In: %s", in_ip))
|
||||
}
|
||||
if out_ip != "" {
|
||||
fr = append(fr, fmt.Sprintf("Out: %s", out_ip))
|
||||
}
|
||||
|
||||
out.FullReport = strings.Join(fr, " / ")
|
||||
|
||||
return
|
||||
}
|
||||
@@ -19,7 +19,7 @@ var update_download_url string
|
||||
func (s *BaseServer) Update(ctx context.Context, in *gen.UpdateReq) (*gen.UpdateResp, error) {
|
||||
ret := &gen.UpdateResp{}
|
||||
|
||||
client := neko_common.GetProxyHttpClient()
|
||||
client := neko_common.CreateProxyHttpClient(neko_common.GetCurrentInstance())
|
||||
|
||||
if in.Action == gen.UpdateAction_Check { // Check update
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if [ ! -z $ENV_NEKORAY ]; then
|
||||
export COMMIT_SING_BOX_EXTRA="e7c37b1587c38841f4eb687249a43dab421d8eff"
|
||||
export COMMIT_SING_BOX_EXTRA="1ea593f166ddb44e12ba9c7b41bcc6e73b66b550"
|
||||
export COMMIT_MATSURI_V2RAY="8134d3cc23aa6b8e2a056887addf22d7d22bd969"
|
||||
fi
|
||||
|
||||
|
||||
@@ -375,7 +375,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||
ui->menuCurrent_Group->insertAction(ui->actionfake_5, ui->menu_clear_test_result);
|
||||
ui->menuCurrent_Group->insertAction(ui->actionfake_5, ui->menu_resolve_domain);
|
||||
}
|
||||
ui->menu_full_test->setVisible(!IS_NEKO_BOX);
|
||||
set_selected_or_group(menuCurrent_Select ? 1 : 0);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user