From 258ae1804d497ba1fac827f22db2e7ddfd5d7acf Mon Sep 17 00:00:00 2001
From: "github-action[bot]"
Date: Sun, 7 Apr 2024 20:25:37 +0200
Subject: [PATCH] Update On Sun Apr 7 20:25:36 CEST 2024
---
.github/update.log | 1 +
.../src/main/golang/native/config/fetch.go | 2 +-
clash-meta/adapter/provider/parser.go | 5 +-
clash-meta/adapter/provider/provider.go | 4 +-
clash-meta/component/geodata/init.go | 4 +-
clash-meta/component/http/http.go | 6 +-
clash-meta/component/mmdb/mmdb.go | 4 +-
clash-meta/component/resource/vehicle.go | 2 +-
clash-meta/config/utils.go | 2 +-
clash-meta/hub/updater/updater.go | 4 +-
clash-meta/rules/provider/parse.go | 5 +-
clash-nyanpasu/.github/workflows/release.yml | 12 +
clash-nyanpasu/README.md | 7 +
clash-nyanpasu/backend/tauri/src/cmds.rs | 35 +-
.../backend/tauri/src/core/commands/mod.rs | 44 ++-
.../backend/tauri/src/core/storage.rs | 6 +
.../backend/tauri/src/core/tray/mod.rs | 4 +-
clash-nyanpasu/backend/tauri/src/main.rs | 17 +-
.../backend/tauri/src/utils/help.rs | 35 +-
.../backend/tauri/src/utils/init/mod.rs | 17 +-
clash-nyanpasu/manifest/version.json | 4 +-
clash-nyanpasu/package.json | 2 +-
clash-nyanpasu/pnpm-lock.yaml | 8 +-
.../src/components/setting/setting-verge.tsx | 4 +-
clash-nyanpasu/src/services/cmds.ts | 4 +
echo/.github/workflows/cd.yaml | 9 +-
echo/README.md | 300 +-----------------
echo/internal/cli/app.go | 2 +-
echo/internal/cli/config.go | 6 +-
echo/internal/constant/constant.go | 21 +-
echo/internal/relay/conf/cfg.go | 45 ++-
echo/internal/relay/relay.go | 124 ++------
echo/internal/relay/server.go | 6 +-
echo/internal/transporter/base.go | 55 ++++
echo/internal/transporter/interface.go | 70 ++--
echo/internal/transporter/mux.go | 63 ++++
echo/internal/transporter/raw.go | 84 ++---
echo/internal/transporter/raw_mux.go | 134 +++-----
echo/internal/transporter/ws.go | 78 ++---
echo/internal/transporter/wss.go | 70 ++--
echo/internal/transporter/wss_mux.go | 151 +++------
.../transporter => pkg/buffer}/buffer.go | 2 +-
echo/pkg/sub/clash_types.go | 4 +-
echo/test/relay_test.go | 36 +--
mihomo/adapter/provider/parser.go | 5 +-
mihomo/adapter/provider/provider.go | 4 +-
mihomo/component/geodata/init.go | 4 +-
mihomo/component/http/http.go | 6 +-
mihomo/component/mmdb/mmdb.go | 4 +-
mihomo/component/resource/vehicle.go | 2 +-
mihomo/config/utils.go | 2 +-
mihomo/hub/updater/updater.go | 4 +-
mihomo/rules/provider/parse.go | 5 +-
openwrt-packages/luci-app-store/Makefile | 2 +-
.../luci-app-store/root/bin/is-opkg | 8 +-
small/chinadns-ng/Makefile | 4 +-
.../model/cbi/shadowsocksr/client-config.lua | 20 ++
small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po | 21 ++
.../usr/share/shadowsocksr/gen_config.lua | 27 +-
suyu/.ci/scripts/windows/docker.sh | 10 +-
suyu/.forgejo/workflows/verify.yml | 4 +-
xray-core/app/proxyman/outbound/handler.go | 33 +-
xray-core/go.mod | 10 +-
xray-core/go.sum | 20 +-
xray-core/proxy/freedom/freedom.go | 3 +
.../workflows/releases-linux-binary.yml | 54 +++-
yass/CMakeLists.txt | 26 +-
yass/src/core/debug.cpp | 5 +-
yass/src/core/rand_util_posix.cpp | 3 +-
.../crypto/fipsmodule/rand/getrandom_fillin.h | 2 +
.../boringssl/src/include/openssl/target.h | 9 +-
.../googleurl-override/build/build_config.h | 5 +
yass/third_party/quiche/CMakeLists.txt | 1 -
yass/tools/build.go | 4 +
youtube-dl/youtube_dl/postprocessor/ffmpeg.py | 16 +-
yt-dlp/yt_dlp/cookies.py | 6 +-
yt-dlp/yt_dlp/extractor/nhk.py | 200 +++++++++---
yt-dlp/yt_dlp/extractor/patreon.py | 44 ++-
yt-dlp/yt_dlp/extractor/tiktok.py | 1 +
yt-dlp/yt_dlp/extractor/vk.py | 15 +-
80 files changed, 1034 insertions(+), 1053 deletions(-)
create mode 100644 echo/internal/transporter/base.go
rename echo/{internal/transporter => pkg/buffer}/buffer.go (98%)
diff --git a/.github/update.log b/.github/update.log
index 6a0002be8d..fc7c345ef7 100644
--- a/.github/update.log
+++ b/.github/update.log
@@ -609,3 +609,4 @@ Update On Wed Apr 3 20:26:29 CEST 2024
Update On Thu Apr 4 20:27:14 CEST 2024
Update On Fri Apr 5 20:26:37 CEST 2024
Update On Sat Apr 6 20:26:05 CEST 2024
+Update On Sun Apr 7 20:25:26 CEST 2024
diff --git a/clash-meta-android/core/src/main/golang/native/config/fetch.go b/clash-meta-android/core/src/main/golang/native/config/fetch.go
index d919f6e745..c1b25105c2 100644
--- a/clash-meta-android/core/src/main/golang/native/config/fetch.go
+++ b/clash-meta-android/core/src/main/golang/native/config/fetch.go
@@ -25,7 +25,7 @@ type Status struct {
}
func openUrl(ctx context.Context, url string) (io.ReadCloser, error) {
- response, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"ClashMetaForAndroid/" + app.VersionName()}}, nil, "")
+ response, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"ClashMetaForAndroid/" + app.VersionName()}}, nil)
if err != nil {
return nil, err
diff --git a/clash-meta/adapter/provider/parser.go b/clash-meta/adapter/provider/parser.go
index bbaf29be31..1094668d46 100644
--- a/clash-meta/adapter/provider/parser.go
+++ b/clash-meta/adapter/provider/parser.go
@@ -88,16 +88,13 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
path := C.Path.Resolve(schema.Path)
vehicle = resource.NewFileVehicle(path)
case "http":
- var path string
+ path := C.Path.GetPathByHash("proxies", schema.URL)
if schema.Path != "" {
path = C.Path.Resolve(schema.Path)
if !features.CMFA && !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("%w: %s", errSubPath, path)
}
- } else {
- path = C.Path.GetPathByHash("proxies", schema.URL)
}
-
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header)
default:
return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
diff --git a/clash-meta/adapter/provider/provider.go b/clash-meta/adapter/provider/provider.go
index aa5b823350..2715a30972 100644
--- a/clash-meta/adapter/provider/provider.go
+++ b/clash-meta/adapter/provider/provider.go
@@ -125,7 +125,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(),
- http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
@@ -134,7 +134,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() {
userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo"))
if userInfoStr == "" {
resp2, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(),
- http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil, "")
+ http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil)
if err != nil {
return
}
diff --git a/clash-meta/component/geodata/init.go b/clash-meta/component/geodata/init.go
index 64022f013b..834567a447 100644
--- a/clash-meta/component/geodata/init.go
+++ b/clash-meta/component/geodata/init.go
@@ -47,7 +47,7 @@ func InitGeoSite() error {
func downloadGeoSite(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
@@ -66,7 +66,7 @@ func downloadGeoSite(path string) (err error) {
func downloadGeoIP(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
diff --git a/clash-meta/component/http/http.go b/clash-meta/component/http/http.go
index ef37e328b8..21d65d2e96 100644
--- a/clash-meta/component/http/http.go
+++ b/clash-meta/component/http/http.go
@@ -16,7 +16,11 @@ import (
"github.com/metacubex/mihomo/listener/inner"
)
-func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) {
+func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) {
+ return HttpRequestWithProxy(ctx, url, method, header, body, "")
+}
+
+func HttpRequestWithProxy(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) {
method = strings.ToUpper(method)
urlRes, err := URL.Parse(url)
if err != nil {
diff --git a/clash-meta/component/mmdb/mmdb.go b/clash-meta/component/mmdb/mmdb.go
index 120739fc15..81156bc62d 100644
--- a/clash-meta/component/mmdb/mmdb.go
+++ b/clash-meta/component/mmdb/mmdb.go
@@ -82,7 +82,7 @@ func IPInstance() IPReader {
func DownloadMMDB(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
@@ -115,7 +115,7 @@ func ASNInstance() ASNReader {
func DownloadASN(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
diff --git a/clash-meta/component/resource/vehicle.go b/clash-meta/component/resource/vehicle.go
index 2f71c2e6c6..2d71be9455 100644
--- a/clash-meta/component/resource/vehicle.go
+++ b/clash-meta/component/resource/vehicle.go
@@ -54,7 +54,7 @@ func (h *HTTPVehicle) Path() string {
func (h *HTTPVehicle) Read() ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, h.header, nil, h.proxy)
+ resp, err := mihomoHttp.HttpRequestWithProxy(ctx, h.url, http.MethodGet, h.header, nil, h.proxy)
if err != nil {
return nil, err
}
diff --git a/clash-meta/config/utils.go b/clash-meta/config/utils.go
index 596199ca18..66bf3441f2 100644
--- a/clash-meta/config/utils.go
+++ b/clash-meta/config/utils.go
@@ -20,7 +20,7 @@ import (
func downloadForBytes(url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return nil, err
}
diff --git a/clash-meta/hub/updater/updater.go b/clash-meta/hub/updater/updater.go
index e0d3a39ca1..02ff07ba26 100644
--- a/clash-meta/hub/updater/updater.go
+++ b/clash-meta/hub/updater/updater.go
@@ -234,7 +234,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024
func downloadPackageFile() (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return fmt.Errorf("http request failed: %w", err)
}
@@ -415,7 +415,7 @@ func copyFile(src, dst string) error {
func getLatestVersion() (version string, err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return "", fmt.Errorf("get Latest Version fail: %w", err)
}
diff --git a/clash-meta/rules/provider/parse.go b/clash-meta/rules/provider/parse.go
index e7920adf6c..a20da28d5c 100644
--- a/clash-meta/rules/provider/parse.go
+++ b/clash-meta/rules/provider/parse.go
@@ -62,15 +62,12 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t
path := C.Path.Resolve(schema.Path)
vehicle = resource.NewFileVehicle(path)
case "http":
- var path string
+ path := C.Path.GetPathByHash("rules", schema.URL)
if schema.Path != "" {
path = C.Path.Resolve(schema.Path)
if !features.CMFA && !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("%w: %s", errSubPath, path)
}
- } else {
- path = C.Path.GetPathByHash("rules", schema.URL)
-
}
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil)
default:
diff --git a/clash-nyanpasu/.github/workflows/release.yml b/clash-nyanpasu/.github/workflows/release.yml
index 31a7418843..2d81116cb4 100644
--- a/clash-nyanpasu/.github/workflows/release.yml
+++ b/clash-nyanpasu/.github/workflows/release.yml
@@ -171,3 +171,15 @@ jobs:
TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
TELEGRAM_TO: "@keikolog"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Post Tweet
+ uses: rg-wood/send-tweet-action@v1
+ with:
+ status: |
+ Clash Nyanpasu ${{ github.event.release.tag_name }} Released!
+
+ Download Link: https://github.com/LibNyanpasu/clash-nyanpasu/releases/tag/v${{ github.event.release.tag_name }}
+ consumer-key: ${{ secrets.TWITTER_CONSUMER_KEY }}
+ consumer-secret: ${{ secrets.TWITTER_CONSUMER_SECRET }}
+ access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }}
+ access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
diff --git a/clash-nyanpasu/README.md b/clash-nyanpasu/README.md
index d5649a84b2..3da481c2d7 100644
--- a/clash-nyanpasu/README.md
+++ b/clash-nyanpasu/README.md
@@ -14,6 +14,12 @@ A Clash GUI based on
+
+
+
+
+
## Features
@@ -80,6 +86,7 @@ Issue and PR welcome!
Clash Nyanpasu was based on or inspired by these projects and so on:
- [zzzgydi/clash-verge](https://github.com/zzzgydi/clash-verge): A Clash GUI based on tauri. Supports Windows, macOS and Linux.
+- [clash-verge-rev/clash-verge-rev](https://github.com/clash-verge-rev/clash-verge-rev): Another fork of Clash Verge. Some patches are included for bug fixes.
- [tauri-apps/tauri](https://github.com/tauri-apps/tauri): Build smaller, faster, and more secure desktop applications with a web frontend.
- [Dreamacro/clash](https://github.com/Dreamacro/clash): A rule-based tunnel in Go.
- [MetaCubeX/Clash.Meta](https://github.com/MetaCubeX/mihomo): A rule-based tunnel in Go.
diff --git a/clash-nyanpasu/backend/tauri/src/cmds.rs b/clash-nyanpasu/backend/tauri/src/cmds.rs
index 03cd2e9822..c5b47be8b2 100644
--- a/clash-nyanpasu/backend/tauri/src/cmds.rs
+++ b/clash-nyanpasu/backend/tauri/src/cmds.rs
@@ -384,41 +384,46 @@ pub fn get_custom_app_dir() -> CmdResult> {
pub async fn set_custom_app_dir(app_handle: tauri::AppHandle, path: String) -> CmdResult {
use crate::utils::{self, dialog::migrate_dialog, winreg::set_app_dir};
use rust_i18n::t;
- use std::{path::PathBuf, time::Duration};
+ use std::path::PathBuf;
let path_str = path.clone();
let path = PathBuf::from(path);
// show a dialog to ask whether to migrate the data
- let res = tauri::async_runtime::spawn_blocking(move || {
- let msg = t!("dialog.custom_app_dir_migrate", path = path_str).to_string();
+ let res =
+ tauri::async_runtime::spawn_blocking(move || {
+ let msg = t!("dialog.custom_app_dir_migrate", path = path_str).to_string();
- if migrate_dialog(&msg) {
- let app_exe = tauri::utils::platform::current_exe()?;
- let app_exe = dunce::canonicalize(app_exe)?.to_string_lossy().to_string();
- std::thread::spawn(move || {
+ if migrate_dialog(&msg) {
+ let app_exe = tauri::utils::platform::current_exe()?;
+ let app_exe = dunce::canonicalize(app_exe)?.to_string_lossy().to_string();
std::process::Command::new("powershell")
.arg("-Command")
.arg(
format!(
- r#"Start-Process '{}' -ArgumentList 'migrate-home-dir','{}' -Verb runAs"#,
+ r#"Start-Process '{}' -ArgumentList 'migrate-home-dir','"{}"' -Verb runAs"#,
app_exe.as_str(),
path_str.as_str()
)
.as_str(),
).spawn().unwrap();
utils::help::quit_application(&app_handle);
- });
- } else {
- set_app_dir(&path)?;
- }
- Ok::<_, anyhow::Error>(())
- })
- .await;
+ } else {
+ set_app_dir(&path)?;
+ }
+ Ok::<_, anyhow::Error>(())
+ })
+ .await;
wrap_err!(wrap_err!(res)?)?;
Ok(())
}
+#[tauri::command]
+pub fn restart_application(app_handle: tauri::AppHandle) -> CmdResult {
+ crate::utils::help::restart_application(&app_handle);
+ Ok(())
+}
+
#[cfg(not(windows))]
#[tauri::command]
pub async fn set_custom_app_dir(_path: String) -> CmdResult {
diff --git a/clash-nyanpasu/backend/tauri/src/core/commands/mod.rs b/clash-nyanpasu/backend/tauri/src/core/commands/mod.rs
index 9a4dbd706d..af5484acf6 100644
--- a/clash-nyanpasu/backend/tauri/src/core/commands/mod.rs
+++ b/clash-nyanpasu/backend/tauri/src/core/commands/mod.rs
@@ -1,5 +1,10 @@
+use std::str::FromStr;
+
use anyhow::Ok;
-use clap::{Parser, Subcommand};
+use clap::{Args, Parser, Subcommand};
+use tauri::utils::platform::current_exe;
+
+use crate::utils;
#[derive(Parser, Debug)]
#[command(name = "clash-nyanpasu", version, about, long_about = None)]
@@ -12,16 +17,52 @@ pub struct Cli {
enum Commands {
#[command(about = "Migrate home directory to another path.")]
MigrateHomeDir { target_path: String },
+ #[command(about = "A launch bridge to resolve the delay exit issue.")]
+ Launch {
+ // FIXME: why the raw arg is not working?
+ #[arg(raw = true)]
+ args: Vec,
+ },
+}
+
+struct DelayedExitGuard;
+impl DelayedExitGuard {
+ pub fn new() -> Self {
+ Self
+ }
+}
+impl Drop for DelayedExitGuard {
+ fn drop(&mut self) {
+ std::thread::sleep(std::time::Duration::from_secs(5));
+ }
}
pub fn parse() -> anyhow::Result<()> {
let cli = Cli::parse();
if let Some(commands) = &cli.command {
+ let guard = DelayedExitGuard::new();
match commands {
Commands::MigrateHomeDir { target_path } => {
self::handler::migrate_home_dir_handler(target_path).unwrap();
}
+ Commands::Launch { args } => {
+ let _ = utils::init::check_singleton().unwrap();
+ let appimage: Option = {
+ #[cfg(target_os = "linux")]
+ {
+ std::env::var_os("APPIMAGE").map(|s| s.to_string_lossy().to_string())
+ }
+ #[cfg(not(target_os = "linux"))]
+ None
+ };
+ let path = match appimage {
+ Some(appimage) => std::path::PathBuf::from_str(&appimage).unwrap(),
+ None => current_exe().unwrap(),
+ };
+ std::process::Command::new(path).args(args).spawn().unwrap();
+ }
}
+ drop(guard);
std::process::exit(0);
}
Ok(()) // bypass
@@ -36,6 +77,7 @@ mod handler {
use std::{path::PathBuf, process::Command, str::FromStr, thread, time::Duration};
use sysinfo::System;
use tauri::utils::platform::current_exe;
+ println!("target path {}", target_path);
let token = Token::with_current_process()?;
if let PrivilegeLevel::NotPrivileged = token.privilege_level()? {
diff --git a/clash-nyanpasu/backend/tauri/src/core/storage.rs b/clash-nyanpasu/backend/tauri/src/core/storage.rs
index cbb571e21d..c37c8cffa2 100644
--- a/clash-nyanpasu/backend/tauri/src/core/storage.rs
+++ b/clash-nyanpasu/backend/tauri/src/core/storage.rs
@@ -28,3 +28,9 @@ impl Storage {
rocksdb::DB::destroy(&rocksdb::Options::default(), &self.path)
}
}
+
+impl Drop for Storage {
+ fn drop(&mut self) {
+ self.destroy().unwrap();
+ }
+}
diff --git a/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs b/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs
index 777114f581..13ea8415bc 100644
--- a/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs
+++ b/clash-nyanpasu/backend/tauri/src/core/tray/mod.rs
@@ -2,7 +2,7 @@ use crate::{cmds, config::Config, feat, utils, utils::resolve};
use anyhow::Result;
use rust_i18n::t;
use tauri::{
- api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
+ AppHandle, CustomMenuItem, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
SystemTraySubmenu,
};
use tracing_attributes::instrument;
@@ -151,7 +151,7 @@ impl Tray {
"open_core_dir" => crate::log_err!(cmds::open_core_dir()),
"open_logs_dir" => crate::log_err!(cmds::open_logs_dir()),
"restart_clash" => feat::restart_clash_core(),
- "restart_app" => api::process::restart(&app_handle.env()),
+ "restart_app" => utils::help::restart_application(app_handle),
"quit" => {
utils::help::quit_application(app_handle);
}
diff --git a/clash-nyanpasu/backend/tauri/src/main.rs b/clash-nyanpasu/backend/tauri/src/main.rs
index ebb87e02a6..a38c0ce775 100644
--- a/clash-nyanpasu/backend/tauri/src/main.rs
+++ b/clash-nyanpasu/backend/tauri/src/main.rs
@@ -13,9 +13,8 @@ mod utils;
use crate::{
config::Config,
core::{commands, handle::Handle},
- utils::{dirs, init, resolve},
+ utils::{init, resolve},
};
-use anyhow::Context;
use tauri::{api, Manager, SystemTray};
rust_i18n::i18n!("../../locales");
@@ -54,16 +53,7 @@ fn main() -> std::io::Result<()> {
tauri_plugin_deep_link::prepare("moe.elaina.clash.nyanpasu");
// 单例检测
- let placeholder = dirs::get_single_instance_placeholder();
- let single_instance_result: anyhow::Result<()> =
- single_instance::SingleInstance::new(&placeholder)
- .context("failed to create single instance")
- .map(|instance| {
- if !instance.is_single() {
- println!("app exists");
- std::process::exit(0);
- }
- });
+ let single_instance_result = utils::init::check_singleton();
// Use system locale as default
let locale = {
@@ -86,7 +76,7 @@ fn main() -> std::io::Result<()> {
rust_i18n::set_locale(verge.as_str());
// show a dialog to print the single instance error
- single_instance_result.unwrap();
+ let _singleton = single_instance_result.unwrap(); // hold the guard until the end of the program
#[allow(unused_mut)]
let mut builder = tauri::Builder::default()
@@ -179,6 +169,7 @@ fn main() -> std::io::Result<()> {
cmds::get_proxies,
cmds::select_proxy,
cmds::update_proxy_provider,
+ cmds::restart_application,
]);
#[cfg(target_os = "macos")]
diff --git a/clash-nyanpasu/backend/tauri/src/utils/help.rs b/clash-nyanpasu/backend/tauri/src/utils/help.rs
index 642d64314e..5d5096c59c 100644
--- a/clash-nyanpasu/backend/tauri/src/utils/help.rs
+++ b/clash-nyanpasu/backend/tauri/src/utils/help.rs
@@ -14,7 +14,10 @@ use std::{
str::FromStr,
};
use tauri::{
- api::shell::{open, Program},
+ api::{
+ process::current_binary,
+ shell::{open, Program},
+ },
AppHandle, Manager,
};
use tracing::{debug, warn};
@@ -216,14 +219,36 @@ pub fn get_max_scale_factor() -> f64 {
}
#[instrument(skip(app_handle))]
-pub fn quit_application(app_handle: &AppHandle) {
+fn cleanup_processes(app_handle: &AppHandle) {
let _ = super::resolve::save_window_state(app_handle, true);
-
super::resolve::resolve_reset();
tauri::api::process::kill_children();
+}
+
+#[instrument(skip(app_handle))]
+pub fn quit_application(app_handle: &AppHandle) {
+ cleanup_processes(app_handle);
+ app_handle.exit(0);
+ std::process::exit(0);
+}
+
+#[instrument(skip(app_handle))]
+pub fn restart_application(app_handle: &AppHandle) {
+ cleanup_processes(app_handle);
+ let env = app_handle.env();
+ let path = current_binary(&env).unwrap();
+ let arg = std::env::args().collect::>();
+ let mut args = vec!["launch".to_string(), "--".to_string()];
+ // filter out the first arg
+ if arg.len() > 1 {
+ args.extend(arg.iter().skip(1).cloned());
+ }
+ tracing::info!("restart app: {:#?} with args: {:#?}", path, args);
+ std::process::Command::new(path)
+ .args(args)
+ .spawn()
+ .expect("application failed to start");
app_handle.exit(0);
- // flush all data to disk
- crate::core::storage::Storage::global().destroy().unwrap();
std::process::exit(0);
}
diff --git a/clash-nyanpasu/backend/tauri/src/utils/init/mod.rs b/clash-nyanpasu/backend/tauri/src/utils/init/mod.rs
index 7e8a3b7de7..3ccb36a50c 100644
--- a/clash-nyanpasu/backend/tauri/src/utils/init/mod.rs
+++ b/clash-nyanpasu/backend/tauri/src/utils/init/mod.rs
@@ -2,7 +2,7 @@ use crate::{
config::*,
utils::{dialog::migrate_dialog, dirs, help},
};
-use anyhow::Result;
+use anyhow::{Context, Result};
use fs_extra::dir::CopyOptions;
use runas::Command as RunasCommand;
use rust_i18n::t;
@@ -196,6 +196,21 @@ pub fn init_service() -> Result<()> {
Ok(())
}
+pub fn check_singleton() -> Result {
+ let placeholder = super::dirs::get_single_instance_placeholder();
+ for i in 0..5 {
+ let instance = single_instance::SingleInstance::new(&placeholder)
+ .context("failed to create single instance")?;
+ if instance.is_single() {
+ return Ok(instance);
+ }
+ if i != 4 {
+ std::thread::sleep(std::time::Duration::from_secs(1));
+ }
+ }
+ anyhow::bail!("single instance check failed: app still exists after 4s");
+}
+
pub fn do_config_migration(old_app_dir: &PathBuf, app_dir: &PathBuf) -> anyhow::Result<()> {
let copy_option = CopyOptions::new();
let copy_option = copy_option.overwrite(true);
diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json
index 3d99d907ff..62a400b675 100644
--- a/clash-nyanpasu/manifest/version.json
+++ b/clash-nyanpasu/manifest/version.json
@@ -2,7 +2,7 @@
"manifest_version": 1,
"latest": {
"mihomo": "v1.18.3",
- "mihomo_alpha": "alpha-5bae0b6",
+ "mihomo_alpha": "alpha-c44949b",
"clash_rs": "v0.1.15",
"clash_premium": "2023-09-05-gdcc8d87"
},
@@ -36,5 +36,5 @@
"darwin-x64": "clash-darwin-amd64-n{}.gz"
}
},
- "updated_at": "2024-04-05T22:19:27.268Z"
+ "updated_at": "2024-04-06T22:19:13.513Z"
}
diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json
index e6ebfa2d0f..c5c04f5c5a 100644
--- a/clash-nyanpasu/package.json
+++ b/clash-nyanpasu/package.json
@@ -91,7 +91,7 @@
"react-markdown": "9.0.1",
"react-router-dom": "6.22.3",
"react-transition-group": "4.4.5",
- "react-virtuoso": "4.7.7",
+ "react-virtuoso": "4.7.8",
"recoil": "0.7.7",
"swr": "2.2.5"
},
diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml
index c940be7fb1..305360b441 100644
--- a/clash-nyanpasu/pnpm-lock.yaml
+++ b/clash-nyanpasu/pnpm-lock.yaml
@@ -93,8 +93,8 @@ dependencies:
specifier: 4.4.5
version: 4.4.5(react-dom@18.2.0)(react@18.2.0)
react-virtuoso:
- specifier: 4.7.7
- version: 4.7.7(react-dom@18.2.0)(react@18.2.0)
+ specifier: 4.7.8
+ version: 4.7.8(react-dom@18.2.0)(react@18.2.0)
recoil:
specifier: 0.7.7
version: 0.7.7(react-dom@18.2.0)(react@18.2.0)
@@ -6251,8 +6251,8 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
- /react-virtuoso@4.7.7(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-n9NdMNaAtxHYH6e3H6zr1Kb08sp+1XPVnfE4cEMgrvmPBLugd9eeJtQo/1uA+SHhGaPX3uqZOuQsfKbX1r8P/A==}
+ /react-virtuoso@4.7.8(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-P0BHOsLrmfnXv1bY9Nja07nvFciRGNgM7lTRHMcVDteTDb9tLtHzajBapKGUZ5zdyUOEVWvuW6ufQxzdGN2AKw==}
engines: {node: '>=10'}
peerDependencies:
react: '>=16 || >=17 || >= 18'
diff --git a/clash-nyanpasu/src/components/setting/setting-verge.tsx b/clash-nyanpasu/src/components/setting/setting-verge.tsx
index bd507e85e4..d7c0cc3a80 100644
--- a/clash-nyanpasu/src/components/setting/setting-verge.tsx
+++ b/clash-nyanpasu/src/components/setting/setting-verge.tsx
@@ -7,6 +7,7 @@ import {
openAppDir,
openCoreDir,
openLogsDir,
+ restartApplication,
setCustomAppDir,
} from "@/services/cmds";
import { sleep } from "@/utils";
@@ -22,7 +23,6 @@ import {
Typography,
} from "@mui/material";
import { open } from "@tauri-apps/api/dialog";
-import { relaunch } from "@tauri-apps/api/process";
import { checkUpdate } from "@tauri-apps/api/updater";
import { useAsyncEffect, useLockFn } from "ahooks";
import { useRef, useState } from "react";
@@ -123,7 +123,7 @@ const SettingVerge = ({ onError }: Props) => {
body: t("App directory changed successfully"),
});
await sleep(1000);
- await relaunch();
+ await restartApplication();
} catch (err: any) {
useMessage(err.message || err.toString(), {
title: t("Error"),
diff --git a/clash-nyanpasu/src/services/cmds.ts b/clash-nyanpasu/src/services/cmds.ts
index fd825604a7..4834f9d06a 100644
--- a/clash-nyanpasu/src/services/cmds.ts
+++ b/clash-nyanpasu/src/services/cmds.ts
@@ -264,3 +264,7 @@ export async function getCustomAppDir() {
export async function setCustomAppDir(path: string) {
return invoke("set_custom_app_dir", { path });
}
+
+export async function restartApplication() {
+ return invoke("restart_application");
+}
diff --git a/echo/.github/workflows/cd.yaml b/echo/.github/workflows/cd.yaml
index 9a6cd48e67..a2723fedc6 100644
--- a/echo/.github/workflows/cd.yaml
+++ b/echo/.github/workflows/cd.yaml
@@ -166,9 +166,12 @@ jobs:
echo "Creating manifest list..."
AMD64_DIGEST=$(ls amd64/)
ARM64_DIGEST=$(ls arm64/)
- docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
- --append ${{ env.REGISTRY_IMAGE }}@sha256:$AMD64_DIGEST \
- --append ${{ env.REGISTRY_IMAGE }}@sha256:$ARM64_DIGEST
+ echo "AMD64_DIGEST: $AMD64_DIGEST"
+ echo "ARM64_DIGEST: $ARM64_DIGEST"
+ docker buildx imagetools create \
+ --tag ${{ env.REGISTRY_IMAGE }}:latest \
+ ${{ env.REGISTRY_IMAGE }}@sha256:$AMD64_DIGEST \
+ ${{ env.REGISTRY_IMAGE }}@sha256:$ARM64_DIGEST
- name: Inspect image
run: |
diff --git a/echo/README.md b/echo/README.md
index 91bb48475f..dcb17f3af5 100644
--- a/echo/README.md
+++ b/echo/README.md
@@ -8,126 +8,11 @@
## Ehco Relay - 让流量转发更简单
-我们很高兴地宣布,ehco 现在提供 SaaS(软件即服务)版本!这是一个全托管的解决方案,旨在为那些希望在不搭建和管理自己的服务器的情况下享受 ehco 强大流量转发能力的用户提供服务。
+ehco 现在提供 SaaS(软件即服务)版本!这是一个全托管的解决方案,旨在为那些希望在不搭建和管理自己的服务器的情况下享受 ehco 强大流量转发能力的用户提供服务。
- [Ehco Relay 官方网站](https://ehco-relay.cc)
- [Ehco Relay 文档](https://docs.ehco-relay.cc/)
-### 为什么选择 Ehco Relay?
-
-- **即刻启动**:无需复杂的配置或服务器管理,立即获得高性能的流量转发服务。
-- **全面托管**:我们的团队会处理所有后端事务,包括维护、更新和故障排除,让您可以专注于您的主要业务。
-- **灵活的计划**:无论您是个人开发者还是大型企业,我们都提供多种计划来满足您的需求。
-- **安全可靠**:利用最先进的加密技术,确保您的数据传输安全无忧。
-
-欢迎访问官网来了解更多信息,并开始您的免费试用。只需几个简单的步骤,您就可以轻松地设置并运行 ehco,享受无缝的流量转发服务。
-
-## 使用场景
-
- 连接内网服务
-
-本地无法链接集群内的服务,可以通过 ehco 将本地流量转发到集群内,方便本地开发和调试
-
-e.g. 本地开发调试连接内网服务 db, db host: xxx-rds.xxx.us-east-1.rds.amazonaws.com
-
-1. 在 k8s 内 启动一个 ehco pod. 启动命令如下:
- `ehco -l 0.0.0.0:3306 -r xxx-rds.xxx.us-east-1.rds.amazonaws.com:3306`
-
-2. 使用 kube port-forward 将本地的 3306 端口转发到 ehco pod 的 3306 端口
- `kubectl port-forward pod/ehco-pod 3306:3306`
-
-3. 本地使用客户端连接
- `mysql -h 127.0.0.1:3306 -u root -p`
-
-
- 中转 proxy 客户端,提供负载均衡功能
-
-从 **v1.1.4-dev(nightly)** 开始, ehco 支持了从 clash proxy provider 读取 proxy 配置并复写成 ehco 的 relay 配置
-从而实现了 ehco 作为代理客户端的前置代理,提供负载均衡,流量监控等功能
-
-e.g.
-
-1. 配置 ehco 的 config.json 并启动
-
-```json
-{
- "web_host": "12.0.0.1",
- "web_port": 9000,
- "sub_configs": [
- {
- "name": "nas",
- "url": "your url"
- }
- ]
-}
-```
-
-`ehco -c config.json`
-
-2. 访问 ehco 的 web 界面 获取 ehco 的 proxy provider url
-
-`http://:`
-
-
-
-ehco 会将每个 clash proxy provider 转换成两个新 clash provider
-
-- 会将每个的 proxy 转换成一个 relay
-- 会将 proxy 按最长前缀**分组**,并将每个分组转换成开启负载均衡的 relay
-
-举个例子
-
-```yaml
-proxies:
- - name: us-1
- server: s1
- password:
- port: 1
- - name: us-2
- server: s2
- port: 2
- - name: jb-1
- server: s3
- password: pass
- port: 3
-```
-
-上面这个包含 3 个 proxy 的会被转换成 5 个 relay:
-
-- us-1 relay to s1:1
-- us-2 relay to s2:2
-- jb-1 relay to s3:3
- us-lb relay to s1:1,s2:2
-- jb-1-lb relay to s3:3
-
-3. 将 ehco 的 proxy provider url 配置到 clash 的配置文件中
-
-```yaml
-proxy-providers:
- ehco:
- type: http
- url: http://:/clash_proxy_provider/?sub_name=
- ehco-lb:
- type: http
- url: http://:/clash_proxy_provider/?sub_name=name&grouped=true
-```
-
-你就能得到一个支持负载均衡的 clash proxy client 了,并且还能在 dashboard 上看到流量监控哟
-
-
-
-
- WIP: 隧道连接到 proxy 集群
-
-
-## 安装
-
-- ehco 提供预编译的的二进制 [release](https://github.com/Ehco1996/ehco/releases) 页面下载
-
-- ehco 提供 [nightly build](https://github.com/Ehco1996/ehco/releases/tag/v0.0.0-nightly)
-
-- ehco 提供 docker 镜像 `docker pull ehco1996/ehco`
-
## 主要功能
- tcp/udp relay
@@ -135,185 +20,4 @@ proxy-providers:
- proxy server (内嵌了完整班版本的 xray)
- 监控报警 (prometheus/grafana)
- WebAPI (http://web_host:web_port)
-
-## 中转使用介绍
-
-使用隧道需要至少两台主机, 并且在两台主机上都安装了 ehco
-
-- 中转机器 A 假设机器 A 的 IP 是 1.1.1.1
-- 落地机器 B 假设机器 B 的 IP 是 2.2.2.2 并且落地机器 B 的 5555 端口跑着一个 SS/v2ray/任意 tcp/udp 服务
-
- 案例一 不用隧道直接通过中转机器中转用户流量
-直接在中转机器 A 上输入: `ehco -l 0.0.0.0:1234 -r 2.2.2.2:5555`
-
-> 该命令表示将所有从中转机器 A 的 1234 端口进入的流量直接转发到落地机器 B 的 5555 端口
-
-用户即可通过 中转机器 A 的 1234 端口访问到落地机器 B 的 5555 端口的 SS/v2ray 服务了
-
-
-
- 案例二 用 mwss 隧道中转用户流量
-在落地机器 B 上输入: `ehco -l 0.0.0.0:443 -lt mwss -r 127.0.0.1:5555`
-
-> 该命令表示将所有从落地机器 B 的 443 端口进入的 wss 流量解密后转发到落地机器 B 的 5555 端口
-
-在中转机器 A 上输入: `ehco -l 0.0.0.0:1234 -r wss://2.2.2.2:443 -tt mwss`
-
-> 该命令表示将所有从 A 的 1234 端口进入的流量通过 wss 加密后转发到落地机器 B 的 443 端口
-
-用户即可通过 中转机器 A 的 1234 端口访问到落地机器 B 的 5555 端口的 SS/v2ray 服务了
-
-
-
-## 内嵌 Xray 功能介绍
-
- ehco 内的 xray 服务端
-从 `v1.1.2` 开始,ehco 内置了完整版本的 [xray](https://github.com/XTLS/Xray-core) 后端,可以通过标准的 xray 配置文件来启动内置的 xray server, 配置的 key 为 `xray_config`:
-
-- 单端口多用户的 ss [xray_ss.json](examples/xray_ss.json)
-- 单端口多用户的 trojan [xray_trojan.json](examples/xray_trojan.json)
-
-
- 用户流量统计
-
-从 `v1.1.2` 开始,ehco 支持通过 api 下方用户配置和上报用户流量,配置的 key 为 `sync_traffic_endpoint`:
-
-ehco 会每隔 60s 发送一次 GET 请求,从 `sync_traffic_endpoint` 同步一次用户配置,到 xray server 里,期望的 API 返回格式如下:
-
-```json
-{
- "users": [
- {
- "user_id": 1,
- "method": "user1",
- "password": 1024,
- "level": 1024,
- "upload_traffic": 1024,
- "download_traffic": 1024,
- "protocol": "trojan/ss"
- },
- {
- "user_id": 2,
- "method": "user1",
- "password": 1024,
- "level": 1024,
- "upload_traffic": 1024,
- "download_traffic": 1024,
- "protocol": "trojan/ss"
- }
- ]
-}
-```
-
-ehco 会每隔 60s 发送一次 POST 请求至 `sync_traffic_endpoint` ,上报当前 xray server 所有用户的流量使用情况,发送的请求格式如下:
-
-```json
-{
- "data": [
- {
- "user_id": 1,
- "upload_traffic": 1024,
- "download_traffic": 1024
- },
- {
- "user_id": 2,
- "upload_traffic": 1024,
- "download_traffic": 1024
- }
- ]
-}
-```
-
-需要注意的是,如果想使用此功能,对 xray 的完整配置文件有如下限制
-
-- 的配置文件必须包开启 `stats` 和 `api` 功能
-- ss inbound 的 `tag` 必须为 `ss_proxy`
-- trojan inbound 的 `tag` 必须为 `trojan_proxy`
-
-一个完整的例子可以参考 [xray_ss.json](examples/xray_ss.json) 和 [xray_trojan.json](examples/xray_trojan.json)
-
-
-
-## 配置文件格式
-
-> ehco 支持从 `配置文件` / `http接口` 里读取 `json` 格式的配置并启动
-> (更多例子可以参考项目里的 [config.json](examples/config.json) 文件):
-
- 热重载配置
-
-- 大于 1.1.0 版本的 ehco 支持热重载配置
-- 通过 `kill -HUP pid` 信号来热重载配置
-- 通过配置 `reload_interval` 来指定配置文件的路径
-- 通过访问 POST `http://web_host:web_port/reload/` 接口来热重载配置
-
-
-## 监控报警
-
-- dashboard 和 prometheus 规则可以从`monitor`文件夹下找到,可以自行导入
-
-- 类似 Smoking Ping 的延迟监控
-
-
-
-- 流量监控
-
-
-
-## Benchmark(Apple m1)
-
-iperf:
-
-```sh
-# run iperf server on 5201
-iperf3 -s
-
-# 直接转发
-# run relay server listen 1234 to 9001 (raw)
-go run cmd/ehco/main.go -l 0.0.0.0:1234 -r 0.0.0.0:5201
-
-# 直接转发END
-
-# 通过ws隧道转发
-# listen 1235 relay over ws to 1236
-go run cmd/ehco/main.go -l 0.0.0.0:1235 -r ws://0.0.0.0:1236 -tt ws
-
-# listen 1236 through ws relay to 5201
-go run cmd/ehco/main.go -l 0.0.0.0:1236 -lt ws -r 0.0.0.0:5201
-# 通过ws隧道转发END
-
-# 通过wss隧道转发
-# listen 1234 relay over wss to 1236
-go run cmd/ehco/main.go -l 0.0.0.0:1235 -r wss://0.0.0.0:1236 -tt wss
-
-# listen 1236 through wss relay to 5201
-go run cmd/ehco/main.go -l 0.0.0.0:1236 -lt wss -r 0.0.0.0:5201
-# 通过wss隧道转发END
-
-# 通过mwss隧道转发 和wss相比 速度会慢,但是能减少延迟
-# listen 1237 relay over mwss to 1238
-go run cmd/ehco/main.go -l 0.0.0.0:1237 -r wss://0.0.0.0:1238 -tt mwss
-
-# listen 1238 through mwss relay to 5201
-go run cmd/ehco/main.go -l 0.0.0.0:1238 -lt mwss -r 0.0.0.0:5201
-# 通过mwss隧道转发END
-
-# run through file
-go run cmd/ehco/main.go -c config.json
-
-# benchmark tcp
-iperf3 -c 0.0.0.0 -p 1234
-
-# benchmark tcp through wss
-iperf3 -c 0.0.0.0 -p 1235
-
-# benchmark upd
-iperf3 -c 0.0.0.0 -p 1234 -u -b 1G --length 1024
-```
-
-```
-| iperf | raw | relay(raw) | relay(ws) | relay(wss) | relay(mwss) | relay(mtcp) |
-| ----- | -------------- | ------------- | ------------ | ------------ | -------------- | -------------- |
-| tcp | 123 Gbits/sec | 55 Gbits/sec | 41 Gbits/sec | 10 Gbits/sec | 5.78 Gbits/sec | 22.2 Gbits/sec |
-| udp | 14.5 Gbits/sec | 3.3 Gbits/sec | 直接转发 | 直接转发 | 直接转发 | 直接转发 |
-
-```
+- [更多功能请探索文档](https://docs.ehco-relay.cc/)
diff --git a/echo/internal/cli/app.go b/echo/internal/cli/app.go
index 7d83cdbbd6..88fd998a33 100644
--- a/echo/internal/cli/app.go
+++ b/echo/internal/cli/app.go
@@ -10,7 +10,7 @@ import (
cli "github.com/urfave/cli/v2"
)
-var cliLogger = log.MustNewLogger("info").Sugar().Named("cli-app")
+var cliLogger = log.MustNewLogger("info").Sugar().Named("cli")
func startAction(ctx *cli.Context) error {
cfg, err := InitConfigAndComponents()
diff --git a/echo/internal/cli/config.go b/echo/internal/cli/config.go
index 0822271454..46412ccfcf 100644
--- a/echo/internal/cli/config.go
+++ b/echo/internal/cli/config.go
@@ -49,10 +49,10 @@ func loadConfig() (cfg *config.Config, err error) {
}
}
- // init tls
+ // init tls when need
for _, cfg := range cfg.RelayConfigs {
- if cfg.ListenType == constant.Listen_WSS || cfg.ListenType == constant.Listen_MWSS ||
- cfg.TransportType == constant.Transport_WSS || cfg.TransportType == constant.Transport_MWSS {
+ if cfg.ListenType == constant.RelayTypeWSS || cfg.ListenType == constant.RelayTypeMWSS ||
+ cfg.TransportType == constant.RelayTypeWSS || cfg.TransportType == constant.RelayTypeMWSS {
if err := tls.InitTlsCfg(); err != nil {
return nil, err
}
diff --git a/echo/internal/constant/constant.go b/echo/internal/constant/constant.go
index b9ede39ada..a4c815b2ba 100644
--- a/echo/internal/constant/constant.go
+++ b/echo/internal/constant/constant.go
@@ -20,19 +20,16 @@ const (
SmuxMaxAliveDuration = 10 * time.Minute
SmuxMaxStreamCnt = 5
- Listen_RAW = "raw"
- Listen_WS = "ws"
- Listen_WSS = "wss"
- Listen_MWSS = "mwss"
- Listen_MTCP = "mtcp"
-
- Transport_RAW = "raw"
- Transport_WS = "ws"
- Transport_WSS = "wss"
- Transport_MWSS = "mwss"
- Transport_MTCP = "mtcp"
-
// todo add udp buffer size
BUFFER_POOL_SIZE = 1024 // support 512 connections
BUFFER_SIZE = 20 * 1024 // 20KB the maximum packet size of shadowsocks is about 16 KiB
)
+
+// relay type
+const (
+ RelayTypeRaw = "raw"
+ RelayTypeWS = "ws"
+ RelayTypeWSS = "wss"
+ RelayTypeMWSS = "mwss"
+ RelayTypeMTCP = "mtcp"
+)
diff --git a/echo/internal/relay/conf/cfg.go b/echo/internal/relay/conf/cfg.go
index d9ad952db1..7b53b83cbf 100644
--- a/echo/internal/relay/conf/cfg.go
+++ b/echo/internal/relay/conf/cfg.go
@@ -5,6 +5,8 @@ import (
"fmt"
"github.com/Ehco1996/ehco/internal/constant"
+
+ "github.com/Ehco1996/ehco/pkg/lb"
"go.uber.org/zap"
)
@@ -22,19 +24,19 @@ func (r *Config) Validate() error {
if r.Adjust() != nil {
return errors.New("adjust config failed")
}
- if r.ListenType != constant.Listen_RAW &&
- r.ListenType != constant.Listen_WS &&
- r.ListenType != constant.Listen_WSS &&
- r.ListenType != constant.Listen_MTCP &&
- r.ListenType != constant.Listen_MWSS {
+ if r.ListenType != constant.RelayTypeRaw &&
+ r.ListenType != constant.RelayTypeWS &&
+ r.ListenType != constant.RelayTypeWSS &&
+ r.ListenType != constant.RelayTypeMTCP &&
+ r.ListenType != constant.RelayTypeMWSS {
return fmt.Errorf("invalid listen type:%s", r.ListenType)
}
- if r.TransportType != constant.Transport_RAW &&
- r.TransportType != constant.Transport_WS &&
- r.TransportType != constant.Transport_WSS &&
- r.TransportType != constant.Transport_MTCP &&
- r.TransportType != constant.Transport_MWSS {
+ if r.TransportType != constant.RelayTypeRaw &&
+ r.TransportType != constant.RelayTypeWS &&
+ r.TransportType != constant.RelayTypeWSS &&
+ r.TransportType != constant.RelayTypeMTCP &&
+ r.TransportType != constant.RelayTypeMWSS {
return fmt.Errorf("invalid transport type:%s", r.ListenType)
}
@@ -106,16 +108,31 @@ func (r *Config) Different(new *Config) bool {
}
// todo make this shorter and more readable
-func (r *Config) defaultLabel() string {
- defaultLabel := fmt.Sprintf("",
- r.Listen, r.ListenType, r.TCPRemotes, r.UDPRemotes, r.TransportType)
+func (r *Config) DefaultLabel() string {
+ defaultLabel := fmt.Sprintf("",
+ r.Listen, r.TCPRemotes, r.TransportType)
return defaultLabel
}
func (r *Config) Adjust() error {
if r.Label == "" {
- r.Label = r.defaultLabel()
+ r.Label = r.DefaultLabel()
zap.S().Debugf("label is empty, set default label:%s", r.Label)
}
return nil
}
+
+func (r *Config) ToTCPRemotes() lb.RoundRobin {
+ tcpNodeList := make([]*lb.Node, len(r.TCPRemotes))
+ for idx, addr := range r.TCPRemotes {
+ tcpNodeList[idx] = &lb.Node{
+ Address: addr,
+ Label: fmt.Sprintf("%s-%s", r.Label, addr),
+ }
+ }
+ return lb.NewRoundRobin(tcpNodeList)
+}
+
+func (r *Config) GetLoggerName() string {
+ return fmt.Sprintf("%s(%s<->%s)", r.Label, r.ListenType, r.TransportType)
+}
diff --git a/echo/internal/relay/relay.go b/echo/internal/relay/relay.go
index a832f4cf19..0964b66eba 100644
--- a/echo/internal/relay/relay.go
+++ b/echo/internal/relay/relay.go
@@ -1,138 +1,50 @@
package relay
import (
- "net"
-
"go.uber.org/zap"
"github.com/Ehco1996/ehco/internal/cmgr"
- "github.com/Ehco1996/ehco/internal/constant"
"github.com/Ehco1996/ehco/internal/relay/conf"
"github.com/Ehco1996/ehco/internal/transporter"
)
type Relay struct {
- Name string // unique name for all relay
- TransportType string
- ListenType string
-
- TP transporter.RelayTransporter
-
- LocalTCPAddr *net.TCPAddr
- closeTcpF func() error
-
cfg *conf.Config
l *zap.SugaredLogger
+
+ relayServer transporter.RelayServer
+}
+
+func (r *Relay) UniqueID() string {
+ return r.cfg.Label
}
func NewRelay(cfg *conf.Config, connMgr cmgr.Cmgr) (*Relay, error) {
- localTCPAddr, err := net.ResolveTCPAddr("tcp", cfg.Listen)
+ base := transporter.NewBaseTransporter(cfg, connMgr)
+ s, err := transporter.NewRelayServer(cfg.ListenType, base)
if err != nil {
return nil, err
}
-
r := &Relay{
- cfg: cfg,
- l: zap.S().Named("relay"),
-
- Name: cfg.Label,
- LocalTCPAddr: localTCPAddr,
- ListenType: cfg.ListenType,
- TransportType: cfg.TransportType,
- TP: transporter.NewRelayTransporter(cfg, connMgr),
+ relayServer: s,
+ cfg: cfg,
+ l: zap.S().Named("relay"),
}
-
return r, nil
}
func (r *Relay) ListenAndServe() error {
errCh := make(chan error)
-
- if len(r.cfg.TCPRemotes) > 0 {
- switch r.ListenType {
- case constant.Listen_RAW:
- go func() {
- errCh <- r.RunLocalTCPServer()
- }()
- case constant.Listen_MTCP:
- go func() {
- errCh <- r.RunLocalMTCPServer()
- }()
- case constant.Listen_WS:
- go func() {
- errCh <- r.RunLocalWSServer()
- }()
- case constant.Listen_WSS:
- go func() {
- errCh <- r.RunLocalWSSServer()
- }()
- case constant.Listen_MWSS:
- go func() {
- errCh <- r.RunLocalMWSSServer()
- }()
- }
- }
+ go func() {
+ r.l.Infof("Start TCP Relay Server:%s", r.cfg.DefaultLabel())
+ errCh <- r.relayServer.ListenAndServe()
+ }()
return <-errCh
}
func (r *Relay) Close() {
- r.l.Infof("Close relay label: %s", r.Name)
- if r.closeTcpF != nil {
- err := r.closeTcpF()
- if err != nil {
- r.l.Errorf(err.Error())
- }
+ r.l.Infof("Close TCP Relay Server:%s", r.cfg.DefaultLabel())
+ if err := r.relayServer.Close(); err != nil {
+ r.l.Errorf(err.Error())
}
}
-
-func (r *Relay) RunLocalTCPServer() error {
- rawServer, err := transporter.NewRawServer(r.LocalTCPAddr.String(), r.TP)
- if err != nil {
- return err
- }
- r.closeTcpF = func() error {
- return rawServer.Close()
- }
- r.l.Infof("Start TCP relay Server: %s", r.Name)
- return rawServer.ListenAndServe()
-}
-
-func (r *Relay) RunLocalMTCPServer() error {
- tp := r.TP.(*transporter.RawClient)
- mTCPServer := transporter.NewMTCPServer(r.LocalTCPAddr.String(), tp, r.l.Named("MTCPServer"))
- r.closeTcpF = func() error {
- return mTCPServer.Close()
- }
- r.l.Infof("Start MTCP relay Server: %s", r.Name)
- return mTCPServer.ListenAndServe()
-}
-
-func (r *Relay) RunLocalWSServer() error {
- tp := r.TP.(*transporter.RawClient)
- wsServer := transporter.NewWSServer(r.LocalTCPAddr.String(), tp, r.l.Named("WSServer"))
- r.closeTcpF = func() error {
- return wsServer.Close()
- }
- r.l.Infof("Start WS relay Server: %s", r.Name)
- return wsServer.ListenAndServe()
-}
-
-func (r *Relay) RunLocalWSSServer() error {
- tp := r.TP.(*transporter.RawClient)
- wssServer := transporter.NewWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("WSSServer"))
- r.closeTcpF = func() error {
- return wssServer.Close()
- }
- r.l.Infof("Start WSS relay Server: %s", r.Name)
- return wssServer.ListenAndServe()
-}
-
-func (r *Relay) RunLocalMWSSServer() error {
- tp := r.TP.(*transporter.RawClient)
- mwssServer := transporter.NewMWSSServer(r.LocalTCPAddr.String(), tp, r.l.Named("MWSSServer"))
- r.closeTcpF = func() error {
- return mwssServer.Close()
- }
- r.l.Infof("Start MWSS relay Server: %s", r.Name)
- return mwssServer.ListenAndServe()
-}
diff --git a/echo/internal/relay/server.go b/echo/internal/relay/server.go
index c00ce99875..9ce52eca98 100644
--- a/echo/internal/relay/server.go
+++ b/echo/internal/relay/server.go
@@ -46,18 +46,18 @@ func NewServer(cfg *config.Config) (*Server, error) {
}
func (s *Server) startOneRelay(r *Relay) {
- s.relayM.Store(r.Name, r)
+ s.relayM.Store(r.UniqueID(), r)
// mute closed network error for tcp server and mute http.ErrServerClosed for http server when config reload
if err := r.ListenAndServe(); err != nil &&
!errors.Is(err, net.ErrClosed) && !errors.Is(err, http.ErrServerClosed) {
- s.l.Errorf("start relay %s meet error: %s", r.Name, err)
+ s.l.Errorf("start relay %s meet error: %s", r.UniqueID(), err)
s.errCH <- err
}
}
func (s *Server) stopOneRelay(r *Relay) {
r.Close()
- s.relayM.Delete(r.Name)
+ s.relayM.Delete(r.UniqueID())
}
func (s *Server) Start(ctx context.Context) error {
diff --git a/echo/internal/transporter/base.go b/echo/internal/transporter/base.go
new file mode 100644
index 0000000000..6751279894
--- /dev/null
+++ b/echo/internal/transporter/base.go
@@ -0,0 +1,55 @@
+package transporter
+
+import (
+ "net"
+
+ "github.com/Ehco1996/ehco/internal/cmgr"
+ "github.com/Ehco1996/ehco/internal/conn"
+ "github.com/Ehco1996/ehco/internal/metrics"
+ "github.com/Ehco1996/ehco/internal/relay/conf"
+
+ "github.com/Ehco1996/ehco/pkg/lb"
+ "go.uber.org/zap"
+)
+
+type baseTransporter struct {
+ cmgr cmgr.Cmgr
+ cfg *conf.Config
+ tCPRemotes lb.RoundRobin
+ l *zap.SugaredLogger
+}
+
+func NewBaseTransporter(cfg *conf.Config, cmgr cmgr.Cmgr) *baseTransporter {
+ return &baseTransporter{
+ cfg: cfg,
+ cmgr: cmgr,
+ tCPRemotes: cfg.ToTCPRemotes(),
+ l: zap.S().Named(cfg.GetLoggerName()),
+ }
+}
+
+func (b *baseTransporter) GetTCPListenAddr() (*net.TCPAddr, error) {
+ return net.ResolveTCPAddr("tcp", b.cfg.Listen)
+}
+
+func (b *baseTransporter) GetRemote() *lb.Node {
+ return b.tCPRemotes.Next()
+}
+
+func (b *baseTransporter) RelayTCPConn(c net.Conn, handshakeF TCPHandShakeF) error {
+ remote := b.GetRemote()
+ metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
+ defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
+
+ clonedRemote := remote.Clone()
+ rc, err := handshakeF(clonedRemote)
+ if err != nil {
+ return err
+ }
+ b.l.Infof("RelayTCPConn from %s to %s", c.LocalAddr(), remote.Address)
+ relayConn := conn.NewRelayConn(
+ b.cfg.Label, c, rc, conn.WithHandshakeDuration(clonedRemote.HandShakeDuration))
+ b.cmgr.AddConnection(relayConn)
+ defer b.cmgr.RemoveConnection(relayConn)
+ return relayConn.Transport(remote.Label)
+}
diff --git a/echo/internal/transporter/interface.go b/echo/internal/transporter/interface.go
index e0fd5f430b..da40fe537c 100644
--- a/echo/internal/transporter/interface.go
+++ b/echo/internal/transporter/interface.go
@@ -1,42 +1,54 @@
package transporter
import (
- "fmt"
"net"
- "github.com/Ehco1996/ehco/internal/cmgr"
"github.com/Ehco1996/ehco/internal/constant"
- "github.com/Ehco1996/ehco/internal/relay/conf"
"github.com/Ehco1996/ehco/pkg/lb"
)
-// RelayTransporter
-type RelayTransporter interface {
- dialRemote(remote *lb.Node) (net.Conn, error)
- HandleTCPConn(c net.Conn, remote *lb.Node) error
- GetRemote() *lb.Node
+type TCPHandShakeF func(remote *lb.Node) (net.Conn, error)
+
+type RelayClient interface {
+ TCPHandShake(remote *lb.Node) (net.Conn, error)
+ RelayTCPConn(c net.Conn, handshakeF TCPHandShakeF) error
}
-func NewRelayTransporter(cfg *conf.Config, connMgr cmgr.Cmgr) RelayTransporter {
- tcpNodeList := make([]*lb.Node, len(cfg.TCPRemotes))
- for idx, addr := range cfg.TCPRemotes {
- tcpNodeList[idx] = &lb.Node{
- Address: addr,
- Label: fmt.Sprintf("%s-%s", cfg.Label, addr),
- }
+func NewRelayClient(relayType string, base *baseTransporter) (RelayClient, error) {
+ switch relayType {
+ case constant.RelayTypeRaw:
+ return newRawClient(base)
+ case constant.RelayTypeWS:
+ return newWsClient(base)
+ case constant.RelayTypeWSS:
+ return newWssClient(base)
+ case constant.RelayTypeMWSS:
+ return newMwssClient(base)
+ case constant.RelayTypeMTCP:
+ return newMtcpClient(base)
+ default:
+ panic("unsupported transport type")
+ }
+}
+
+type RelayServer interface {
+ ListenAndServe() error
+ Close() error
+}
+
+func NewRelayServer(relayType string, base *baseTransporter) (RelayServer, error) {
+ switch relayType {
+ case constant.RelayTypeRaw:
+ return newRawServer(base)
+ case constant.RelayTypeWS:
+ return newWsServer(base)
+ case constant.RelayTypeWSS:
+ return newWssServer(base)
+ case constant.RelayTypeMWSS:
+ return newMwssServer(base)
+ case constant.RelayTypeMTCP:
+ return newMtcpServer(base)
+ default:
+ panic("unsupported transport type")
}
- raw := newRawClient(cfg.Label, lb.NewRoundRobin(tcpNodeList), connMgr)
- switch cfg.TransportType {
- case constant.Transport_RAW:
- return raw
- case constant.Transport_WS:
- return newWsClient(raw)
- case constant.Transport_WSS:
- return newWSSClient(raw)
- case constant.Transport_MWSS:
- return newMWSSClient(raw)
- case constant.Transport_MTCP:
- return newMTCPClient(raw)
- }
- return nil
}
diff --git a/echo/internal/transporter/mux.go b/echo/internal/transporter/mux.go
index ae82212532..5bc9d3d586 100644
--- a/echo/internal/transporter/mux.go
+++ b/echo/internal/transporter/mux.go
@@ -136,3 +136,66 @@ func (tr *smuxTransporter) Dial(ctx context.Context, addr string) (conn net.Conn
curSM.streamList = append(curSM.streamList, stream)
return stream, nil
}
+
+type muxServer interface {
+ ListenAndServe() error
+ Accept() (net.Conn, error)
+ Close() error
+ mux(net.Conn)
+}
+
+func newMuxServer(listenAddr string, l *zap.SugaredLogger) *muxServerImpl {
+ return &muxServerImpl{
+ errChan: make(chan error, 1),
+ connChan: make(chan net.Conn, 1024),
+ listenAddr: listenAddr,
+ l: l,
+ }
+}
+
+type muxServerImpl struct {
+ errChan chan error
+ connChan chan net.Conn
+
+ listenAddr string
+ l *zap.SugaredLogger
+}
+
+func (s *muxServerImpl) Accept() (net.Conn, error) {
+ select {
+ case conn := <-s.connChan:
+ return conn, nil
+ case err := <-s.errChan:
+ return nil, err
+ }
+}
+
+func (s *muxServerImpl) mux(conn net.Conn) {
+ defer conn.Close()
+
+ cfg := smux.DefaultConfig()
+ cfg.KeepAliveDisabled = true
+ session, err := smux.Server(conn, cfg)
+ if err != nil {
+ s.l.Debugf("server err %s - %s : %s", conn.RemoteAddr(), s.listenAddr, err)
+ return
+ }
+ defer session.Close() // nolint: errcheck
+
+ s.l.Debugf("session init %s %s", conn.RemoteAddr(), s.listenAddr)
+ defer s.l.Debugf("session close %s >-< %s", conn.RemoteAddr(), s.listenAddr)
+
+ for {
+ stream, err := session.AcceptStream()
+ if err != nil {
+ s.l.Errorf("accept stream err: %s", err)
+ break
+ }
+ select {
+ case s.connChan <- stream:
+ default:
+ stream.Close() // nolint: errcheck
+ s.l.Infof("%s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
+ }
+ }
+}
diff --git a/echo/internal/transporter/raw.go b/echo/internal/transporter/raw.go
index d9954780bd..c52df4651d 100644
--- a/echo/internal/transporter/raw.go
+++ b/echo/internal/transporter/raw.go
@@ -5,40 +5,33 @@ import (
"net"
"time"
- "go.uber.org/zap"
-
- "github.com/Ehco1996/ehco/internal/cmgr"
- "github.com/Ehco1996/ehco/internal/conn"
"github.com/Ehco1996/ehco/internal/constant"
"github.com/Ehco1996/ehco/internal/metrics"
"github.com/Ehco1996/ehco/pkg/lb"
)
+var (
+ _ RelayClient = &RawClient{}
+ _ RelayServer = &RawServer{}
+)
+
type RawClient struct {
- relayLabel string
- cmgr cmgr.Cmgr
- tCPRemotes lb.RoundRobin
- l *zap.SugaredLogger
+ *baseTransporter
+
+ dialer *net.Dialer
}
-func newRawClient(relayLabel string, tcpRemotes lb.RoundRobin, cmgr cmgr.Cmgr) *RawClient {
+func newRawClient(base *baseTransporter) (*RawClient, error) {
r := &RawClient{
- cmgr: cmgr,
- relayLabel: relayLabel,
- tCPRemotes: tcpRemotes,
- l: zap.S().Named(relayLabel),
+ baseTransporter: base,
+ dialer: &net.Dialer{Timeout: constant.DialTimeOut},
}
- return r
+ return r, nil
}
-func (raw *RawClient) GetRemote() *lb.Node {
- return raw.tCPRemotes.Next()
-}
-
-func (raw *RawClient) dialRemote(remote *lb.Node) (net.Conn, error) {
+func (raw *RawClient) TCPHandShake(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
- d := net.Dialer{Timeout: constant.DialTimeOut}
- rc, err := d.Dial("tcp", remote.Address)
+ rc, err := raw.dialer.Dial("tcp", remote.Address)
if err != nil {
return nil, err
}
@@ -48,38 +41,32 @@ func (raw *RawClient) dialRemote(remote *lb.Node) (net.Conn, error) {
return rc, nil
}
-func (raw *RawClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
- metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
- defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
-
- clonedRemote := remote.Clone()
- rc, err := raw.dialRemote(clonedRemote)
- if err != nil {
- return err
- }
- raw.l.Infof("HandleTCPConn from %s to %s", c.LocalAddr(), remote.Address)
- relayConn := conn.NewRelayConn(raw.relayLabel, c, rc, conn.WithHandshakeDuration(clonedRemote.HandShakeDuration))
- raw.cmgr.AddConnection(relayConn)
- defer raw.cmgr.RemoveConnection(relayConn)
- return relayConn.Transport(remote.Label)
-}
-
type RawServer struct {
- rtp RelayTransporter
- lis *net.TCPListener
- l *zap.SugaredLogger
+ *baseTransporter
+ localTCPAddr *net.TCPAddr
+ lis *net.TCPListener
+ relayer RelayClient
}
-func NewRawServer(addr string, rtp RelayTransporter) (*RawServer, error) {
- tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
+func newRawServer(base *baseTransporter) (*RawServer, error) {
+ addr, err := base.GetTCPListenAddr()
if err != nil {
return nil, err
}
- lis, err := net.ListenTCP("tcp", tcpAddr)
+ lis, err := net.ListenTCP("tcp", addr)
if err != nil {
return nil, err
}
- return &RawServer{lis: lis, rtp: rtp}, nil
+ relayer, err := NewRelayClient(base.cfg.TransportType, base)
+ if err != nil {
+ return nil, err
+ }
+ return &RawServer{
+ lis: lis,
+ baseTransporter: base,
+ localTCPAddr: addr,
+ relayer: relayer,
+ }, nil
}
func (s *RawServer) Close() error {
@@ -93,13 +80,8 @@ func (s *RawServer) ListenAndServe() error {
return err
}
go func(c net.Conn) {
- remote := s.rtp.GetRemote()
- metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
- defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
- if err := s.rtp.HandleTCPConn(c, remote); err != nil {
- s.l.Errorf("HandleTCPConn meet error tp:%s from:%s to:%s err:%s",
- s.rtp,
- c.RemoteAddr(), remote.Address, err)
+ if err := s.RelayTCPConn(c, s.relayer.TCPHandShake); err != nil {
+ s.l.Errorf("RelayTCPConn error: %s", err.Error())
}
}(c)
}
diff --git a/echo/internal/transporter/raw_mux.go b/echo/internal/transporter/raw_mux.go
index ef1669d5cd..7e52861cb8 100644
--- a/echo/internal/transporter/raw_mux.go
+++ b/echo/internal/transporter/raw_mux.go
@@ -1,4 +1,3 @@
-// nolint: errcheck
package transporter
import (
@@ -7,29 +6,32 @@ import (
"time"
"github.com/xtaci/smux"
- "go.uber.org/zap"
- "github.com/Ehco1996/ehco/internal/conn"
- "github.com/Ehco1996/ehco/internal/constant"
"github.com/Ehco1996/ehco/internal/metrics"
"github.com/Ehco1996/ehco/pkg/lb"
)
-type MTCPClient struct {
+var (
+ _ RelayClient = &MtcpClient{}
+ _ RelayServer = &MtcpServer{}
+)
+
+type MtcpClient struct {
*RawClient
- dialer *net.Dialer
- mtp *smuxTransporter
+ muxTP *smuxTransporter
}
-func newMTCPClient(raw *RawClient) *MTCPClient {
- dialer := &net.Dialer{Timeout: constant.DialTimeOut}
- c := &MTCPClient{dialer: dialer, RawClient: raw}
- mtp := NewSmuxTransporter(raw.l.Named("mtcp"), c.initNewSession)
- c.mtp = mtp
- return c
+func newMtcpClient(base *baseTransporter) (*MtcpClient, error) {
+ raw, err := newRawClient(base)
+ if err != nil {
+ return nil, err
+ }
+ c := &MtcpClient{RawClient: raw}
+ c.muxTP = NewSmuxTransporter(raw.l.Named("mtcp"), c.initNewSession)
+ return c, nil
}
-func (c *MTCPClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) {
+func (c *MtcpClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) {
rc, err := c.dialer.Dial("tcp", addr)
if err != nil {
return nil, err
@@ -45,9 +47,9 @@ func (c *MTCPClient) initNewSession(ctx context.Context, addr string) (*smux.Ses
return session, nil
}
-func (s *MTCPClient) dialRemote(remote *lb.Node) (net.Conn, error) {
+func (s *MtcpClient) TCPHandShake(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
- mtcpc, err := s.mtp.Dial(context.TODO(), remote.Address)
+ mtcpc, err := s.muxTP.Dial(context.TODO(), remote.Address)
if err != nil {
return nil, err
}
@@ -57,87 +59,28 @@ func (s *MTCPClient) dialRemote(remote *lb.Node) (net.Conn, error) {
return mtcpc, nil
}
-func (s *MTCPClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
- clonedRemote := remote.Clone()
- mtcpc, err := s.dialRemote(clonedRemote)
+type MtcpServer struct {
+ *RawServer
+ *muxServerImpl
+}
+
+func newMtcpServer(base *baseTransporter) (*MtcpServer, error) {
+ raw, err := newRawServer(base)
if err != nil {
- return err
+ return nil, err
}
- s.l.Infof("HandleTCPConn from:%s to:%s", c.LocalAddr(), remote.Address)
- relayConn := conn.NewRelayConn(s.relayLabel, c, mtcpc, conn.WithHandshakeDuration(clonedRemote.HandShakeDuration))
- s.cmgr.AddConnection(relayConn)
- defer s.cmgr.RemoveConnection(relayConn)
- return relayConn.Transport(remote.Label)
+ s := &MtcpServer{
+ RawServer: raw,
+ muxServerImpl: newMuxServer(base.cfg.Listen, base.l.Named("mtcp")),
+ }
+
+ return s, nil
}
-type MTCPServer struct {
- raw *RawClient
- listenAddr string
- listener net.Listener
- l *zap.SugaredLogger
-
- errChan chan error
- connChan chan net.Conn
-}
-
-func NewMTCPServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *MTCPServer {
- return &MTCPServer{
- l: l,
- raw: raw,
- listenAddr: listenAddr,
- errChan: make(chan error, 1),
- connChan: make(chan net.Conn, 1024),
- }
-}
-
-func (s *MTCPServer) mux(conn net.Conn) {
- defer conn.Close()
-
- cfg := smux.DefaultConfig()
- cfg.KeepAliveDisabled = true
- session, err := smux.Server(conn, cfg)
- if err != nil {
- s.l.Debugf("server err %s - %s : %s", conn.RemoteAddr(), s.listenAddr, err)
- return
- }
- defer session.Close()
-
- s.l.Debugf("session init %s %s", conn.RemoteAddr(), s.listenAddr)
- defer s.l.Debugf("session close %s >-< %s", conn.RemoteAddr(), s.listenAddr)
-
- for {
- stream, err := session.AcceptStream()
- if err != nil {
- s.l.Errorf("accept stream err: %s", err)
- break
- }
- select {
- case s.connChan <- stream:
- default:
- stream.Close()
- s.l.Infof("%s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
- }
- }
-}
-
-func (s *MTCPServer) Accept() (conn net.Conn, err error) {
- select {
- case conn = <-s.connChan:
- case err = <-s.errChan:
- }
- return
-}
-
-func (s *MTCPServer) ListenAndServe() error {
- lis, err := net.Listen("tcp", s.listenAddr)
- if err != nil {
- return err
- }
- s.listener = lis
-
+func (s *MtcpServer) ListenAndServe() error {
go func() {
for {
- c, err := lis.Accept()
+ c, err := s.lis.Accept()
if err != nil {
s.errChan <- err
continue
@@ -152,14 +95,13 @@ func (s *MTCPServer) ListenAndServe() error {
return e
}
go func(c net.Conn) {
- remote := s.raw.GetRemote()
- if err := s.raw.HandleTCPConn(c, remote); err != nil {
- s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", c.RemoteAddr(), remote.Address, err)
+ if err := s.RelayTCPConn(c, s.relayer.TCPHandShake); err != nil {
+ s.l.Errorf("RelayTCPConn error: %s", err.Error())
}
}(conn)
}
}
-func (s *MTCPServer) Close() error {
- return s.listener.Close()
+func (s *MtcpServer) Close() error {
+ return s.lis.Close()
}
diff --git a/echo/internal/transporter/ws.go b/echo/internal/transporter/ws.go
index 0b4608ed84..402b11850c 100644
--- a/echo/internal/transporter/ws.go
+++ b/echo/internal/transporter/ws.go
@@ -8,27 +8,35 @@ import (
"github.com/gobwas/ws"
"github.com/labstack/echo/v4"
- "go.uber.org/zap"
- "github.com/Ehco1996/ehco/internal/conn"
"github.com/Ehco1996/ehco/internal/constant"
"github.com/Ehco1996/ehco/internal/metrics"
"github.com/Ehco1996/ehco/internal/web"
"github.com/Ehco1996/ehco/pkg/lb"
)
+var (
+ _ RelayClient = &WsClient{}
+ _ RelayServer = &WsServer{}
+)
+
type WsClient struct {
- *RawClient
+ *baseTransporter
+
+ dialer *ws.Dialer
}
-func newWsClient(raw *RawClient) *WsClient {
- return &WsClient{RawClient: raw}
+func newWsClient(base *baseTransporter) (*WsClient, error) {
+ s := &WsClient{
+ baseTransporter: base,
+ dialer: &ws.Dialer{Timeout: constant.DialTimeOut},
+ }
+ return s, nil
}
-func (s *WsClient) dialRemote(remote *lb.Node) (net.Conn, error) {
+func (s *WsClient) TCPHandShake(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
- d := ws.Dialer{Timeout: constant.DialTimeOut}
- wsc, _, _, err := d.Dial(context.TODO(), remote.Address+"/handshake/")
+ wsc, _, _, err := s.dialer.Dial(context.TODO(), remote.Address+"/handshake/")
if err != nil {
return nil, err
}
@@ -38,57 +46,51 @@ func (s *WsClient) dialRemote(remote *lb.Node) (net.Conn, error) {
return wsc, nil
}
-func (s *WsClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
- clonedRemote := remote.Clone()
- wsc, err := s.dialRemote(clonedRemote)
- if err != nil {
- return err
- }
- s.l.Infof("HandleTCPConn from %s to %s", c.LocalAddr(), remote.Address)
- relayConn := conn.NewRelayConn(
- s.relayLabel, c, wsc,
- conn.WithHandshakeDuration(clonedRemote.HandShakeDuration))
- s.cmgr.AddConnection(relayConn)
- defer s.cmgr.RemoveConnection(relayConn)
- return relayConn.Transport(remote.Label)
-}
+type WsServer struct {
+ *baseTransporter
-type WSServer struct {
- raw *RawClient
e *echo.Echo
httpServer *http.Server
- l *zap.SugaredLogger
+ relayer RelayClient
}
-func NewWSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *WSServer {
- s := &WSServer{
- l: l,
- raw: raw,
- httpServer: &http.Server{Addr: listenAddr, ReadHeaderTimeout: 30 * time.Second},
+func newWsServer(base *baseTransporter) (*WsServer, error) {
+ localTCPAddr, err := base.GetTCPListenAddr()
+ if err != nil {
+ return nil, err
+ }
+ s := &WsServer{
+ baseTransporter: base,
+ httpServer: &http.Server{
+ Addr: localTCPAddr.String(), ReadHeaderTimeout: 30 * time.Second,
+ },
}
e := web.NewEchoServer()
e.GET("/", echo.WrapHandler(web.MakeIndexF()))
e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest)))
s.e = e
- s.httpServer.Handler = e
- return s
+ relayer, err := NewRelayClient(base.cfg.TransportType, base)
+ if err != nil {
+ return nil, err
+ }
+ s.relayer = relayer
+ return s, nil
}
-func (s *WSServer) ListenAndServe() error {
+func (s *WsServer) ListenAndServe() error {
return s.e.StartServer(s.httpServer)
}
-func (s *WSServer) Close() error {
+func (s *WsServer) Close() error {
return s.e.Close()
}
-func (s *WSServer) HandleRequest(w http.ResponseWriter, req *http.Request) {
+func (s *WsServer) HandleRequest(w http.ResponseWriter, req *http.Request) {
wsc, _, _, err := ws.UpgradeHTTP(req, w)
if err != nil {
return
}
- remote := s.raw.GetRemote()
- if err := s.raw.HandleTCPConn(wsc, remote); err != nil {
- s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", wsc.RemoteAddr(), remote.Address, err)
+ if err := s.RelayTCPConn(wsc, s.relayer.TCPHandShake); err != nil {
+ s.l.Errorf("RelayTCPConn error: %s", err.Error())
}
}
diff --git a/echo/internal/transporter/wss.go b/echo/internal/transporter/wss.go
index a8915ae93c..19c5eb9610 100644
--- a/echo/internal/transporter/wss.go
+++ b/echo/internal/transporter/wss.go
@@ -1,64 +1,38 @@
-// nolint: errcheck
package transporter
import (
- "context"
- "net"
- "time"
-
- "github.com/gobwas/ws"
- "go.uber.org/zap"
-
- "github.com/Ehco1996/ehco/internal/conn"
- "github.com/Ehco1996/ehco/internal/metrics"
mytls "github.com/Ehco1996/ehco/internal/tls"
- "github.com/Ehco1996/ehco/pkg/lb"
)
-type WSSClient struct {
- WsClient
+var (
+ _ RelayClient = &WssClient{}
+ _ RelayServer = &WssServer{}
+)
+
+type WssClient struct {
+ *WsClient
}
-func newWSSClient(raw *RawClient) *WSSClient {
- return &WSSClient{*newWsClient(raw)}
-}
-
-func (s *WSSClient) dialRemote(remote *lb.Node) (net.Conn, error) {
- t1 := time.Now()
- d := ws.Dialer{TLSConfig: mytls.DefaultTLSConfig}
- wssc, _, _, err := d.Dial(context.TODO(), remote.Address+"/handshake/")
+func newWssClient(base *baseTransporter) (*WssClient, error) {
+ wc, err := newWsClient(base)
if err != nil {
- println("wss called", err.Error())
return nil, err
}
- latency := time.Since(t1)
- metrics.HandShakeDuration.WithLabelValues(remote.Label).Observe(float64(latency.Milliseconds()))
- remote.HandShakeDuration = latency
- return wssc, nil
+ // insert tls config
+ wc.dialer.TLSConfig = mytls.DefaultTLSConfig
+ return &WssClient{WsClient: wc}, nil
}
-func (s *WSSClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
- clonedRemote := remote.Clone()
- wssc, err := s.dialRemote(clonedRemote)
+type WssServer struct {
+ *WsServer
+}
+
+func newWssServer(base *baseTransporter) (*WssServer, error) {
+ wsServer, err := newWsServer(base)
if err != nil {
- return err
+ return nil, err
}
- s.l.Infof("HandleTCPConn from %s to %s", c.RemoteAddr(), remote.Address)
-
- relayConn := conn.NewRelayConn(s.relayLabel, c, wssc, conn.WithHandshakeDuration(clonedRemote.HandShakeDuration))
- s.cmgr.AddConnection(relayConn)
- defer s.cmgr.RemoveConnection(relayConn)
- return relayConn.Transport(remote.Label)
-}
-
-type WSSServer struct{ WSServer }
-
-func NewWSSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *WSSServer {
- wsServer := NewWSServer(listenAddr, raw, l)
- return &WSSServer{WSServer: *wsServer}
-}
-
-func (s *WSSServer) ListenAndServe() error {
- s.httpServer.TLSConfig = mytls.DefaultTLSConfig
- return s.WSServer.ListenAndServe()
+ // insert tls config
+ wsServer.httpServer.TLSConfig = mytls.DefaultTLSConfig
+ return &WssServer{WsServer: wsServer}, nil
}
diff --git a/echo/internal/transporter/wss_mux.go b/echo/internal/transporter/wss_mux.go
index d180c5f2f6..844a1cbca4 100644
--- a/echo/internal/transporter/wss_mux.go
+++ b/echo/internal/transporter/wss_mux.go
@@ -1,9 +1,7 @@
-// nolint: errcheck
package transporter
import (
"context"
- "crypto/tls"
"net"
"net/http"
"time"
@@ -11,31 +9,34 @@ import (
"github.com/gobwas/ws"
"github.com/labstack/echo/v4"
"github.com/xtaci/smux"
- "go.uber.org/zap"
- "github.com/Ehco1996/ehco/internal/conn"
- "github.com/Ehco1996/ehco/internal/constant"
"github.com/Ehco1996/ehco/internal/metrics"
- mytls "github.com/Ehco1996/ehco/internal/tls"
- "github.com/Ehco1996/ehco/internal/web"
"github.com/Ehco1996/ehco/pkg/lb"
)
-type MWSSClient struct {
- *RawClient
- dialer *ws.Dialer
- mtp *smuxTransporter
+var (
+ _ RelayClient = &MwssClient{}
+ _ RelayServer = &MwssServer{}
+ _ muxServer = &MwssServer{}
+)
+
+type MwssClient struct {
+ *WssClient
+
+ muxTP *smuxTransporter
}
-func newMWSSClient(raw *RawClient) *MWSSClient {
- dialer := &ws.Dialer{TLSConfig: mytls.DefaultTLSConfig, Timeout: constant.DialTimeOut}
- c := &MWSSClient{dialer: dialer, RawClient: raw}
- mtp := NewSmuxTransporter(raw.l.Named("mwss"), c.initNewSession)
- c.mtp = mtp
- return c
+func newMwssClient(base *baseTransporter) (*MwssClient, error) {
+ wc, err := newWssClient(base)
+ if err != nil {
+ return nil, err
+ }
+ c := &MwssClient{WssClient: wc}
+ c.muxTP = NewSmuxTransporter(c.l.Named("mwss"), c.initNewSession)
+ return c, nil
}
-func (c *MWSSClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) {
+func (c *MwssClient) initNewSession(ctx context.Context, addr string) (*smux.Session, error) {
rc, _, _, err := c.dialer.Dial(ctx, addr)
if err != nil {
return nil, err
@@ -51,68 +52,39 @@ func (c *MWSSClient) initNewSession(ctx context.Context, addr string) (*smux.Ses
return session, nil
}
-func (s *MWSSClient) dialRemote(remote *lb.Node) (net.Conn, error) {
+func (s *MwssClient) TCPHandShake(remote *lb.Node) (net.Conn, error) {
t1 := time.Now()
- mwssc, err := s.mtp.Dial(context.TODO(), remote.Address+"/handshake/")
+ mwssc, err := s.muxTP.Dial(context.TODO(), remote.Address+"/handshake/")
if err != nil {
return nil, err
}
-
latency := time.Since(t1)
metrics.HandShakeDuration.WithLabelValues(remote.Label).Observe(float64(latency.Milliseconds()))
remote.HandShakeDuration = latency
return mwssc, nil
}
-func (s *MWSSClient) HandleTCPConn(c net.Conn, remote *lb.Node) error {
- clonedRemote := remote.Clone()
- mwsc, err := s.dialRemote(clonedRemote)
+type MwssServer struct {
+ *WssServer
+ *muxServerImpl
+}
+
+func newMwssServer(base *baseTransporter) (*MwssServer, error) {
+ wssServer, err := newWssServer(base)
if err != nil {
- return err
+ return nil, err
}
- s.l.Infof("HandleTCPConn from:%s to:%s", c.LocalAddr(), remote.Address)
- relayConn := conn.NewRelayConn(s.relayLabel, c, mwsc, conn.WithHandshakeDuration(clonedRemote.HandShakeDuration))
- s.cmgr.AddConnection(relayConn)
- defer s.cmgr.RemoveConnection(relayConn)
- return relayConn.Transport(remote.Label)
+ s := &MwssServer{
+ WssServer: wssServer,
+ muxServerImpl: newMuxServer(base.cfg.Listen, base.l.Named("mwss")),
+ }
+ s.e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest)))
+ return s, nil
}
-type MWSSServer struct {
- raw *RawClient
- httpServer *http.Server
- l *zap.SugaredLogger
-
- connChan chan net.Conn
- errChan chan error
-}
-
-func NewMWSSServer(listenAddr string, raw *RawClient, l *zap.SugaredLogger) *MWSSServer {
- s := &MWSSServer{
- raw: raw,
- l: l,
- errChan: make(chan error, 1),
- connChan: make(chan net.Conn, 1024),
- }
-
- e := web.NewEchoServer()
- e.GET("/", echo.WrapHandler(web.MakeIndexF()))
- e.GET("/handshake/", echo.WrapHandler(http.HandlerFunc(s.HandleRequest)))
- s.httpServer = &http.Server{
- Addr: listenAddr,
- Handler: e,
- TLSConfig: mytls.DefaultTLSConfig,
- ReadHeaderTimeout: 30 * time.Second,
- }
- return s
-}
-
-func (s *MWSSServer) ListenAndServe() error {
- lis, err := net.Listen("tcp", s.httpServer.Addr)
- if err != nil {
- return err
- }
+func (s *MwssServer) ListenAndServe() error {
go func() {
- s.errChan <- s.httpServer.Serve(tls.NewListener(lis, s.httpServer.TLSConfig))
+ s.errChan <- s.e.StartServer(s.httpServer)
}()
for {
@@ -121,15 +93,14 @@ func (s *MWSSServer) ListenAndServe() error {
return e
}
go func(c net.Conn) {
- remote := s.raw.GetRemote()
- if err := s.raw.HandleTCPConn(c, remote); err != nil {
- s.l.Errorf("HandleTCPConn meet error from:%s to:%s err:%s", c.RemoteAddr(), remote.Address, err)
+ if err := s.RelayTCPConn(c, s.relayer.TCPHandShake); err != nil {
+ s.l.Errorf("RelayTCPConn error: %s", err.Error())
}
}(conn)
}
}
-func (s *MWSSServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
+func (s *MwssServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
conn, _, _, err := ws.UpgradeHTTP(r, w)
if err != nil {
s.l.Error(err)
@@ -138,44 +109,6 @@ func (s *MWSSServer) HandleRequest(w http.ResponseWriter, r *http.Request) {
s.mux(conn)
}
-func (s *MWSSServer) mux(conn net.Conn) {
- defer conn.Close()
-
- cfg := smux.DefaultConfig()
- cfg.KeepAliveDisabled = true
- session, err := smux.Server(conn, cfg)
- if err != nil {
- s.l.Debugf("server err %s - %s : %s", conn.RemoteAddr(), s.httpServer.Addr, err)
- return
- }
- defer session.Close()
-
- s.l.Debugf("session init %s %s", conn.RemoteAddr(), s.httpServer.Addr)
- defer s.l.Debugf("session close %s >-< %s", conn.RemoteAddr(), s.httpServer.Addr)
-
- for {
- stream, err := session.AcceptStream()
- if err != nil {
- s.l.Errorf("accept stream err: %s", err)
- break
- }
- select {
- case s.connChan <- stream:
- default:
- stream.Close()
- s.l.Infof("%s - %s: connection queue is full", conn.RemoteAddr(), conn.LocalAddr())
- }
- }
-}
-
-func (s *MWSSServer) Accept() (conn net.Conn, err error) {
- select {
- case conn = <-s.connChan:
- case err = <-s.errChan:
- }
- return
-}
-
-func (s *MWSSServer) Close() error {
- return s.httpServer.Close()
+func (s *MwssServer) Close() error {
+ return s.e.Close()
}
diff --git a/echo/internal/transporter/buffer.go b/echo/pkg/buffer/buffer.go
similarity index 98%
rename from echo/internal/transporter/buffer.go
rename to echo/pkg/buffer/buffer.go
index 8edd7ebef5..8ae9d3ebe0 100644
--- a/echo/internal/transporter/buffer.go
+++ b/echo/pkg/buffer/buffer.go
@@ -1,4 +1,4 @@
-package transporter
+package buffer
import (
"github.com/Ehco1996/ehco/internal/constant"
diff --git a/echo/pkg/sub/clash_types.go b/echo/pkg/sub/clash_types.go
index d36e6822d7..f40f9e488a 100644
--- a/echo/pkg/sub/clash_types.go
+++ b/echo/pkg/sub/clash_types.go
@@ -133,8 +133,8 @@ func (p *Proxies) ToRelayConfig(listenHost string, listenPort string, newName st
remoteAddr := net.JoinHostPort(p.Server, p.Port)
r := &relay_cfg.Config{
Label: newName,
- ListenType: constant.Listen_RAW,
- TransportType: constant.Transport_RAW,
+ ListenType: constant.RelayTypeRaw,
+ TransportType: constant.RelayTypeRaw,
Listen: net.JoinHostPort(listenHost, listenPort),
TCPRemotes: []string{remoteAddr},
}
diff --git a/echo/test/relay_test.go b/echo/test/relay_test.go
index a01410c4b8..d271f0678f 100644
--- a/echo/test/relay_test.go
+++ b/echo/test/relay_test.go
@@ -56,66 +56,66 @@ func init() {
// raw cfg
{
Listen: RAW_LISTEN,
- ListenType: constant.Listen_RAW,
+ ListenType: constant.RelayTypeRaw,
TCPRemotes: []string{ECHO_SERVER},
UDPRemotes: []string{ECHO_SERVER},
- TransportType: constant.Transport_RAW,
+ TransportType: constant.RelayTypeRaw,
},
// ws
{
Listen: WS_LISTEN,
- ListenType: constant.Listen_RAW,
+ ListenType: constant.RelayTypeRaw,
TCPRemotes: []string{WS_REMOTE},
- TransportType: constant.Transport_WS,
+ TransportType: constant.RelayTypeWS,
},
{
Listen: WS_SERVER,
- ListenType: constant.Listen_WS,
+ ListenType: constant.RelayTypeWS,
TCPRemotes: []string{ECHO_SERVER},
- TransportType: constant.Transport_RAW,
+ TransportType: constant.RelayTypeRaw,
},
// wss
{
Listen: WSS_LISTEN,
- ListenType: constant.Listen_RAW,
+ ListenType: constant.RelayTypeRaw,
TCPRemotes: []string{WSS_REMOTE},
- TransportType: constant.Transport_WSS,
+ TransportType: constant.RelayTypeWSS,
},
{
Listen: WSS_SERVER,
- ListenType: constant.Listen_WSS,
+ ListenType: constant.RelayTypeWSS,
TCPRemotes: []string{ECHO_SERVER},
- TransportType: constant.Transport_RAW,
+ TransportType: constant.RelayTypeRaw,
},
// mwss
{
Listen: MWSS_LISTEN,
- ListenType: constant.Listen_RAW,
+ ListenType: constant.RelayTypeRaw,
TCPRemotes: []string{MWSS_REMOTE},
- TransportType: constant.Transport_MWSS,
+ TransportType: constant.RelayTypeMWSS,
},
{
Listen: MWSS_SERVER,
- ListenType: constant.Listen_MWSS,
+ ListenType: constant.RelayTypeMWSS,
TCPRemotes: []string{ECHO_SERVER},
- TransportType: constant.Transport_RAW,
+ TransportType: constant.RelayTypeRaw,
},
// mtcp
{
Listen: MTCP_LISTEN,
- ListenType: constant.Listen_RAW,
+ ListenType: constant.RelayTypeRaw,
TCPRemotes: []string{MTCP_REMOTE},
- TransportType: constant.Transport_MTCP,
+ TransportType: constant.RelayTypeMTCP,
},
{
Listen: MTCP_SERVER,
- ListenType: constant.Listen_MTCP,
+ ListenType: constant.RelayTypeMTCP,
TCPRemotes: []string{ECHO_SERVER},
- TransportType: constant.Transport_RAW,
+ TransportType: constant.RelayTypeRaw,
},
},
}
diff --git a/mihomo/adapter/provider/parser.go b/mihomo/adapter/provider/parser.go
index bbaf29be31..1094668d46 100644
--- a/mihomo/adapter/provider/parser.go
+++ b/mihomo/adapter/provider/parser.go
@@ -88,16 +88,13 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
path := C.Path.Resolve(schema.Path)
vehicle = resource.NewFileVehicle(path)
case "http":
- var path string
+ path := C.Path.GetPathByHash("proxies", schema.URL)
if schema.Path != "" {
path = C.Path.Resolve(schema.Path)
if !features.CMFA && !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("%w: %s", errSubPath, path)
}
- } else {
- path = C.Path.GetPathByHash("proxies", schema.URL)
}
-
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header)
default:
return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type)
diff --git a/mihomo/adapter/provider/provider.go b/mihomo/adapter/provider/provider.go
index aa5b823350..2715a30972 100644
--- a/mihomo/adapter/provider/provider.go
+++ b/mihomo/adapter/provider/provider.go
@@ -125,7 +125,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(),
- http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
@@ -134,7 +134,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() {
userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo"))
if userInfoStr == "" {
resp2, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(),
- http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil, "")
+ http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil)
if err != nil {
return
}
diff --git a/mihomo/component/geodata/init.go b/mihomo/component/geodata/init.go
index 64022f013b..834567a447 100644
--- a/mihomo/component/geodata/init.go
+++ b/mihomo/component/geodata/init.go
@@ -47,7 +47,7 @@ func InitGeoSite() error {
func downloadGeoSite(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
@@ -66,7 +66,7 @@ func downloadGeoSite(path string) (err error) {
func downloadGeoIP(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
diff --git a/mihomo/component/http/http.go b/mihomo/component/http/http.go
index ef37e328b8..21d65d2e96 100644
--- a/mihomo/component/http/http.go
+++ b/mihomo/component/http/http.go
@@ -16,7 +16,11 @@ import (
"github.com/metacubex/mihomo/listener/inner"
)
-func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) {
+func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) {
+ return HttpRequestWithProxy(ctx, url, method, header, body, "")
+}
+
+func HttpRequestWithProxy(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) {
method = strings.ToUpper(method)
urlRes, err := URL.Parse(url)
if err != nil {
diff --git a/mihomo/component/mmdb/mmdb.go b/mihomo/component/mmdb/mmdb.go
index 120739fc15..81156bc62d 100644
--- a/mihomo/component/mmdb/mmdb.go
+++ b/mihomo/component/mmdb/mmdb.go
@@ -82,7 +82,7 @@ func IPInstance() IPReader {
func DownloadMMDB(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
@@ -115,7 +115,7 @@ func ASNInstance() ASNReader {
func DownloadASN(path string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, C.ASNUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return
}
diff --git a/mihomo/component/resource/vehicle.go b/mihomo/component/resource/vehicle.go
index 2f71c2e6c6..2d71be9455 100644
--- a/mihomo/component/resource/vehicle.go
+++ b/mihomo/component/resource/vehicle.go
@@ -54,7 +54,7 @@ func (h *HTTPVehicle) Path() string {
func (h *HTTPVehicle) Read() ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, h.header, nil, h.proxy)
+ resp, err := mihomoHttp.HttpRequestWithProxy(ctx, h.url, http.MethodGet, h.header, nil, h.proxy)
if err != nil {
return nil, err
}
diff --git a/mihomo/config/utils.go b/mihomo/config/utils.go
index 596199ca18..66bf3441f2 100644
--- a/mihomo/config/utils.go
+++ b/mihomo/config/utils.go
@@ -20,7 +20,7 @@ import (
func downloadForBytes(url string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return nil, err
}
diff --git a/mihomo/hub/updater/updater.go b/mihomo/hub/updater/updater.go
index e0d3a39ca1..02ff07ba26 100644
--- a/mihomo/hub/updater/updater.go
+++ b/mihomo/hub/updater/updater.go
@@ -234,7 +234,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024
func downloadPackageFile() (err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return fmt.Errorf("http request failed: %w", err)
}
@@ -415,7 +415,7 @@ func copyFile(src, dst string) error {
func getLatestVersion() (version string, err error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
- resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil, "")
+ resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
if err != nil {
return "", fmt.Errorf("get Latest Version fail: %w", err)
}
diff --git a/mihomo/rules/provider/parse.go b/mihomo/rules/provider/parse.go
index e7920adf6c..a20da28d5c 100644
--- a/mihomo/rules/provider/parse.go
+++ b/mihomo/rules/provider/parse.go
@@ -62,15 +62,12 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t
path := C.Path.Resolve(schema.Path)
vehicle = resource.NewFileVehicle(path)
case "http":
- var path string
+ path := C.Path.GetPathByHash("rules", schema.URL)
if schema.Path != "" {
path = C.Path.Resolve(schema.Path)
if !features.CMFA && !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("%w: %s", errSubPath, path)
}
- } else {
- path = C.Path.GetPathByHash("rules", schema.URL)
-
}
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil)
default:
diff --git a/openwrt-packages/luci-app-store/Makefile b/openwrt-packages/luci-app-store/Makefile
index 8cb1502640..319b2651eb 100644
--- a/openwrt-packages/luci-app-store/Makefile
+++ b/openwrt-packages/luci-app-store/Makefile
@@ -11,7 +11,7 @@ LUCI_DEPENDS:=+curl +opkg +luci-base +tar +coreutils +coreutils-stat +libuci-lua
LUCI_EXTRA_DEPENDS:=luci-lib-taskd (>=1.0.17)
LUCI_PKGARCH:=all
-PKG_VERSION:=0.1.14-2
+PKG_VERSION:=0.1.14-3
# PKG_RELEASE MUST be empty for luci.mk
PKG_RELEASE:=
diff --git a/openwrt-packages/luci-app-store/root/bin/is-opkg b/openwrt-packages/luci-app-store/root/bin/is-opkg
index 01698cc2bc..5bc97ae65d 100755
--- a/openwrt-packages/luci-app-store/root/bin/is-opkg
+++ b/openwrt-packages/luci-app-store/root/bin/is-opkg
@@ -58,11 +58,13 @@ update() {
return 1
fi
- fcurl -o ${OPKG_CONF_DIR}/meta.conf "${FEEDS_SERVER}/all/meta.conf" && \
- fcurl -o ${OPKG_CONF_DIR}/all.conf "${FEEDS_SERVER}/all/isfeeds.conf" && \
- fcurl -o ${OPKG_CONF_DIR}/arch.conf "${FEEDS_SERVER}/${ARCH}/isfeeds.conf" || \
+ echo "Fetch feed list for ${ARCH}"
+ fcurl --no-progress-meter -o ${OPKG_CONF_DIR}/meta.conf "${FEEDS_SERVER}/all/meta.conf" && \
+ fcurl --no-progress-meter -o ${OPKG_CONF_DIR}/all.conf "${FEEDS_SERVER}/all/isfeeds.conf" && \
+ fcurl --no-progress-meter -o ${OPKG_CONF_DIR}/arch.conf "${FEEDS_SERVER}/${ARCH}/isfeeds.conf" || \
return 1
+ echo "Update feeds index"
opkg -f ${IS_ROOT}/etc/opkg_o.conf --offline-root ${IS_ROOT} update
return 0
diff --git a/small/chinadns-ng/Makefile b/small/chinadns-ng/Makefile
index 7bb5555289..e524022526 100644
--- a/small/chinadns-ng/Makefile
+++ b/small/chinadns-ng/Makefile
@@ -12,8 +12,8 @@ ifeq ($(ARCH),aarch64)
else ifeq ($(ARCH),arm)
ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE))))
ifeq ($(ARM_CPU_FEATURES),)
- PKG_ARCH:=chinadns-ng@arm-linux-musleabi@generic+v7a@fast+lto
- PKG_HASH:=c2e0378e20f5fda376d4f52bfbe1a3dbc7dfe23879e8edc8ef7ab55694cfd676
+ PKG_ARCH:=chinadns-ng@arm-linux-musleabi@generic+v6+soft_float@fast+lto
+ PKG_HASH:=f9e597bbc060d7c5e19c837a3c0b3118f91c986f29ee7f55a23ace321aca1731
else
PKG_ARCH:=chinadns-ng@arm-linux-musleabihf@generic+v7a@fast+lto
PKG_HASH:=d065c7d55b6c43b20dbb668d7bdafabe371c3360cc75bd0279cc2d7a83e342e9
diff --git a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
index d2b87a7fa0..44b29af29a 100644
--- a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
+++ b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
@@ -525,7 +525,9 @@ o.default = "3"
o.rmempty = true
o = s:option(Value, "timeout", translate("Timeout for establishing a connection to server(second)"))
+o.description = translate("Default value 0 indicatesno heartbeat.")
o:depends("type", "tuic")
+o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
o.datatype = "uinteger"
o.default = "8"
o.rmempty = true
@@ -831,11 +833,22 @@ o:depends("transport", "kcp")
o.rmempty = true
-- [[ WireGuard 部分 ]]--
+o = s:option(Flag, "kernelmode", translate("Enabled Kernel virtual NIC TUN(optional)"))
+o.description = translate("Virtual NIC TUN of Linux kernel can be used only when system supports and have root permission. If used, IPv6 routing table 1023 is occupied.")
+o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
+o.default = "0"
+o.rmempty = true
+
o = s:option(DynamicList, "local_addresses", translate("Local addresses"))
o.datatype = "cidr"
o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
o.rmempty = true
+o = s:option(DynamicList, "reserved", translate("Reserved bytes(optional)"))
+o.description = translate("Wireguard reserved bytes.")
+o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
+o.rmempty = true
+
o = s:option(Value, "private_key", translate("Private key"))
o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
o.password = true
@@ -850,6 +863,13 @@ o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
o.password = true
o.rmempty = true
+o = s:option(DynamicList, "allowedips", translate("allowedIPs(optional)"))
+o.description = translate("Wireguard allows only traffic from specific source IP.")
+o.datatype = "cidr"
+o:depends({type = "v2ray", v2ray_protocol = "wireguard"})
+o.default = "0.0.0.0/0"
+o.rmempty = true
+
-- [[ TLS ]]--
o = s:option(Flag, "tls", translate("TLS"))
o.rmempty = true
diff --git a/small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po b/small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po
index d343d4f28a..632b5c9e44 100644
--- a/small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po
+++ b/small/luci-app-ssr-plus/po/zh-cn/ssr-plus.po
@@ -942,9 +942,21 @@ msgstr "写入缓冲区大小"
msgid "Congestion"
msgstr "拥塞控制"
+msgid "Enabled Kernel virtual NIC TUN(optional)"
+msgstr "启用内核的虚拟网卡 TUN(可选)"
+
+msgid "Virtual NIC TUN of Linux kernel can be used only when system supports and have root permission. If used, IPv6 routing table 1023 is occupied."
+msgstr "需要系统支持且有 root 权限才能使用 Linux 内核的虚拟网卡 TUN,使用后会占用 IPv6 的 1023 号路由表。"
+
msgid "Local addresses"
msgstr "本地地址"
+msgid "Reserved bytes(optional)"
+msgstr "保留字节(可选)"
+
+msgid "Wireguard reserved bytes."
+msgstr "Wireguard 保留字节。"
+
msgid "Private key"
msgstr "私钥"
@@ -954,6 +966,15 @@ msgstr "节点公钥"
msgid "Pre-shared key"
msgstr "预共享密钥"
+msgid "Default value 0 indicatesno heartbeat."
+msgstr "默认为 0 表示无心跳。"
+
+msgid "allowedIPs(optional)"
+msgstr "allowedIPs(可选)"
+
+msgid "Wireguard allows only traffic from specific source IP."
+msgstr "Wireguard 仅允许特定源 IP 的流量。"
+
msgid "Network interface to use"
msgstr "使用的网络接口"
diff --git a/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua
index cbb911ebed..b07949e5f1 100755
--- a/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua
+++ b/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua
@@ -72,9 +72,13 @@ function wireguard()
{
publicKey = server.peer_pubkey,
preSharedKey = server.preshared_key,
- endpoint = server.server .. ":" .. server.server_port
+ endpoint = server.server .. ":" .. server.server_port,
+ keepAlive = tonumber(server.heartbeat),
+ allowedIPs = (server.allowedips) or nil,
}
},
+ kernelMode = (server.kernelmode == "1") and true or false,
+ reserved = {server.reserved} or nil,
mtu = tonumber(server.mtu)
}
end
@@ -172,7 +176,7 @@ local Xray = {
protocol = server.v2ray_protocol,
settings = outbound_settings,
-- 底层传输配置
- streamSettings = {
+ streamSettings = (server.v2ray_protocol ~= "wireguard") and {
network = server.transport or "tcp",
security = (server.tls == '1') and "tls" or (server.reality == '1') and "reality" or nil,
tlsSettings = (server.tls == '1') and {
@@ -258,14 +262,14 @@ local Xray = {
tcpNoDelay = (server.mptcp == "1") and true or false, -- MPTCP
tcpcongestion = server.custom_tcpcongestion -- 连接服务器节点的 TCP 拥塞控制算法
}
- },
- mux = {
+ } or nil,
+ mux = (server.v2ray_protocol ~= "wireguard") and {
-- mux
enabled = (server.mux == "1") and true or false, -- Mux
concurrency = tonumber(server.concurrency), -- TCP 最大并发连接数
xudpConcurrency = tonumber(server.xudpConcurrency), -- UDP 最大并发连接数
xudpProxyUDP443 = server.xudpProxyUDP443 -- 对被代理的 UDP/443 流量处理方式
- }
+ } or nil
}
}
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
@@ -322,7 +326,7 @@ local ss = {
}
local hysteria = {
server = (server.server_port and (server.port_range and (server.server .. ":" .. server.server_port .. "," .. server.port_range) or server.server .. ":" .. server.server_port) or (server.port_range and server.server .. ":" .. server.port_range or server.server .. ":443")),
- bandwidth = {
+ bandwidth = (server.uplink_capacity or server.downlink_capacity) and {
up = tonumber(server.uplink_capacity) and tonumber(server.uplink_capacity) .. " mbps" or nil,
down = tonumber(server.downlink_capacity) and tonumber(server.downlink_capacity) .. " mbps" or nil
},
@@ -336,12 +340,11 @@ local hysteria = {
hopInterval = (server.port_range and (tonumber(server.hopinterval) .. "s") or nil)
} or nil)
} or nil,
-
--[[
tcpTProxy = (proto:find("tcp") and local_port ~= "0") and {
- listen = "0.0.0.0:" .. tonumber(local_port)
-} or nil,
-]]
+ listen = "0.0.0.0:" .. tonumber(local_port)
+ } or nil,
+]]--
tcpRedirect = (proto:find("tcp") and local_port ~= "0") and {
listen = "0.0.0.0:" .. tonumber(local_port)
} or nil,
@@ -359,7 +362,7 @@ local hysteria = {
maxConnReceiveWindow = (server.maxconnreceivewindow and server.maxconnreceivewindow or nil),
maxIdleTimeout = (tonumber(server.maxidletimeout) and tonumber(server.maxidletimeout) .. "s" or nil),
keepAlivePeriod = (tonumber(server.keepaliveperiod) and tonumber(server.keepaliveperiod) .. "s" or nil),
- disable_mtu_discovery = (server.disablepathmtudiscovery == "1") and true or false
+ disablePathMTUDiscovery = (server.disablepathmtudiscovery == "1") and true or false
} or nil,
auth = server.hy2_auth,
tls = (server.tls_host) and {
@@ -394,7 +397,7 @@ local chain_sslocal = {
mode = (proto:find("tcp,udp") and "tcp_and_udp") or proto .. "_only",
protocol = "redir",
tcp_redir = "redirect",
- --tcp_redir = "tproxy",
+ --tcp_redir = "tproxy",
udp_redir = "tproxy"
},
socks_port ~= "0" and {
diff --git a/suyu/.ci/scripts/windows/docker.sh b/suyu/.ci/scripts/windows/docker.sh
index 70eadda41e..73e000324c 100755
--- a/suyu/.ci/scripts/windows/docker.sh
+++ b/suyu/.ci/scripts/windows/docker.sh
@@ -1,6 +1,7 @@
#!/bin/bash -ex
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
+# SPDX-FileCopyrightText: 2024 suyu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
set -e
@@ -9,12 +10,15 @@ set -e
ccache -sv
+rm -rf build
mkdir -p build && cd build
-cmake .. \
+/usr/bin/x86_64-w64-mingw32-cmake .. \
-DCMAKE_BUILD_TYPE=Release \
- -DCMAKE_TOOLCHAIN_FILE="${PWD}/../CMakeModules/MinGWCross.cmake" \
-DDISPLAY_VERSION="$1" \
- -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
+ -DDYNARMIC_USE_PRECOMPILED_HEADERS=OFF \
+ -DSUYU_USE_PRECOMPILED_HEADERS=OFF \
+ -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=OFF \
+ -DUSE_DISCORD_PRESENCE=ON \
-DENABLE_QT_TRANSLATION=ON \
-DUSE_CCACHE=ON \
-DSUYU_USE_BUNDLED_SDL2=OFF \
diff --git a/suyu/.forgejo/workflows/verify.yml b/suyu/.forgejo/workflows/verify.yml
index f89166dbde..1292ddcfa9 100644
--- a/suyu/.forgejo/workflows/verify.yml
+++ b/suyu/.forgejo/workflows/verify.yml
@@ -63,8 +63,8 @@ jobs:
image: linux-fresh
- type: linux
image: linux-fresh
- # - type: windows
- # image: linux-mingw
+ - type: windows
+ image: linux-mingw
container: fijxu/build-environments:${{ matrix.image }}
# User 1001 doesn't exists on the images.
# options: -u 1001
diff --git a/xray-core/app/proxyman/outbound/handler.go b/xray-core/app/proxyman/outbound/handler.go
index 41713d0b8c..792ac24971 100644
--- a/xray-core/app/proxyman/outbound/handler.go
+++ b/xray-core/app/proxyman/outbound/handler.go
@@ -2,12 +2,8 @@ package outbound
import (
"context"
+ "crypto/rand"
"errors"
- "io"
- "math/rand"
- gonet "net"
- "os"
-
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
@@ -25,6 +21,10 @@ import (
"github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/pipe"
+ "io"
+ "math/big"
+ gonet "net"
+ "os"
)
func getStatCounter(v *core.Instance, tag string) (stats.Counter, stats.Counter) {
@@ -319,16 +319,21 @@ func (h *Handler) Close() error {
return nil
}
-// Return random IPv6 in a CIDR block
+
func ParseRandomIPv6(address net.Address, prefix string) net.Address {
- addr := address.IP().String()
- _, network, _ := gonet.ParseCIDR(addr + "/" + prefix)
+ _, network, _ := gonet.ParseCIDR(address.IP().String() + "/" + prefix)
- ipv6 := network.IP.To16()
- prefixLen, _ := network.Mask.Size()
- for i := prefixLen / 8; i < 16; i++ {
- ipv6[i] = byte(rand.Intn(256))
- }
+ maskSize, totalBits := network.Mask.Size()
+ subnetSize := big.NewInt(1).Lsh(big.NewInt(1), uint(totalBits-maskSize))
- return net.ParseAddress(gonet.IP(ipv6).String())
+ // random
+ randomBigInt, _ := rand.Int(rand.Reader, subnetSize)
+
+ startIPBigInt := big.NewInt(0).SetBytes(network.IP.To16())
+ randomIPBigInt := big.NewInt(0).Add(startIPBigInt, randomBigInt)
+
+ randomIPBytes := randomIPBigInt.Bytes()
+ randomIPBytes = append(make([]byte, 16-len(randomIPBytes)), randomIPBytes...)
+
+ return net.ParseAddress(gonet.IP(randomIPBytes).String())
}
diff --git a/xray-core/go.mod b/xray-core/go.mod
index 92fad3c3b4..bb3a6beb9d 100644
--- a/xray-core/go.mod
+++ b/xray-core/go.mod
@@ -20,16 +20,16 @@ require (
github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3
github.com/xtls/reality v0.0.0-20231112171332-de1173cf2b19
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
- golang.org/x/crypto v0.21.0
- golang.org/x/net v0.23.0
- golang.org/x/sync v0.6.0
- golang.org/x/sys v0.18.0
+ golang.org/x/crypto v0.22.0
+ golang.org/x/net v0.24.0
+ golang.org/x/sync v0.7.0
+ golang.org/x/sys v0.19.0
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
google.golang.org/grpc v1.63.0
google.golang.org/protobuf v1.33.0
gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b
h12.io/socks v1.0.3
- lukechampine.com/blake3 v1.2.1
+ lukechampine.com/blake3 v1.2.2
)
require (
diff --git a/xray-core/go.sum b/xray-core/go.sum
index b9a4797b92..f0450753b7 100644
--- a/xray-core/go.sum
+++ b/xray-core/go.sum
@@ -179,8 +179,8 @@ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
@@ -201,8 +201,8 @@ golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
-golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -214,8 +214,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -228,8 +228,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -299,7 +299,7 @@ h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
-lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+lukechampine.com/blake3 v1.2.2 h1:wEAbSg0IVU4ih44CVlpMqMZMpzr5hf/6aqodLlevd/w=
+lukechampine.com/blake3 v1.2.2/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
diff --git a/xray-core/proxy/freedom/freedom.go b/xray-core/proxy/freedom/freedom.go
index 558536462f..0176929cc4 100644
--- a/xray-core/proxy/freedom/freedom.go
+++ b/xray-core/proxy/freedom/freedom.go
@@ -373,6 +373,9 @@ func (f *FragmentWriter) Write(b []byte) (int, error) {
return f.writer.Write(b)
}
recordLen := 5 + ((int(b[3]) << 8) | int(b[4]))
+ if len(b) < recordLen { // maybe already fragmented somehow
+ return f.writer.Write(b)
+ }
data := b[5:recordLen]
buf := make([]byte, 1024)
for from := 0; ; {
diff --git a/yass/.github/workflows/releases-linux-binary.yml b/yass/.github/workflows/releases-linux-binary.yml
index 23d2c1289e..8ab1b92a2e 100644
--- a/yass/.github/workflows/releases-linux-binary.yml
+++ b/yass/.github/workflows/releases-linux-binary.yml
@@ -57,10 +57,13 @@ jobs:
qemu_suffix: mipsel
- arch: mips64el
qemu_suffix: mips64el
+ - arch: loongarch64
+ qemu_suffix: loongarch64
+ - arch: riscv64
+ qemu_suffix: riscv64
+ - arch: riscv32
+ qemu_suffix: riscv32
runs-on: ubuntu-20.04
- env:
- ARCH: ${{ matrix.arch }}
- SDK_ROOT: ${{ github.workspace }}/debian_bullseye_${{ matrix.arch }}-sysroot
steps:
- uses: actions/checkout@v4
- name: Checkout with shallow submodules
@@ -73,6 +76,18 @@ jobs:
run: |
cd third_party/libc++abi
patch -p1 < v8-6.7.17-fix-gcc-unwind-header.patch
+ - name: Set SDK_ROOT
+ if: ${{ matrix.arch != 'loongarch64' && matrix.arch != 'riscv64' && matrix.arch != 'riscv32' }}
+ run: |
+ echo "SDK_ROOT=${{ github.workspace }}/debian_bullseye_${{ matrix.arch }}-sysroot" >> $GITHUB_ENV
+ - name: Set SDK_ROOT for loongarch64
+ if: ${{ matrix.arch == 'loongarch64' }}
+ run: |
+ echo "SDK_ROOT=${{ github.workspace }}/debian_bullseye_${{ matrix.arch }}-sysroot/target" >> $GITHUB_ENV
+ - name: Set SDK_ROOT for riscv64 and riscv32
+ if: ${{ matrix.arch == 'riscv64' || matrix.arch == 'riscv32' }}
+ run: |
+ echo "SDK_ROOT=${{ github.workspace }}/debian_bullseye_${{ matrix.arch }}-sysroot/sysroot" >> $GITHUB_ENV
- name: Cache clang
id: clang-cache
uses: actions/cache@v4
@@ -101,8 +116,8 @@ jobs:
uses: actions/cache@v4
with:
path: |
- ${{ env.SDK_ROOT }}
- key: ${{ runner.os }}-sysroot-${{ matrix.arch }}-${{ hashFiles('scripts/sysroots.json') }}-v1
+ ${{ github.workspace }}/debian_bullseye_${{ matrix.arch }}-sysroot
+ key: ${{ runner.os }}-sysroot-${{ matrix.arch }}-${{ hashFiles('scripts/sysroots.json') }}-v2
- name: Build build tool
run: |
cd tools
@@ -117,9 +132,27 @@ jobs:
run: |
wget http://ftp.us.debian.org/debian/pool/main/q/qemu/qemu-user-static_8.2.2+ds-2_amd64.deb
- name: "Install dependency: sysroot"
- if: ${{ steps.sysroot-cache.outputs.cache-hit != 'true' }}
+ if: ${{ steps.sysroot-cache.outputs.cache-hit != 'true' && matrix.arch != 'loongarch64' && matrix.arch != 'riscv64' && matrix.arch != 'riscv32' }}
run: |
- ./scripts/install-sysroot.py --arch ${{ env.ARCH }}
+ ./scripts/install-sysroot.py --arch ${{ matrix.arch }}
+ - name: "Install dependency: sysroot (loongarch64)"
+ if: ${{ steps.sysroot-cache.outputs.cache-hit != 'true' && matrix.arch == 'loongarch64' }}
+ run: |
+ mkdir -p debian_bullseye_loongarch64-sysroot
+ cd debian_bullseye_loongarch64-sysroot
+ curl -L https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | tar --strip-components=1 --xz -xf -
+ cp -fv ./loongarch64-unknown-linux-gnu/lib/libgcc_s.so target/lib64/
+ cp -fv ./loongarch64-unknown-linux-gnu/lib/libgcc_s.so.1 target/lib64/
+ rm -rf bin include libexec loongarch64-unknown-linux-gnu share
+ cd ..
+ - name: "Install dependency: sysroot (riscv64 and riscv32)"
+ if: ${{ steps.sysroot-cache.outputs.cache-hit != 'true' && (matrix.arch == 'riscv64' || matrix.arch == 'riscv32') }}
+ run: |
+ mkdir -p debian_bullseye_${{ matrix.arch }}-sysroot
+ cd debian_bullseye_${{ matrix.arch }}-sysroot
+ curl -L https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2023.07.07/${{ matrix.arch }}-glibc-ubuntu-20.04-gcc-nightly-2023.07.07-nightly.tar.gz | tar --strip-components=1 --gz -xf -
+ rm -rf bin include libexec ${{ matrix.arch }}-unknown-linux-gnu share
+ cd ..
- name: Change ubuntu mirror
run: |
sudo sed -i 's/azure.archive.ubuntu.com/azure.archive.ubuntu.com/g' /etc/apt/sources.list
@@ -134,11 +167,14 @@ jobs:
sudo apt install qemu-user
sudo apt remove -y qemu-user-binfmt
sudo dpkg -i qemu-user-static_*.deb
- - name: Build TGZ packages
+ - name: Build TGZ packages (CLI and Server)
run: |
- ./tools/build --variant gui --arch ${{ matrix.arch }} --system linux --sysroot ${{ env.SDK_ROOT }} -build-benchmark -build-test -nc
./tools/build --variant cli --arch ${{ matrix.arch }} --system linux --sysroot ${{ env.SDK_ROOT }} -build-benchmark -build-test -nc
./tools/build --variant server --arch ${{ matrix.arch }} --system linux --sysroot ${{ env.SDK_ROOT }} -build-benchmark -build-test -nc
+ - name: Build TGZ packages (GUI)
+ if: ${{ matrix.arch != 'loongarch64' && matrix.arch != 'riscv64' && matrix.arch != 'riscv32' }}
+ run: |
+ ./tools/build --variant gui --arch ${{ matrix.arch }} --system linux --sysroot ${{ env.SDK_ROOT }} -build-benchmark -build-test -nc
- name: Run tests (i386 and amd64)
if: ${{ matrix.arch == 'i386' || matrix.arch == 'amd64' }}
run: |
diff --git a/yass/CMakeLists.txt b/yass/CMakeLists.txt
index 51f8d286d6..a4e4a58ef7 100644
--- a/yass/CMakeLists.txt
+++ b/yass/CMakeLists.txt
@@ -310,6 +310,9 @@ else()
if (CMAKE_C_COMPILER_TARGET MATCHES "^riscv64-.*")
set(OS_RISCV64 TRUE)
endif()
+ if (CMAKE_C_COMPILER_TARGET MATCHES "^riscv32-.*")
+ set(OS_RISCV32 TRUE)
+ endif()
# Fix MINGW (native mingw)'s CMAKE_SYSTEM_PROCESSOR
if (MINGW)
if (OS_X86)
@@ -529,6 +532,14 @@ if (UNIX AND CMAKE_CROSSCOMPILING AND CMAKE_SYSROOT AND COMPILER_CLANG AND NOT C
# fix up for loongarch sysroot
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "loongarch64")
file(GLOB _GCC_SYSROOT "${CMAKE_SYSROOT}/../../lib/gcc/*/*.*.*")
+ # required by loongarch64 sdk https://github.com/loongson/build-tools/releases
+ if (NOT _GCC_SYSROOT)
+ file(GLOB _GCC_SYSROOT "${CMAKE_SYSROOT}/../lib/gcc/*/*.*.*")
+ endif()
+ endif()
+ # fix up for riscv64 and riscv32 sysroot
+ if (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv32")
+ file(GLOB _GCC_SYSROOT "${CMAKE_SYSROOT}/../lib/gcc/*/*.*.*")
endif()
if (_GCC_SYSROOT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --gcc-install-dir=${_GCC_SYSROOT}")
@@ -2044,8 +2055,17 @@ elseif (GUI)
set(GUI off)
endif()
+ # fix up for loongarch gtk support
+ # see https://github.com/microcai/gentoo-zh/pull/4486
+ if (CMAKE_SYSTEM_PROCESSOR STREQUAL "loongarch64")
+ message(STATUS "Blacklist gtk4 for loongarch64 target")
+ set(BLACKLIST_GTK4 ON)
+ else()
+ set(BLACKLIST_GTK4 OFF)
+ endif()
+
pkg_check_modules(GTK4 gtk4)
- if (GTK4_FOUND)
+ if (GTK4_FOUND AND NOT BLACKLIST_GTK4)
set(GUI_FLAVOUR "gtk4")
set(GUI_OTHER_FLAGS -Wno-deprecated-declarations)
@@ -2280,6 +2300,10 @@ if (USE_TCMALLOC)
message(WARNING "tcmalloc: loongarch64 is not supported, disabling...")
set(USE_TCMALLOC OFF)
endif()
+ if (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv32")
+ message(WARNING "tcmalloc: riscv32 is not supported, disabling...")
+ set(USE_TCMALLOC OFF)
+ endif()
endif()
# tunings:
diff --git a/yass/src/core/debug.cpp b/yass/src/core/debug.cpp
index ae0a74f8e1..c5e0b6b217 100644
--- a/yass/src/core/debug.cpp
+++ b/yass/src/core/debug.cpp
@@ -4,6 +4,7 @@
#include "core/debug.hpp"
#include "core/check_op.hpp"
+#include
#include
#include
#include
@@ -38,7 +39,7 @@ bool WaitForDebugger(int wait_seconds, bool silent) {
BreakDebugger();
return true;
}
- // FIXME PlatformThread::Sleep(Milliseconds(100));
+ absl::SleepFor(absl::Milliseconds(100));
}
return false;
}
@@ -287,7 +288,7 @@ void DebugBreak() {
#else
volatile int go = 0;
while (!go)
- PlatformThread::Sleep(Milliseconds(100));
+ absl::SleepFor(absl::Milliseconds(100));
#endif
}
}
diff --git a/yass/src/core/rand_util_posix.cpp b/yass/src/core/rand_util_posix.cpp
index 4c65c75e0c..82c1df3a14 100644
--- a/yass/src/core/rand_util_posix.cpp
+++ b/yass/src/core/rand_util_posix.cpp
@@ -72,7 +72,8 @@ class URandomFd {
// (https://chromium-review.googlesource.com/c/chromium/src/+/1545096) and land
// it or some form of it.
void RandBytes(void* output, size_t output_length) {
-#ifdef __linux__
+// FIXME currently lss doesn't like riscv32
+#if defined(__linux__) && !defined(ARCH_CPU_RISCV32)
// We have to call `getrandom` via Linux Syscall Support, rather than through
// the libc wrapper, because we might not have an up-to-date libc (e.g. on
// some bots).
diff --git a/yass/third_party/boringssl/src/crypto/fipsmodule/rand/getrandom_fillin.h b/yass/third_party/boringssl/src/crypto/fipsmodule/rand/getrandom_fillin.h
index 5f03768be7..73d267cb85 100644
--- a/yass/third_party/boringssl/src/crypto/fipsmodule/rand/getrandom_fillin.h
+++ b/yass/third_party/boringssl/src/crypto/fipsmodule/rand/getrandom_fillin.h
@@ -32,6 +32,8 @@
#define EXPECTED_NR_getrandom 384
#elif defined(OPENSSL_RISCV64)
#define EXPECTED_NR_getrandom 278
+#elif defined(OPENSSL_RISCV)
+#define EXPECTED_NR_getrandom 278
#elif defined(OPENSSL_LOONGARCH64)
#define EXPECTED_NR_getrandom 278
#endif
diff --git a/yass/third_party/boringssl/src/include/openssl/target.h b/yass/third_party/boringssl/src/include/openssl/target.h
index c38114df3b..638190dfd6 100644
--- a/yass/third_party/boringssl/src/include/openssl/target.h
+++ b/yass/third_party/boringssl/src/include/openssl/target.h
@@ -45,12 +45,13 @@
#define OPENSSL_RISCV64
#elif defined(__riscv) && __SIZEOF_POINTER__ == 4
#define OPENSSL_32_BIT
-#elif defined(__loongarch__) && __loongarch_grlen == 64
+#define OPENSSL_RISCV
+#elif defined(__loongarch__) && !defined(__loongarch_lp64)
+#define OPENSSL_32_BIT
+#define OPENSSL_LOONGARCH
+#elif defined(__loongarch__) && defined(__loongarch_lp64)
#define OPENSSL_64_BIT
#define OPENSSL_LOONGARCH64
-#elif defined(__loongarch__) && __loongarch_grlen == 32
-#define OPENSSL_32_BIT
-#define OPENSSL_LOONGARCH32
#elif defined(__pnacl__)
#define OPENSSL_32_BIT
#define OPENSSL_PNACL
diff --git a/yass/third_party/googleurl-override/build/build_config.h b/yass/third_party/googleurl-override/build/build_config.h
index fd0651fd39..a151d61372 100644
--- a/yass/third_party/googleurl-override/build/build_config.h
+++ b/yass/third_party/googleurl-override/build/build_config.h
@@ -358,6 +358,11 @@
#define ARCH_CPU_RISCV64 1
#define ARCH_CPU_64_BITS 1
#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__riscv) && (__riscv_xlen == 32)
+#define ARCH_CPU_RISCV_FAMILY 1
+#define ARCH_CPU_RISCV32 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
#else
#error Please add support for your architecture in build/build_config.h
#endif
diff --git a/yass/third_party/quiche/CMakeLists.txt b/yass/third_party/quiche/CMakeLists.txt
index 55956ce604..45c8994ea8 100644
--- a/yass/third_party/quiche/CMakeLists.txt
+++ b/yass/third_party/quiche/CMakeLists.txt
@@ -730,7 +730,6 @@ target_include_directories(quiche PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/overrides
${CMAKE_CURRENT_BINARY_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/../googleurl
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../../src
${CMAKE_CURRENT_SOURCE_DIR}/../../
diff --git a/yass/tools/build.go b/yass/tools/build.go
index 149746e08c..7fe5c86404 100644
--- a/yass/tools/build.go
+++ b/yass/tools/build.go
@@ -471,6 +471,10 @@ func getGNUTargetTypeAndArch(arch string, subsystem string) (string, string) {
return "mips64el-linux-gnuabi64", "mips64el"
} else if arch == "loongarch64" {
return "loongarch64-linux-gnu", "loongarch64"
+ } else if arch == "riscv64" {
+ return "riscv64-linux-gnu", "riscv64"
+ } else if arch == "riscv32" {
+ return "riscv32-linux-gnu", "riscv32"
}
glog.Fatalf("Invalid arch: %s", arch)
return "", ""
diff --git a/youtube-dl/youtube_dl/postprocessor/ffmpeg.py b/youtube-dl/youtube_dl/postprocessor/ffmpeg.py
index e5ffdf3788..214825aa97 100644
--- a/youtube-dl/youtube_dl/postprocessor/ffmpeg.py
+++ b/youtube-dl/youtube_dl/postprocessor/ffmpeg.py
@@ -74,8 +74,11 @@ class FFmpegPostProcessor(PostProcessor):
return FFmpegPostProcessor(downloader)._versions
def _determine_executables(self):
- programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe']
+ # ordered to match prefer_ffmpeg!
+ convs = ['ffmpeg', 'avconv']
+ probes = ['ffprobe', 'avprobe']
prefer_ffmpeg = True
+ programs = convs + probes
def get_ffmpeg_version(path):
ver = get_exe_version(path, args=['-version'])
@@ -127,10 +130,13 @@ class FFmpegPostProcessor(PostProcessor):
(p, get_ffmpeg_version(self._paths[p])) for p in programs)
if x[1] is not None)
- for p in ('ffmpeg', 'avconv')[::-1 if prefer_ffmpeg is False else 1]:
- if self._versions.get(p):
- self.basename = self.probe_basename = p
- break
+ basenames = [None, None]
+ for i, progs in enumerate((convs, probes)):
+ for p in progs[::-1 if prefer_ffmpeg is False else 1]:
+ if self._versions.get(p):
+ basenames[i] = p
+ break
+ self.basename, self.probe_basename = basenames
@property
def available(self):
diff --git a/yt-dlp/yt_dlp/cookies.py b/yt-dlp/yt_dlp/cookies.py
index 85d6dd1823..7b8d215f03 100644
--- a/yt-dlp/yt_dlp/cookies.py
+++ b/yt-dlp/yt_dlp/cookies.py
@@ -194,7 +194,11 @@ def _firefox_browser_dirs():
yield os.path.expanduser('~/Library/Application Support/Firefox/Profiles')
else:
- yield from map(os.path.expanduser, ('~/.mozilla/firefox', '~/snap/firefox/common/.mozilla/firefox'))
+ yield from map(os.path.expanduser, (
+ '~/.mozilla/firefox',
+ '~/snap/firefox/common/.mozilla/firefox',
+ '~/.var/app/org.mozilla.firefox/.mozilla/firefox',
+ ))
def _firefox_cookie_dbs(roots):
diff --git a/yt-dlp/yt_dlp/extractor/nhk.py b/yt-dlp/yt_dlp/extractor/nhk.py
index 7cf5b246b1..8bb017a732 100644
--- a/yt-dlp/yt_dlp/extractor/nhk.py
+++ b/yt-dlp/yt_dlp/extractor/nhk.py
@@ -8,6 +8,7 @@ from ..utils import (
int_or_none,
join_nonempty,
parse_duration,
+ remove_end,
traverse_obj,
try_call,
unescapeHTML,
@@ -19,8 +20,7 @@ from ..utils import (
class NhkBaseIE(InfoExtractor):
_API_URL_TEMPLATE = 'https://nwapi.nhk.jp/nhkworld/%sod%slist/v7b/%s/%s/%s/all%s.json'
- _BASE_URL_REGEX = r'https?://www3\.nhk\.or\.jp/nhkworld/(?P[a-z]{2})/ondemand'
- _TYPE_REGEX = r'/(?Pvideo|audio)/'
+ _BASE_URL_REGEX = r'https?://www3\.nhk\.or\.jp/nhkworld/(?P[a-z]{2})/'
def _call_api(self, m_id, lang, is_video, is_episode, is_clip):
return self._download_json(
@@ -83,7 +83,7 @@ class NhkBaseIE(InfoExtractor):
def _extract_episode_info(self, url, episode=None):
fetch_episode = episode is None
lang, m_type, episode_id = NhkVodIE._match_valid_url(url).group('lang', 'type', 'id')
- is_video = m_type == 'video'
+ is_video = m_type != 'audio'
if is_video:
episode_id = episode_id[:4] + '-' + episode_id[4:]
@@ -138,9 +138,10 @@ class NhkBaseIE(InfoExtractor):
else:
if fetch_episode:
- audio_path = episode['audio']['audio']
+ # From https://www3.nhk.or.jp/nhkworld/common/player/radio/inline/rod.html
+ audio_path = remove_end(episode['audio']['audio'], '.m4a')
info['formats'] = self._extract_m3u8_formats(
- 'https://nhkworld-vh.akamaihd.net/i%s/master.m3u8' % audio_path,
+ f'{urljoin("https://vod-stream.nhk.jp", audio_path)}/index.m3u8',
episode_id, 'm4a', entry_protocol='m3u8_native',
m3u8_id='hls', fatal=False)
for f in info['formats']:
@@ -155,9 +156,11 @@ class NhkBaseIE(InfoExtractor):
class NhkVodIE(NhkBaseIE):
- # the 7-character IDs can have alphabetic chars too: assume [a-z] rather than just [a-f], eg
- _VALID_URL = [rf'{NhkBaseIE._BASE_URL_REGEX}/(?Pvideo)/(?P[0-9a-z]+)',
- rf'{NhkBaseIE._BASE_URL_REGEX}/(?Paudio)/(?P[^/?#]+?-\d{{8}}-[0-9a-z]+)']
+ _VALID_URL = [
+ rf'{NhkBaseIE._BASE_URL_REGEX}shows/(?:(?Pvideo)/)?(?P\d{{4}}[\da-z]\d+)/?(?:$|[?#])',
+ rf'{NhkBaseIE._BASE_URL_REGEX}(?:ondemand|shows)/(?Paudio)/(?P[^/?#]+?-\d{{8}}-[\da-z]+)',
+ rf'{NhkBaseIE._BASE_URL_REGEX}ondemand/(?Pvideo)/(?P\d{{4}}[\da-z]\d+)', # deprecated
+ ]
# Content available only for a limited period of time. Visit
# https://www3.nhk.or.jp/nhkworld/en/ondemand/ for working samples.
_TESTS = [{
@@ -167,17 +170,16 @@ class NhkVodIE(NhkBaseIE):
'ext': 'mp4',
'title': 'Japan Railway Journal - The Tohoku Shinkansen: Full Speed Ahead',
'description': 'md5:49f7c5b206e03868a2fdf0d0814b92f6',
- 'thumbnail': 'md5:51bcef4a21936e7fea1ff4e06353f463',
+ 'thumbnail': r're:https://.+/.+\.jpg',
'episode': 'The Tohoku Shinkansen: Full Speed Ahead',
'series': 'Japan Railway Journal',
- 'modified_timestamp': 1694243656,
+ 'modified_timestamp': 1707217907,
'timestamp': 1681428600,
'release_timestamp': 1693883728,
'duration': 1679,
'upload_date': '20230413',
- 'modified_date': '20230909',
+ 'modified_date': '20240206',
'release_date': '20230905',
-
},
}, {
# video clip
@@ -188,15 +190,15 @@ class NhkVodIE(NhkBaseIE):
'ext': 'mp4',
'title': 'Dining with the Chef - Chef Saito\'s Family recipe: MENCHI-KATSU',
'description': 'md5:5aee4a9f9d81c26281862382103b0ea5',
- 'thumbnail': 'md5:d6a4d9b6e9be90aaadda0bcce89631ed',
+ 'thumbnail': r're:https://.+/.+\.jpg',
'series': 'Dining with the Chef',
'episode': 'Chef Saito\'s Family recipe: MENCHI-KATSU',
'duration': 148,
'upload_date': '20190816',
'release_date': '20230902',
'release_timestamp': 1693619292,
- 'modified_timestamp': 1694168033,
- 'modified_date': '20230908',
+ 'modified_timestamp': 1707217907,
+ 'modified_date': '20240206',
'timestamp': 1565997540,
},
}, {
@@ -208,7 +210,7 @@ class NhkVodIE(NhkBaseIE):
'title': 'Living in Japan - Tips for Travelers to Japan / Ramen Vending Machines',
'series': 'Living in Japan',
'description': 'md5:0a0e2077d8f07a03071e990a6f51bfab',
- 'thumbnail': 'md5:960622fb6e06054a4a1a0c97ea752545',
+ 'thumbnail': r're:https://.+/.+\.jpg',
'episode': 'Tips for Travelers to Japan / Ramen Vending Machines'
},
}, {
@@ -245,7 +247,7 @@ class NhkVodIE(NhkBaseIE):
'title': 'おはよう日本(7時台) - 10月8日放送',
'series': 'おはよう日本(7時台)',
'episode': '10月8日放送',
- 'thumbnail': 'md5:d733b1c8e965ab68fb02b2d347d0e9b4',
+ 'thumbnail': r're:https://.+/.+\.jpg',
'description': 'md5:9c1d6cbeadb827b955b20e99ab920ff0',
},
'skip': 'expires 2023-10-15',
@@ -255,17 +257,100 @@ class NhkVodIE(NhkBaseIE):
'info_dict': {
'id': 'nw_vod_v_en_3004_952_20230723091000_01_1690074552',
'ext': 'mp4',
- 'title': 'Barakan Discovers AMAMI OSHIMA: Isson\'s Treasure Island',
+ 'title': 'Barakan Discovers - AMAMI OSHIMA: Isson\'s Treasure Isla',
'description': 'md5:5db620c46a0698451cc59add8816b797',
- 'thumbnail': 'md5:67d9ff28009ba379bfa85ad1aaa0e2bd',
+ 'thumbnail': r're:https://.+/.+\.jpg',
'release_date': '20230905',
'timestamp': 1690103400,
'duration': 2939,
'release_timestamp': 1693898699,
- 'modified_timestamp': 1698057495,
- 'modified_date': '20231023',
'upload_date': '20230723',
+ 'modified_timestamp': 1707217907,
+ 'modified_date': '20240206',
+ 'episode': 'AMAMI OSHIMA: Isson\'s Treasure Isla',
+ 'series': 'Barakan Discovers',
},
+ }, {
+ # /ondemand/video/ url with alphabetical character in 5th position of id
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/video/9999a07/',
+ 'info_dict': {
+ 'id': 'nw_c_en_9999-a07',
+ 'ext': 'mp4',
+ 'episode': 'Mini-Dramas on SDGs: Ep 1 Close the Gender Gap [Director\'s Cut]',
+ 'series': 'Mini-Dramas on SDGs',
+ 'modified_date': '20240206',
+ 'title': 'Mini-Dramas on SDGs - Mini-Dramas on SDGs: Ep 1 Close the Gender Gap [Director\'s Cut]',
+ 'description': 'md5:3f9dcb4db22fceb675d90448a040d3f6',
+ 'timestamp': 1621962360,
+ 'duration': 189,
+ 'release_date': '20230903',
+ 'modified_timestamp': 1707217907,
+ 'upload_date': '20210525',
+ 'thumbnail': r're:https://.+/.+\.jpg',
+ 'release_timestamp': 1693713487,
+ },
+ }, {
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/video/9999d17/',
+ 'info_dict': {
+ 'id': 'nw_c_en_9999-d17',
+ 'ext': 'mp4',
+ 'title': 'Flowers of snow blossom - The 72 Pentads of Yamato',
+ 'description': 'Today’s focus: Snow',
+ 'release_timestamp': 1693792402,
+ 'release_date': '20230904',
+ 'upload_date': '20220128',
+ 'timestamp': 1643370960,
+ 'thumbnail': r're:https://.+/.+\.jpg',
+ 'duration': 136,
+ 'series': '',
+ 'modified_date': '20240206',
+ 'modified_timestamp': 1707217907,
+ },
+ }, {
+ # new /shows/ url format
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/2032307/',
+ 'info_dict': {
+ 'id': 'nw_vod_v_en_2032_307_20240321113000_01_1710990282',
+ 'ext': 'mp4',
+ 'title': 'Japanology Plus - 20th Anniversary Special Part 1',
+ 'description': 'md5:817d41fc8e54339ad2a916161ea24faf',
+ 'episode': '20th Anniversary Special Part 1',
+ 'series': 'Japanology Plus',
+ 'thumbnail': r're:https://.+/.+\.jpg',
+ 'duration': 1680,
+ 'timestamp': 1711020600,
+ 'upload_date': '20240321',
+ 'release_timestamp': 1711022683,
+ 'release_date': '20240321',
+ 'modified_timestamp': 1711031012,
+ 'modified_date': '20240321',
+ },
+ }, {
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/3020025/',
+ 'info_dict': {
+ 'id': 'nw_vod_v_en_3020_025_20230325144000_01_1679723944',
+ 'ext': 'mp4',
+ 'title': '100 Ideas to Save the World - Working Styles Evolve',
+ 'description': 'md5:9e6c7778eaaf4f7b4af83569649f84d9',
+ 'episode': 'Working Styles Evolve',
+ 'series': '100 Ideas to Save the World',
+ 'thumbnail': r're:https://.+/.+\.jpg',
+ 'duration': 899,
+ 'upload_date': '20230325',
+ 'timestamp': 1679755200,
+ 'release_date': '20230905',
+ 'release_timestamp': 1693880540,
+ 'modified_date': '20240206',
+ 'modified_timestamp': 1707217907,
+ },
+ }, {
+ # new /shows/audio/ url format
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/audio/livinginjapan-20231001-1/',
+ 'only_matching': True,
+ }, {
+ # valid url even if can't be found in wild; support needed for clip entries extraction
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/9999o80/',
+ 'only_matching': True,
}]
def _real_extract(self, url):
@@ -273,18 +358,21 @@ class NhkVodIE(NhkBaseIE):
class NhkVodProgramIE(NhkBaseIE):
- _VALID_URL = rf'{NhkBaseIE._BASE_URL_REGEX}/program{NhkBaseIE._TYPE_REGEX}(?P\w+)(?:.+?\btype=(?Pclip|(?:radio|tv)Episode))?'
+ _VALID_URL = rf'''(?x)
+ {NhkBaseIE._BASE_URL_REGEX}(?:shows|tv)/
+ (?:(?Paudio)/programs/)?(?P\w+)/?
+ (?:\?(?:[^#]+&)?type=(?Pclip|(?:radio|tv)Episode))?'''
_TESTS = [{
# video program episodes
- 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/program/video/sumo',
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/sumo/',
'info_dict': {
'id': 'sumo',
'title': 'GRAND SUMO Highlights',
'description': 'md5:fc20d02dc6ce85e4b72e0273aa52fdbf',
},
- 'playlist_mincount': 0,
+ 'playlist_mincount': 1,
}, {
- 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/program/video/japanrailway',
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/japanrailway/',
'info_dict': {
'id': 'japanrailway',
'title': 'Japan Railway Journal',
@@ -293,40 +381,68 @@ class NhkVodProgramIE(NhkBaseIE):
'playlist_mincount': 12,
}, {
# video program clips
- 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/program/video/japanrailway/?type=clip',
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/japanrailway/?type=clip',
'info_dict': {
'id': 'japanrailway',
'title': 'Japan Railway Journal',
'description': 'md5:ea39d93af7d05835baadf10d1aae0e3f',
},
- 'playlist_mincount': 5,
- }, {
- 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/program/video/10yearshayaomiyazaki/',
- 'only_matching': True,
+ 'playlist_mincount': 12,
}, {
# audio program
- 'url': 'https://www3.nhk.or.jp/nhkworld/en/ondemand/program/audio/listener/',
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/audio/programs/livinginjapan/',
+ 'info_dict': {
+ 'id': 'livinginjapan',
+ 'title': 'Living in Japan',
+ 'description': 'md5:665bb36ec2a12c5a7f598ee713fc2b54',
+ },
+ 'playlist_mincount': 12,
+ }, {
+ # /tv/ program url
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/tv/designtalksplus/',
+ 'info_dict': {
+ 'id': 'designtalksplus',
+ 'title': 'DESIGN TALKS plus',
+ 'description': 'md5:47b3b3a9f10d4ac7b33b53b70a7d2837',
+ },
+ 'playlist_mincount': 20,
+ }, {
+ 'url': 'https://www3.nhk.or.jp/nhkworld/en/shows/10yearshayaomiyazaki/',
'only_matching': True,
}]
+ @classmethod
+ def suitable(cls, url):
+ return False if NhkVodIE.suitable(url) else super().suitable(url)
+
+ def _extract_meta_from_class_elements(self, class_values, html):
+ for class_value in class_values:
+ if value := clean_html(get_element_by_class(class_value, html)):
+ return value
+
def _real_extract(self, url):
lang, m_type, program_id, episode_type = self._match_valid_url(url).group('lang', 'type', 'id', 'episode_type')
episodes = self._call_api(
- program_id, lang, m_type == 'video', False, episode_type == 'clip')
+ program_id, lang, m_type != 'audio', False, episode_type == 'clip')
- entries = []
- for episode in episodes:
- episode_path = episode.get('url')
- if not episode_path:
- continue
- entries.append(self._extract_episode_info(
- urljoin(url, episode_path), episode))
+ def entries():
+ for episode in episodes:
+ if episode_path := episode.get('url'):
+ yield self._extract_episode_info(urljoin(url, episode_path), episode)
html = self._download_webpage(url, program_id)
- program_title = clean_html(get_element_by_class('p-programDetail__title', html))
- program_description = clean_html(get_element_by_class('p-programDetail__text', html))
+ program_title = self._extract_meta_from_class_elements([
+ 'p-programDetail__title', # /ondemand/program/
+ 'pProgramHero__logoText', # /shows/
+ 'tAudioProgramMain__title', # /shows/audio/programs/
+ 'p-program-name'], html) # /tv/
+ program_description = self._extract_meta_from_class_elements([
+ 'p-programDetail__text', # /ondemand/program/
+ 'pProgramHero__description', # /shows/
+ 'tAudioProgramMain__info', # /shows/audio/programs/
+ 'p-program-description'], html) # /tv/
- return self.playlist_result(entries, program_id, program_title, program_description)
+ return self.playlist_result(entries(), program_id, program_title, program_description)
class NhkForSchoolBangumiIE(InfoExtractor):
diff --git a/yt-dlp/yt_dlp/extractor/patreon.py b/yt-dlp/yt_dlp/extractor/patreon.py
index d2ddb72cd4..d4f822f52d 100644
--- a/yt-dlp/yt_dlp/extractor/patreon.py
+++ b/yt-dlp/yt_dlp/extractor/patreon.py
@@ -92,7 +92,7 @@ class PatreonIE(PatreonBaseIE):
'thumbnail': 're:^https?://.*$',
'upload_date': '20150211',
'description': 'md5:8af6425f50bd46fbf29f3db0fc3a8364',
- 'uploader_id': 'TraciJHines',
+ 'uploader_id': '@TraciHinesMusic',
'categories': ['Entertainment'],
'duration': 282,
'view_count': int,
@@ -106,8 +106,10 @@ class PatreonIE(PatreonBaseIE):
'availability': 'public',
'channel_follower_count': int,
'playable_in_embed': True,
- 'uploader_url': 'http://www.youtube.com/user/TraciJHines',
+ 'uploader_url': 'https://www.youtube.com/@TraciHinesMusic',
'comment_count': int,
+ 'channel_is_verified': True,
+ 'chapters': 'count:4',
},
'params': {
'noplaylist': True,
@@ -176,6 +178,27 @@ class PatreonIE(PatreonBaseIE):
'uploader_url': 'https://www.patreon.com/thenormies',
},
'skip': 'Patron-only content',
+ }, {
+ # dead vimeo and embed URLs, need to extract post_file
+ 'url': 'https://www.patreon.com/posts/hunter-x-hunter-34007913',
+ 'info_dict': {
+ 'id': '34007913',
+ 'ext': 'mp4',
+ 'title': 'Hunter x Hunter | Kurapika DESTROYS Uvogin!!!',
+ 'like_count': int,
+ 'uploader': 'YaBoyRoshi',
+ 'timestamp': 1581636833,
+ 'channel_url': 'https://www.patreon.com/yaboyroshi',
+ 'thumbnail': r're:^https?://.*$',
+ 'tags': ['Hunter x Hunter'],
+ 'uploader_id': '14264111',
+ 'comment_count': int,
+ 'channel_follower_count': int,
+ 'description': 'Kurapika is a walking cheat code!',
+ 'upload_date': '20200213',
+ 'channel_id': '2147162',
+ 'uploader_url': 'https://www.patreon.com/yaboyroshi',
+ },
}]
def _real_extract(self, url):
@@ -250,20 +273,13 @@ class PatreonIE(PatreonBaseIE):
v_url = url_or_none(compat_urllib_parse_unquote(
self._search_regex(r'(https(?:%3A%2F%2F|://)player\.vimeo\.com.+app_id(?:=|%3D)+\d+)', embed_html, 'vimeo url', fatal=False)))
if v_url:
- return {
- **info,
- '_type': 'url_transparent',
- 'url': VimeoIE._smuggle_referrer(v_url, 'https://patreon.com'),
- 'ie_key': 'Vimeo',
- }
+ v_url = VimeoIE._smuggle_referrer(v_url, 'https://patreon.com')
+ if self._request_webpage(v_url, video_id, 'Checking Vimeo embed URL', fatal=False, errnote=False):
+ return self.url_result(v_url, VimeoIE, url_transparent=True, **info)
embed_url = try_get(attributes, lambda x: x['embed']['url'])
- if embed_url:
- return {
- **info,
- '_type': 'url',
- 'url': embed_url,
- }
+ if embed_url and self._request_webpage(embed_url, video_id, 'Checking embed URL', fatal=False, errnote=False):
+ return self.url_result(embed_url, **info)
post_file = traverse_obj(attributes, 'post_file')
if post_file:
diff --git a/yt-dlp/yt_dlp/extractor/tiktok.py b/yt-dlp/yt_dlp/extractor/tiktok.py
index 295e14932a..3f5261ad96 100644
--- a/yt-dlp/yt_dlp/extractor/tiktok.py
+++ b/yt-dlp/yt_dlp/extractor/tiktok.py
@@ -155,6 +155,7 @@ class TikTokBaseIE(InfoExtractor):
'locale': 'en',
'ac2': 'wifi5g',
'uoo': '1',
+ 'carrier_region': 'US',
'op_region': 'US',
'build_number': self._APP_INFO['app_version'],
'region': 'US',
diff --git a/yt-dlp/yt_dlp/extractor/vk.py b/yt-dlp/yt_dlp/extractor/vk.py
index e4a78c2977..7e3a3a9a98 100644
--- a/yt-dlp/yt_dlp/extractor/vk.py
+++ b/yt-dlp/yt_dlp/extractor/vk.py
@@ -707,6 +707,7 @@ class VKWallPostIE(VKBaseIE):
class VKPlayBaseIE(InfoExtractor):
+ _BASE_URL_RE = r'https?://(?:vkplay\.live|live\.vkplay\.ru)/'
_RESOLUTIONS = {
'tiny': '256x144',
'lowest': '426x240',
@@ -765,7 +766,7 @@ class VKPlayBaseIE(InfoExtractor):
class VKPlayIE(VKPlayBaseIE):
- _VALID_URL = r'https?://vkplay\.live/(?P[^/#?]+)/record/(?P[a-f0-9-]+)'
+ _VALID_URL = rf'{VKPlayBaseIE._BASE_URL_RE}(?P[^/#?]+)/record/(?P[\da-f-]+)'
_TESTS = [{
'url': 'https://vkplay.live/zitsmann/record/f5e6e3b5-dc52-4d14-965d-0680dd2882da',
'info_dict': {
@@ -776,13 +777,16 @@ class VKPlayIE(VKPlayBaseIE):
'uploader_id': '13159830',
'release_timestamp': 1683461378,
'release_date': '20230507',
- 'thumbnail': r're:https://images.vkplay.live/public_video_stream/record/f5e6e3b5-dc52-4d14-965d-0680dd2882da/preview\?change_time=\d+',
+ 'thumbnail': r're:https://[^/]+/public_video_stream/record/f5e6e3b5-dc52-4d14-965d-0680dd2882da/preview',
'duration': 10608,
'view_count': int,
'like_count': int,
'categories': ['Atomic Heart'],
},
'params': {'skip_download': 'm3u8'},
+ }, {
+ 'url': 'https://live.vkplay.ru/lebwa/record/33a4e4ce-e3ef-49db-bb14-f006cc6fabc9/records',
+ 'only_matching': True,
}]
def _real_extract(self, url):
@@ -802,7 +806,7 @@ class VKPlayIE(VKPlayBaseIE):
class VKPlayLiveIE(VKPlayBaseIE):
- _VALID_URL = r'https?://vkplay\.live/(?P[^/#?]+)/?(?:[#?]|$)'
+ _VALID_URL = rf'{VKPlayBaseIE._BASE_URL_RE}(?P[^/#?]+)/?(?:[#?]|$)'
_TESTS = [{
'url': 'https://vkplay.live/bayda',
'info_dict': {
@@ -813,7 +817,7 @@ class VKPlayLiveIE(VKPlayBaseIE):
'uploader_id': '12279401',
'release_timestamp': 1687209962,
'release_date': '20230619',
- 'thumbnail': r're:https://images.vkplay.live/public_video_stream/12279401/preview\?change_time=\d+',
+ 'thumbnail': r're:https://[^/]+/public_video_stream/12279401/preview',
'view_count': int,
'concurrent_view_count': int,
'like_count': int,
@@ -822,6 +826,9 @@ class VKPlayLiveIE(VKPlayBaseIE):
},
'skip': 'livestream',
'params': {'skip_download': True},
+ }, {
+ 'url': 'https://live.vkplay.ru/lebwa',
+ 'only_matching': True,
}]
def _real_extract(self, url):