Compare commits

..

1 Commits

Author SHA1 Message Date
chen08209
af361a086a Optimize startTun performance 2025-04-25 22:34:37 +08:00
19 changed files with 68 additions and 129 deletions

View File

@@ -245,6 +245,7 @@ abstract class ClashHandlerInterface with ClashInterface {
);
}
@override
Future<bool> crash() {
return invoke<bool>(

View File

@@ -71,9 +71,9 @@ class ClashService extends ClashHandlerInterface {
}
}, (error, stack) {
commonPrint.log(error.toString());
if (error is SocketException) {
if(error is SocketException){
globalState.showNotifier(error.toString());
// globalState.appController.restartCore();
globalState.appController.restartCore();
}
});
}

View File

@@ -16,8 +16,7 @@ const browserUa =
const packageName = "com.follow.clash";
final unixSocketPath = "/tmp/FlClashSocket_${Random().nextInt(10000)}.sock";
const helperPort = 47890;
const maxTextScale = 1.4;
const minTextScale = 0.8;
const helperTag = "2024125";
final baseInfoEdgeInsets = EdgeInsets.symmetric(
vertical: 16.ap,
horizontal: 16.ap,

View File

@@ -130,7 +130,7 @@ class Request {
if (response.statusCode != HttpStatus.ok) {
return false;
}
return (response.data as String) == globalState.helperToken;
return (response.data as String) == helperTag;
} catch (_) {
return false;
}

View File

@@ -396,9 +396,9 @@ class AppController {
handleExit() async {
try {
await updateStatus(false);
await proxy?.stopProxy();
await clashCore.shutdown();
await clashService?.destroy();
await proxy?.stopProxy();
await savePreferences();
} finally {
system.exit();
@@ -487,10 +487,10 @@ class AppController {
Future<void> _initCore() async {
final isInit = await clashCore.isInit;
if (!isInit) {
await clashCore.init();
await clashCore.setState(
globalState.getCoreState(),
);
await clashCore.init();
}
await applyProfile();
}

View File

@@ -123,13 +123,8 @@ class _ProxiesFragmentState extends ConsumerState<ProxiesFragment>
@override
Widget build(BuildContext context) {
final proxiesType = ref.watch(
proxiesStyleSettingProvider.select(
(state) => state.type,
),
);
ref.watch(themeSettingProvider.select((state) => state.textScale));
final proxiesType =
ref.watch(proxiesStyleSettingProvider.select((state) => state.type));
return switch (proxiesType) {
ProxiesType.tab => ProxiesTabFragment(
key: _proxiesTabKey,

View File

@@ -147,21 +147,22 @@ class _GeoDataListItemState extends State<GeoDataListItem> {
FutureBuilder<FileInfo>(
future: _getGeoFileLastModified(geoItem.fileName),
builder: (_, snapshot) {
final height = globalState.measure.bodyMediumHeight;
return SizedBox(
height: height,
child: snapshot.data == null
? SizedBox(
width: height,
height: height,
child: CircularProgressIndicator(
strokeWidth: 2,
height: 24,
child: FadeThroughBox(
key: Key("fade_box_${geoItem.label}"),
child: snapshot.data == null
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
: Text(
snapshot.data!.desc,
),
)
: Text(
snapshot.data!.desc,
style: context.textTheme.bodyMedium,
),
),
);
},
),

View File

@@ -526,8 +526,8 @@ class _TextScaleFactorItem extends ConsumerWidget {
data: _SliderDefaultsM3(context),
child: Slider(
padding: EdgeInsets.zero,
min: minTextScale,
max: maxTextScale,
min: 0.8,
max: 1.2,
value: textScale.scale,
onChanged: (value) {
ref.read(themeSettingProvider.notifier).updateState(

View File

@@ -27,7 +27,6 @@ Future<void> main() async {
await android?.init();
await window?.init(version);
globalState.isPre = const String.fromEnvironment("APP_ENV") != 'stable';
globalState.helperToken = const String.fromEnvironment("HELPER_TOKEN");
HttpOverrides.global = FlClashHttpOverrides();
runApp(ProviderScope(
child: const Application(),

View File

@@ -23,9 +23,9 @@ class ThemeManager extends ConsumerWidget {
final double textScaleFactor = max(
min(
textScale.enable ? textScale.scale : defaultTextScaleFactor,
maxTextScale,
1.2,
),
minTextScale,
0.8,
);
globalState.measure = Measure.of(context, textScaleFactor);

View File

@@ -127,7 +127,6 @@ class _EditorPageState extends ConsumerState<EditorPage> {
);
},
popup: CommonPopupMenu(
minWidth: 180,
items: [
PopupMenuItemData(
icon: Icons.search,
@@ -190,7 +189,7 @@ class _EditorPageState extends ConsumerState<EditorPage> {
shortcutsActivatorsBuilder: DefaultCodeShortcutsActivatorsBuilder(),
controller: _controller,
style: CodeEditorStyle(
fontSize: 14.ap,
fontSize: 14,
fontFamily: FontFamily.jetBrainsMono.value,
codeTheme: CodeHighlightTheme(
languages: {

View File

@@ -30,7 +30,6 @@ class GlobalState {
late Config config;
late AppState appState;
bool isPre = true;
String? helperToken;
late PackageInfo packageInfo;
Function? updateCurrentDelayDebounce;
late Measure measure;

View File

@@ -279,7 +279,7 @@ packages:
source: hosted
version: "0.3.4+2"
crypto:
dependency: "direct dev"
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"

View File

@@ -66,7 +66,6 @@ dev_dependencies:
riverpod_generator: ^2.6.3
custom_lint: ^0.7.0
riverpod_lint: ^2.6.3
crypto: ^3.0.3
flutter:
uses-material-design: true

View File

@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
version = 3
[[package]]
name = "addr2line"
@@ -284,7 +284,6 @@ dependencies = [
"anyhow",
"once_cell",
"serde",
"sha2",
"tokio",
"warp",
"windows-service",
@@ -823,17 +822,6 @@ dependencies = [
"digest",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"

View File

@@ -14,11 +14,10 @@ anyhow = "1.0.93"
warp = "0.3.7"
serde = { version = "1.0.215", features = ["derive"] }
once_cell = "1.20.2"
sha2 = "0.10.8"
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"
opt-level = "s"

View File

@@ -1,4 +0,0 @@
fn main() {
let version = std::env::var("TOKEN").unwrap_or_default();
println!("cargo:rustc-env=TOKEN={}", version);
}

View File

@@ -1,13 +1,11 @@
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::VecDeque;
use std::fs::File;
use std::io::{BufRead, Error, Read};
use std::{io, thread};
use std::io::BufRead;
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::{io, thread};
use warp::{Filter, Reply};
use serde::{Deserialize, Serialize};
use once_cell::sync::Lazy;
const LISTEN_PORT: u16 = 47890;
@@ -17,31 +15,10 @@ pub struct StartParams {
pub arg: String,
}
fn sha256_file(path: &str) -> Result<String, Error> {
let mut file = File::open(path)?;
let mut hasher = Sha256::new();
let mut buffer = [0; 4096];
loop {
let bytes_read = file.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
hasher.update(&buffer[..bytes_read]);
}
Ok(format!("{:x}", hasher.finalize()))
}
static LOGS: Lazy<Arc<Mutex<VecDeque<String>>>> =
Lazy::new(|| Arc::new(Mutex::new(VecDeque::with_capacity(100))));
static PROCESS: Lazy<Arc<Mutex<Option<std::process::Child>>>> =
Lazy::new(|| Arc::new(Mutex::new(None)));
static LOGS: Lazy<Arc<Mutex<VecDeque<String>>>> = Lazy::new(|| Arc::new(Mutex::new(VecDeque::with_capacity(100))));
static PROCESS: Lazy<Arc<Mutex<Option<std::process::Child>>>> = Lazy::new(|| Arc::new(Mutex::new(None)));
fn start(start_params: StartParams) -> impl Reply {
if sha256_file(start_params.path.as_str()).unwrap_or("".to_string()) != env!("TOKEN") {
return "Only FlClashCore is allowed to run.".to_string();
}
stop();
let mut process = PROCESS.lock().unwrap();
match Command::new(&start_params.path)
@@ -96,29 +73,38 @@ fn log_message(message: String) {
fn get_logs() -> impl Reply {
let log_buffer = LOGS.lock().unwrap();
let value = log_buffer
.iter()
.cloned()
.collect::<Vec<String>>()
.join("\n");
let value = log_buffer.iter().cloned().collect::<Vec<String>>().join("\n");
warp::reply::with_header(value, "Content-Type", "text/plain")
}
pub async fn run_service() -> anyhow::Result<()> {
let api_ping = warp::get().and(warp::path("ping")).map(|| env!("TOKEN"));
let api_ping = warp::get()
.and(warp::path("ping"))
.map(|| "2024125");
let api_start = warp::post()
.and(warp::path("start"))
.and(warp::body::json())
.map(|start_params: StartParams| start(start_params));
.map(|start_params: StartParams| {
start(start_params)
});
let api_stop = warp::post().and(warp::path("stop")).map(|| stop());
let api_stop = warp::post()
.and(warp::path("stop"))
.map(|| stop());
let api_logs = warp::get().and(warp::path("logs")).map(|| get_logs());
let api_logs = warp::get()
.and(warp::path("logs"))
.map(|| get_logs());
warp::serve(api_ping.or(api_start).or(api_stop).or(api_logs))
warp::serve(
api_ping
.or(api_start)
.or(api_stop)
.or(api_logs)
)
.run(([127, 0, 0, 1], LISTEN_PORT))
.await;
Ok(())
}
}

View File

@@ -5,7 +5,6 @@ import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:path/path.dart';
import 'package:crypto/crypto.dart';
enum Target {
windows,
@@ -196,16 +195,7 @@ class Build {
if (exitCode != 0 && name != null) throw "$name error";
}
static Future<String?> calcSha256(String filePath) async {
final file = File(filePath);
if (!await file.exists()) {
return null;
}
final stream = file.openRead();
return sha256.convert(await stream.reduce((a, b) => a + b)).toString();
}
static Future<List<String>> buildCore({
static buildCore({
required Mode mode,
required Target target,
Arch? arch,
@@ -219,8 +209,6 @@ class Build {
},
).toList();
final List<String> corePaths = [];
for (final item in items) {
final outFileDir = join(
outDir,
@@ -240,7 +228,6 @@ class Build {
outFileDir,
fileName,
);
corePaths.add(outPath);
final Map<String, String> env = {};
env["GOOS"] = item.target.os;
@@ -271,11 +258,9 @@ class Build {
workingDirectory: _coreDir,
);
}
return corePaths;
}
static buildHelper(Target target, String token) async {
static buildHelper(Target target) async {
await exec(
[
"cargo",
@@ -284,9 +269,6 @@ class Build {
"--features",
"windows-service",
],
environment: {
"TOKEN": token,
},
name: "build helper",
workingDirectory: _servicesDir,
);
@@ -296,15 +278,13 @@ class Build {
"release",
"helper${target.executableExtensionName}",
);
final targetPath = join(
outDir,
target.name,
"FlClashHelperService${target.executableExtensionName}",
);
final targetPath = join(outDir, target.name,
"FlClashHelperService${target.executableExtensionName}");
await File(outPath).copy(targetPath);
}
static List<String> getExecutable(String command) {
print(command);
return command.split(" ");
}
@@ -486,28 +466,26 @@ class BuildCommand extends Command {
throw "Invalid arch parameter";
}
final corePaths = await Build.buildCore(
await Build.buildCore(
target: target,
arch: arch,
mode: mode,
);
if (target == Target.windows) {
await Build.buildHelper(target);
}
if (out != "app") {
return;
}
switch (target) {
case Target.windows:
final token = await Build.calcSha256(corePaths.first);
if (token == null) {
throw "Core not exists";
}
Build.buildHelper(target, token);
_buildDistributor(
target: target,
targets: "exe,zip",
args:
" --description $archName --build-dart-define=HELPER_TOKEN=$token",
args: " --description $archName",
env: env,
);
return;