From e44279742c3ef97a5b47f43f00dc343639ec44b6 Mon Sep 17 00:00:00 2001 From: arm64v8a <48624112+arm64v8a@users.noreply.github.com> Date: Tue, 27 Sep 2022 12:39:40 +0800 Subject: [PATCH] update --- fmt/Bean2CoreObj_box.cpp | 10 ++--- go/cmd/nekobox_core/core_box.go | 66 +++++++++--------------------- go/cmd/nekobox_core/grpc_box.go | 40 +++++++++--------- go/cmd/nekoray_core/core_ray.go | 1 + go/cmd/nekoray_core/grpc_ray.go | 25 +++--------- go/pkg/neko_log/log.go | 51 +++++++++++++++++++++++ go/pkg/speedtest/speedtest.go | 72 +++++++++++++++++++++++++++++++++ main/NekoRay_DataStore.hpp | 2 +- main/main.cpp | 5 ++- rpc/gRPC.cpp | 2 +- ui/mainwindow.cpp | 18 +++++++-- ui/mainwindow_grpc.cpp | 2 +- 12 files changed, 193 insertions(+), 101 deletions(-) create mode 100644 go/pkg/neko_log/log.go create mode 100644 go/pkg/speedtest/speedtest.go diff --git a/fmt/Bean2CoreObj_box.cpp b/fmt/Bean2CoreObj_box.cpp index 8ae735c..3061c78 100644 --- a/fmt/Bean2CoreObj_box.cpp +++ b/fmt/Bean2CoreObj_box.cpp @@ -52,12 +52,10 @@ namespace NekoRay::fmt { outbound["server"] = serverAddress; outbound["server_port"] = serverPort; - QJsonArray users; - QJsonObject user; - user["username"] = username; - user["password"] = password; - users.push_back(user); - if (!username.isEmpty() && !password.isEmpty()) outbound["users"] = users; + if (!username.isEmpty() && !password.isEmpty()) { + outbound["username"] = username; + outbound["password"] = password; + } stream->BuildStreamSettingsSingBox(&outbound); result.outbound = outbound; diff --git a/go/cmd/nekobox_core/core_box.go b/go/cmd/nekobox_core/core_box.go index 782bc5b..ce0e66b 100644 --- a/go/cmd/nekobox_core/core_box.go +++ b/go/cmd/nekobox_core/core_box.go @@ -2,15 +2,13 @@ package main import ( "context" - "fmt" + "io" "log" - "math/rand" "neko/pkg/neko_common" + "neko/pkg/neko_log" "net" "net/http" - "os" "reflect" - "strings" "time" "unsafe" @@ -27,8 +25,10 @@ var instance_cancel context.CancelFunc // Use sing-box instead of libcore & v2ray func setupCore() { + neko_log.SetupLog(50*1024, "./neko.log") + // log.SetFlags(log.LstdFlags) - log.SetOutput(os.Stdout) + log.SetOutput(neko_log.LogWriter) // neko_common.GetProxyHttpClient = func() *http.Client { return getProxyHttpClient(instance) @@ -67,45 +67,19 @@ func getProxyHttpClient(box *box.Box) *http.Client { return client } -// TODO move -func UrlTestSingBox(box *box.Box, link string, timeout int32) (int32, error) { - client := getProxyHttpClient(box) - if client == nil { - return 0, fmt.Errorf("no client") - } - - // Test handshake time - var time_start time.Time - var times = 1 - var rtt_times = 1 - - // Test RTT "true delay" - if link2 := strings.TrimLeft(link, "true"); link != link2 { - link = link2 - times = 3 - rtt_times = 2 - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Millisecond) - defer cancel() - req, err := http.NewRequestWithContext(ctx, "GET", link, nil) - req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%84, rand.Int()%2)) - if err != nil { - return 0, err - } - - for i := 0; i < times; i++ { - if i == 1 || times == 1 { - time_start = time.Now() - } - - resp, err := client.Do(req) - if err != nil { - fmt.Println("Url test failed:", err) - return 0, err - } - resp.Body.Close() - } - - return int32(time.Since(time_start).Milliseconds() / int64(rtt_times)), nil +type logWriter struct { + files []io.Writer +} + +func (w *logWriter) Write(p []byte) (n int, err error) { + for _, file := range w.files { + if file == nil { + continue + } + n, err = file.Write(p) + if err != nil { + return + } + } + return } diff --git a/go/cmd/nekobox_core/grpc_box.go b/go/cmd/nekobox_core/grpc_box.go index a3da27d..74fa465 100644 --- a/go/cmd/nekobox_core/grpc_box.go +++ b/go/cmd/nekobox_core/grpc_box.go @@ -3,13 +3,16 @@ package main import ( "context" "errors" + "fmt" "log" "neko/gen" "neko/pkg/grpc_server" "neko/pkg/neko_common" + "neko/pkg/neko_log" + "neko/pkg/speedtest" "nekobox_core/box_main" - "net" - "time" + "reflect" + "unsafe" box "github.com/sagernet/sing-box" ) @@ -39,6 +42,17 @@ func (s *server) Start(ctx context.Context, in *gen.LoadConfigReq) (out *gen.Err } instance, instance_cancel, err = box_main.Create([]byte(in.CoreConfig), true) + + // Logger + if instance != nil { + logFactory_ := reflect.Indirect(reflect.ValueOf(instance)).FieldByName("logFactory") + logFactory_ = reflect.NewAt(logFactory_.Type(), unsafe.Pointer(logFactory_.UnsafeAddr())).Elem() // get unexported logFactory + logFactory_ = logFactory_.Elem().Elem() // get struct + writer_ := logFactory_.FieldByName("writer") + writer_ = reflect.NewAt(writer_.Type(), unsafe.Pointer(writer_.UnsafeAddr())).Elem() // get unexported io.Writer + writer_.Set(reflect.ValueOf(neko_log.LogWriter)) + } + return } @@ -93,27 +107,11 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, } } // Latency - out.Ms, err = UrlTestSingBox(i, in.Url, in.Timeout) + out.Ms, err = speedtest.UrlTest(getProxyHttpClient(i), in.Url, in.Timeout) } else if in.Mode == gen.TestMode_TcpPing { - host, port, err := net.SplitHostPort(in.Address) - if err != nil { - out.Error = err.Error() - return - } - ip, err := net.ResolveIPAddr("ip", host) - if err != nil { - out.Error = err.Error() - return - } - // - startTime := time.Now() - _, err = net.DialTimeout("tcp", net.JoinHostPort(ip.String(), port), time.Duration(in.Timeout)*time.Millisecond) - endTime := time.Now() - if err == nil { - out.Ms = int32(endTime.Sub(startTime).Milliseconds()) - } + out.Ms, err = speedtest.TcpPing(in.Address, in.Timeout) } else { - // TODO copy + err = fmt.Errorf("not available") } return diff --git a/go/cmd/nekoray_core/core_ray.go b/go/cmd/nekoray_core/core_ray.go index 79bddaf..d1e7c7a 100644 --- a/go/cmd/nekoray_core/core_ray.go +++ b/go/cmd/nekoray_core/core_ray.go @@ -16,6 +16,7 @@ import ( var instance *libcore.V2RayInstance func setupCore() { + // TODO del device.IsNekoray = true libcore.SetConfig("", false, true) libcore.InitCore("", "", "", nil, ".", "moe.nekoray.pc:bg", true, 50) diff --git a/go/cmd/nekoray_core/grpc_ray.go b/go/cmd/nekoray_core/grpc_ray.go index fc4cfb2..95ede17 100644 --- a/go/cmd/nekoray_core/grpc_ray.go +++ b/go/cmd/nekoray_core/grpc_ray.go @@ -11,6 +11,7 @@ import ( "neko/gen" "neko/pkg/grpc_server" "neko/pkg/neko_common" + "neko/pkg/speedtest" "net" "strings" "time" @@ -121,31 +122,15 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, // Latency var t int32 - t, err = libcore.UrlTestV2ray(i, in.Inbound, in.Url, in.Timeout) + t, err = speedtest.UrlTest(getProxyHttpClient(i), in.Address, in.Timeout) out.Ms = t // sn: ms==0 是错误 } else if in.Mode == gen.TestMode_TcpPing { - host, port, err := net.SplitHostPort(in.Address) - if err != nil { - out.Error = err.Error() - return - } - ip, err := net.ResolveIPAddr("ip", host) - if err != nil { - out.Error = err.Error() - return - } - // - startTime := time.Now() - _, err = net.DialTimeout("tcp", net.JoinHostPort(ip.String(), port), time.Duration(in.Timeout)*time.Millisecond) - endTime := time.Now() - if err == nil { - out.Ms = int32(endTime.Sub(startTime).Milliseconds()) - } + out.Ms, err = speedtest.TcpPing(in.Address, in.Timeout) } else if in.Mode == gen.TestMode_FullTest { if in.Config == nil { return } - + // TODO del // Test instance i := libcore.NewV2rayInstance() i.ForTest = true @@ -164,7 +149,7 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, // Latency var latency string if in.FullLatency { - t, _ := libcore.UrlTestV2ray(i, in.Inbound, in.Url, in.Timeout) + t, _ := speedtest.UrlTest(getProxyHttpClient(i), in.Address, in.Timeout) out.Ms = t if t > 0 { latency = fmt.Sprint(t, "ms") diff --git a/go/pkg/neko_log/log.go b/go/pkg/neko_log/log.go new file mode 100644 index 0000000..68d622a --- /dev/null +++ b/go/pkg/neko_log/log.go @@ -0,0 +1,51 @@ +package neko_log + +import ( + "fmt" + "io" + "os" +) + +var f_neko_log *os.File + +var LogWriter *logWriter + +func SetupLog(maxSize int, path string) { + if f_neko_log != nil && LogWriter != nil { + return + } + // mod from libcore, simplify because only 1 proccess. + oldBytes, err := os.ReadFile(path) + if err == nil && len(oldBytes) > maxSize { + if os.Truncate(path, 0) == nil { + oldBytes = oldBytes[len(oldBytes)-maxSize:] + } + } + f_neko_log, err = os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0644) + if err == nil { + f_neko_log.Write(oldBytes) + } else { + fmt.Println("error open log", err) + } + // + LogWriter = &logWriter{ + files: []io.Writer{os.Stdout, f_neko_log}, + } +} + +type logWriter struct { + files []io.Writer +} + +func (w *logWriter) Write(p []byte) (n int, err error) { + for _, file := range w.files { + if file == nil { + continue + } + n, err = file.Write(p) + if err != nil { + return + } + } + return +} diff --git a/go/pkg/speedtest/speedtest.go b/go/pkg/speedtest/speedtest.go new file mode 100644 index 0000000..c64522e --- /dev/null +++ b/go/pkg/speedtest/speedtest.go @@ -0,0 +1,72 @@ +package speedtest + +import ( + "context" + "fmt" + "math/rand" + "net" + "net/http" + "strings" + "time" +) + +func UrlTest(client *http.Client, link string, timeout int32) (int32, error) { + if client == nil { + return 0, fmt.Errorf("no client") + } + + // Test handshake time + var time_start time.Time + var times = 1 + var rtt_times = 1 + + // Test RTT "true delay" + if link2 := strings.TrimLeft(link, "true"); link != link2 { + link = link2 + times = 3 + rtt_times = 2 + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Millisecond) + defer cancel() + req, err := http.NewRequestWithContext(ctx, "GET", link, nil) + req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%84, rand.Int()%2)) + if err != nil { + return 0, err + } + + for i := 0; i < times; i++ { + if i == 1 || times == 1 { + time_start = time.Now() + } + + resp, err := client.Do(req) + if err != nil { + fmt.Println("Url test failed:", err) + return 0, err + } + resp.Body.Close() + } + + return int32(time.Since(time_start).Milliseconds() / int64(rtt_times)), nil +} + +func TcpPing(address string, timeout int32) (ms int32, err error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return + } + ip, err := net.ResolveIPAddr("ip", host) + if err != nil { + return + } + // + startTime := time.Now() + c, err := net.DialTimeout("tcp", net.JoinHostPort(ip.String(), port), time.Duration(timeout)*time.Millisecond) + endTime := time.Now() + if err == nil { + ms = int32(endTime.Sub(startTime).Milliseconds()) + c.Close() + } + return +} diff --git a/main/NekoRay_DataStore.hpp b/main/NekoRay_DataStore.hpp index 0ef33a0..32ddfe1 100644 --- a/main/NekoRay_DataStore.hpp +++ b/main/NekoRay_DataStore.hpp @@ -85,7 +85,7 @@ namespace NekoRay { // Socks & HTTP Inbound QString inbound_address = "127.0.0.1"; - int inbound_socks_port = 2080; + int inbound_socks_port = 2080; // or Mixed int inbound_http_port = -2081; QString custom_inbound = "{\"inbounds\": []}"; diff --git a/main/main.cpp b/main/main.cpp index 4f85bd7..1f28e5c 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -36,7 +36,10 @@ int main(int argc, char *argv[]) { // Clean QDir::setCurrent(QApplication::applicationDirPath()); - QFile::remove("updater.old"); + if (QFile::exists("updater.old")) { + QFile::remove("updater.old"); + QFile::remove("sing-box.exe"); // v1.11 + } #ifndef Q_OS_WIN if (!QFile::exists("updater")) { QFile::link("launcher", "updater"); diff --git a/rpc/gRPC.cpp b/rpc/gRPC.cpp index a44b39d..c594ea0 100644 --- a/rpc/gRPC.cpp +++ b/rpc/gRPC.cpp @@ -185,7 +185,7 @@ namespace NekoRay::rpc { QString Client::Start(bool *rpcOK, const libcore::LoadConfigReq &request) { libcore::ErrorResp reply; - auto status = grpc_channel->Call("Start", request, &reply); + auto status = grpc_channel->Call("Start", request, &reply, 3000); if (status == QNetworkReply::NoError) { *rpcOK = true; diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index ab4a756..2c678c9 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -585,9 +585,13 @@ void MainWindow::neko_set_spmode(int mode, bool save) { return; } #endif - SetSystemProxy("127.0.0.1", - NekoRay::dataStore->inbound_http_port, - NekoRay::dataStore->inbound_socks_port); + auto socks_port = NekoRay::dataStore->inbound_socks_port; + auto http_port = NekoRay::dataStore->inbound_http_port; + if (IS_NEKO_BOX) { + http_port = socks_port; + socks_port = -1; + } + SetSystemProxy("127.0.0.1", http_port, socks_port); } else if (mode == NekoRay::SystemProxyMode::VPN) { if (!StartVPNProcess()) { refresh_status(); @@ -974,7 +978,10 @@ void MainWindow::on_menu_profile_debug_info_triggered() { } void MainWindow::on_menu_copy_links_triggered() { - if (ui->masterLogBrowser->hasFocus()) return; + if (ui->masterLogBrowser->hasFocus()) { + ui->masterLogBrowser->copy(); + return; + }; auto ents = get_now_selected(); QStringList links; for (const auto &ent: ents) { @@ -1227,6 +1234,9 @@ void MainWindow::keyPressEvent(QKeyEvent *event) { case Qt::Key_Escape: // take over by shortcut_esc break; + case Qt::Key_Enter: + neko_start(); + break; default: QMainWindow::keyPressEvent(event); } diff --git a/ui/mainwindow_grpc.cpp b/ui/mainwindow_grpc.cpp index 4ad3e74..df1268b 100644 --- a/ui/mainwindow_grpc.cpp +++ b/ui/mainwindow_grpc.cpp @@ -21,7 +21,7 @@ void MainWindow::setup_grpc() { #ifndef NKR_NO_GRPC // Setup Connection defaultClient = new Client([=](const QString &errStr) { - showLog("gRPC Error: " + errStr); + showLog("[Error] gRPC: " + errStr); }, "127.0.0.1:" + Int2String(NekoRay::dataStore->core_port), NekoRay::dataStore->core_token); auto t = new QTimer(); connect(t, &QTimer::timeout, this, [=]() {