feat: Migrate PowerShell calls to Rust implementation

This commit is contained in:
xkeyC
2025-12-05 10:52:03 +08:00
parent 855ea1fe8f
commit f6676ed3d8
10 changed files with 1216 additions and 56 deletions

View File

@@ -98,15 +98,17 @@ class SystemHelper {
"$programDataPath\\Microsoft\\Windows\\Start Menu\\Programs\\Roberts Space Industries\\RSI Launcher.lnk";
final rsiLinkFile = File(rsiFilePath);
if (await rsiLinkFile.exists()) {
final r = await Process.run(SystemHelper.powershellPath, [
"(New-Object -ComObject WScript.Shell).CreateShortcut(\"$rsiFilePath\").targetpath",
]);
if (r.stdout.toString().contains("RSI Launcher.exe")) {
final start = r.stdout.toString().split("RSI Launcher.exe");
if (skipEXE) {
return start[0];
try {
final targetPath = await win32.resolveShortcut(lnkPath: rsiFilePath);
if (targetPath.contains("RSI Launcher.exe")) {
final start = targetPath.split("RSI Launcher.exe");
if (skipEXE) {
return start[0];
}
return "${start[0]}RSI Launcher.exe";
}
return "${start[0]}RSI Launcher.exe";
} catch (e) {
dPrint("resolveShortcut error: $e");
}
}
return "";
@@ -147,45 +149,78 @@ class SystemHelper {
}
static Future<int> getSystemMemorySizeGB() async {
final r = await Process.run(powershellPath, [
"(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb",
]);
return int.tryParse(r.stdout.toString().trim()) ?? 0;
try {
final memoryGb = await win32.getSystemMemorySizeGb();
return memoryGb.toInt();
} catch (e) {
dPrint("getSystemMemorySizeGB error: $e");
return 0;
}
}
static Future<String> getSystemCimInstance(String win32InstanceName, {pathName = "Name"}) async {
final r = await Process.run(powershellPath, ["(Get-CimInstance $win32InstanceName).$pathName"]);
return r.stdout.toString().trim();
// This method is deprecated, use getSystemInfo() instead
try {
final sysInfo = await win32.getSystemInfo();
if (win32InstanceName.contains("OperatingSystem")) {
return sysInfo.osName;
} else if (win32InstanceName.contains("Processor")) {
return sysInfo.cpuName;
} else if (win32InstanceName.contains("VideoController")) {
return sysInfo.gpuInfo;
} else if (win32InstanceName.contains("DiskDrive")) {
return sysInfo.diskInfo;
}
} catch (e) {
dPrint("getSystemCimInstance error: $e");
}
return "";
}
static Future<String> getSystemName() async {
final r = await Process.run(powershellPath, ["(Get-ComputerInfo | Select-Object -expand OsName)"]);
return r.stdout.toString().trim();
try {
final sysInfo = await win32.getSystemInfo();
return sysInfo.osName;
} catch (e) {
dPrint("getSystemName error: $e");
return "";
}
}
static Future<String> getCpuName() async {
final r = await Process.run(powershellPath, ["(Get-WmiObject -Class Win32_Processor).Name"]);
return r.stdout.toString().trim();
try {
final sysInfo = await win32.getSystemInfo();
return sysInfo.cpuName;
} catch (e) {
dPrint("getCpuName error: $e");
return "";
}
}
static Future<String> getGpuInfo() async {
const cmd = r"""
$adapterMemory = (Get-ItemProperty -Path "HKLM:\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0*" -Name "HardwareInformation.AdapterString", "HardwareInformation.qwMemorySize" -Exclude PSPath -ErrorAction SilentlyContinue)
foreach ($adapter in $adapterMemory) {
[PSCustomObject] @{
Model=$adapter."HardwareInformation.AdapterString"
"VRAM (GB)"=[math]::round($adapter."HardwareInformation.qwMemorySize"/1GB)
}
}
""";
final r = await Process.run(powershellPath, [cmd]);
return r.stdout.toString().trim();
try {
// Try registry first for more accurate VRAM info
final regInfo = await win32.getGpuInfoFromRegistry();
if (regInfo.isNotEmpty) {
return regInfo;
}
// Fallback to WMI
final sysInfo = await win32.getSystemInfo();
return sysInfo.gpuInfo;
} catch (e) {
dPrint("getGpuInfo error: $e");
return "";
}
}
static Future<String> getDiskInfo() async {
return (await Process.run(powershellPath, [
"Get-PhysicalDisk | format-table BusType,FriendlyName,Size",
])).stdout.toString().trim();
try {
final sysInfo = await win32.getSystemInfo();
return sysInfo.diskInfo;
} catch (e) {
dPrint("getDiskInfo error: $e");
return "";
}
}
static Future<int> getDirLen(String path, {List<String>? skipPath}) async {
@@ -212,11 +247,12 @@ foreach ($adapter in $adapterMemory) {
}
static Future<int> getNumberOfLogicalProcessors() async {
final cpuNumberResult = await Process.run(powershellPath, [
"(Get-WmiObject -Class Win32_Processor).NumberOfLogicalProcessors",
]);
if (cpuNumberResult.exitCode != 0) return 0;
return int.tryParse(cpuNumberResult.stdout.toString().trim()) ?? 0;
try {
return await win32.getNumberOfLogicalProcessors();
} catch (e) {
dPrint("getNumberOfLogicalProcessors error: $e");
return 0;
}
}
static Future<String?> getCpuAffinity() async {
@@ -244,10 +280,11 @@ foreach ($adapter in $adapterMemory) {
static Future openDir(dynamic path, {bool isFile = false}) async {
dPrint("SystemHelper.openDir path === $path");
if (Platform.isWindows) {
await Process.run(SystemHelper.powershellPath, [
"explorer.exe",
isFile ? "/select,$path" : "\"/select,\"$path\"\"",
]);
try {
await win32.openDirWithExplorer(path: path.toString(), isFile: isFile);
} catch (e) {
dPrint("openDir error: $e");
}
}
}

View File

@@ -8,9 +8,8 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
part 'webview_api.freezed.dart';
// These functions are ignored because they are not marked as `pub`: `handle_command`, `load_app_icon`, `run_webview_loop`, `send_command`
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `UserEvent`, `WebViewCommand`, `WebViewInstance`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `WebViewCommand`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt`
/// Create a new WebView window and return its ID
String webviewCreate({required WebViewConfiguration config}) =>

View File

@@ -7,7 +7,7 @@ import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
// These functions are ignored because they are not marked as `pub`: `get_process_path`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `fmt`, `fmt`
Future<void> sendNotify({
String? summary,
@@ -21,6 +21,35 @@ Future<void> sendNotify({
appId: appId,
);
/// Get system memory size in GB
Future<BigInt> getSystemMemorySizeGb() =>
RustLib.instance.api.crateApiWin32ApiGetSystemMemorySizeGb();
/// Get number of logical processors
Future<int> getNumberOfLogicalProcessors() =>
RustLib.instance.api.crateApiWin32ApiGetNumberOfLogicalProcessors();
/// Get all system information at once
Future<SystemInfo> getSystemInfo() =>
RustLib.instance.api.crateApiWin32ApiGetSystemInfo();
/// Get GPU info from registry (more accurate VRAM)
Future<String> getGpuInfoFromRegistry() =>
RustLib.instance.api.crateApiWin32ApiGetGpuInfoFromRegistry();
/// Resolve shortcut (.lnk) file to get target path
Future<String> resolveShortcut({required String lnkPath}) =>
RustLib.instance.api.crateApiWin32ApiResolveShortcut(lnkPath: lnkPath);
/// Open file explorer and select file/folder
Future<void> openDirWithExplorer({
required String path,
required bool isFile,
}) => RustLib.instance.api.crateApiWin32ApiOpenDirWithExplorer(
path: path,
isFile: isFile,
);
Future<bool> setForegroundWindow({required String windowName}) => RustLib
.instance
.api
@@ -59,3 +88,32 @@ class ProcessInfo {
name == other.name &&
path == other.path;
}
/// System information struct
class SystemInfo {
final String osName;
final String cpuName;
final String gpuInfo;
final String diskInfo;
const SystemInfo({
required this.osName,
required this.cpuName,
required this.gpuInfo,
required this.diskInfo,
});
@override
int get hashCode =>
osName.hashCode ^ cpuName.hashCode ^ gpuInfo.hashCode ^ diskInfo.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is SystemInfo &&
runtimeType == other.runtimeType &&
osName == other.osName &&
cpuName == other.cpuName &&
gpuInfo == other.gpuInfo &&
diskInfo == other.diskInfo;
}

View File

@@ -71,7 +71,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.11.1';
@override
int get rustContentHash => -1082688871;
int get rustContentHash => 1317751362;
static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig(
@@ -102,6 +102,10 @@ abstract class RustLibApi extends BaseApi {
String? pathSuffix,
});
Future<String> crateApiWin32ApiGetGpuInfoFromRegistry();
Future<int> crateApiWin32ApiGetNumberOfLogicalProcessors();
Future<List<ProcessInfo>> crateApiWin32ApiGetProcessListByName({
required String processName,
});
@@ -114,6 +118,10 @@ abstract class RustLibApi extends BaseApi {
required String asarPath,
});
Future<SystemInfo> crateApiWin32ApiGetSystemInfo();
Future<BigInt> crateApiWin32ApiGetSystemMemorySizeGb();
Future<void> crateApiOrtApiLoadTranslationModel({
required String modelPath,
required String modelKey,
@@ -121,6 +129,11 @@ abstract class RustLibApi extends BaseApi {
required bool useXnnpack,
});
Future<void> crateApiWin32ApiOpenDirWithExplorer({
required String path,
required bool isFile,
});
Future<void> crateApiUnp4KApiP4KClose();
Future<void> crateApiUnp4KApiP4KExtractToDisk({
@@ -138,6 +151,8 @@ abstract class RustLibApi extends BaseApi {
Future<void> crateApiUnp4KApiP4KOpen({required String p4KPath});
Future<String> crateApiWin32ApiResolveShortcut({required String lnkPath});
Future<void> crateApiAsarApiRsiLauncherAsarDataWriteMainJs({
required RsiLauncherAsarData that,
required List<int> content,
@@ -402,6 +417,59 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ["urls", "pathSuffix"],
);
@override
Future<String> crateApiWin32ApiGetGpuInfoFromRegistry() {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
return wire.wire__crate__api__win32_api__get_gpu_info_from_registry(
port_,
);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_String,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiWin32ApiGetGpuInfoFromRegistryConstMeta,
argValues: [],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiWin32ApiGetGpuInfoFromRegistryConstMeta =>
const TaskConstMeta(
debugName: "get_gpu_info_from_registry",
argNames: [],
);
@override
Future<int> crateApiWin32ApiGetNumberOfLogicalProcessors() {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
return wire
.wire__crate__api__win32_api__get_number_of_logical_processors(
port_,
);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_u_32,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiWin32ApiGetNumberOfLogicalProcessorsConstMeta,
argValues: [],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiWin32ApiGetNumberOfLogicalProcessorsConstMeta =>
const TaskConstMeta(
debugName: "get_number_of_logical_processors",
argNames: [],
);
@override
Future<List<ProcessInfo>> crateApiWin32ApiGetProcessListByName({
required String processName,
@@ -492,6 +560,50 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ["asarPath"],
);
@override
Future<SystemInfo> crateApiWin32ApiGetSystemInfo() {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
return wire.wire__crate__api__win32_api__get_system_info(port_);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_system_info,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiWin32ApiGetSystemInfoConstMeta,
argValues: [],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiWin32ApiGetSystemInfoConstMeta =>
const TaskConstMeta(debugName: "get_system_info", argNames: []);
@override
Future<BigInt> crateApiWin32ApiGetSystemMemorySizeGb() {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
return wire.wire__crate__api__win32_api__get_system_memory_size_gb(
port_,
);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_u_64,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiWin32ApiGetSystemMemorySizeGbConstMeta,
argValues: [],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiWin32ApiGetSystemMemorySizeGbConstMeta =>
const TaskConstMeta(debugName: "get_system_memory_size_gb", argNames: []);
@override
Future<void> crateApiOrtApiLoadTranslationModel({
required String modelPath,
@@ -531,6 +643,39 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ["modelPath", "modelKey", "quantizationSuffix", "useXnnpack"],
);
@override
Future<void> crateApiWin32ApiOpenDirWithExplorer({
required String path,
required bool isFile,
}) {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
var arg0 = cst_encode_String(path);
var arg1 = cst_encode_bool(isFile);
return wire.wire__crate__api__win32_api__open_dir_with_explorer(
port_,
arg0,
arg1,
);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_unit,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiWin32ApiOpenDirWithExplorerConstMeta,
argValues: [path, isFile],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiWin32ApiOpenDirWithExplorerConstMeta =>
const TaskConstMeta(
debugName: "open_dir_with_explorer",
argNames: ["path", "isFile"],
);
@override
Future<void> crateApiUnp4KApiP4KClose() {
return handler.executeNormal(
@@ -679,6 +824,31 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
TaskConstMeta get kCrateApiUnp4KApiP4KOpenConstMeta =>
const TaskConstMeta(debugName: "p4k_open", argNames: ["p4KPath"]);
@override
Future<String> crateApiWin32ApiResolveShortcut({required String lnkPath}) {
return handler.executeNormal(
NormalTask(
callFfi: (port_) {
var arg0 = cst_encode_String(lnkPath);
return wire.wire__crate__api__win32_api__resolve_shortcut(
port_,
arg0,
);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_String,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kCrateApiWin32ApiResolveShortcutConstMeta,
argValues: [lnkPath],
apiImpl: this,
),
);
}
TaskConstMeta get kCrateApiWin32ApiResolveShortcutConstMeta =>
const TaskConstMeta(debugName: "resolve_shortcut", argNames: ["lnkPath"]);
@override
Future<void> crateApiAsarApiRsiLauncherAsarDataWriteMainJs({
required RsiLauncherAsarData that,
@@ -1667,6 +1837,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
}
@protected
SystemInfo dco_decode_system_info(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
final arr = raw as List<dynamic>;
if (arr.length != 4)
throw Exception('unexpected arr length: expect 4 but see ${arr.length}');
return SystemInfo(
osName: dco_decode_String(arr[0]),
cpuName: dco_decode_String(arr[1]),
gpuInfo: dco_decode_String(arr[2]),
diskInfo: dco_decode_String(arr[3]),
);
}
@protected
int dco_decode_u_16(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -2081,6 +2265,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
}
@protected
SystemInfo sse_decode_system_info(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
var var_osName = sse_decode_String(deserializer);
var var_cpuName = sse_decode_String(deserializer);
var var_gpuInfo = sse_decode_String(deserializer);
var var_diskInfo = sse_decode_String(deserializer);
return SystemInfo(
osName: var_osName,
cpuName: var_cpuName,
gpuInfo: var_gpuInfo,
diskInfo: var_diskInfo,
);
}
@protected
int sse_decode_u_16(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -2556,6 +2755,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_opt_list_prim_u_8_strict(self.data, serializer);
}
@protected
void sse_encode_system_info(SystemInfo self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_String(self.osName, serializer);
sse_encode_String(self.cpuName, serializer);
sse_encode_String(self.gpuInfo, serializer);
sse_encode_String(self.diskInfo, serializer);
}
@protected
void sse_encode_u_16(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs

View File

@@ -126,6 +126,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
RustHttpResponse dco_decode_rust_http_response(dynamic raw);
@protected
SystemInfo dco_decode_system_info(dynamic raw);
@protected
int dco_decode_u_16(dynamic raw);
@@ -274,6 +277,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
RustHttpResponse sse_decode_rust_http_response(SseDeserializer deserializer);
@protected
SystemInfo sse_decode_system_info(SseDeserializer deserializer);
@protected
int sse_decode_u_16(SseDeserializer deserializer);
@@ -588,6 +594,17 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
wireObj.data = cst_encode_opt_list_prim_u_8_strict(apiObj.data);
}
@protected
void cst_api_fill_to_wire_system_info(
SystemInfo apiObj,
wire_cst_system_info wireObj,
) {
wireObj.os_name = cst_encode_String(apiObj.osName);
wireObj.cpu_name = cst_encode_String(apiObj.cpuName);
wireObj.gpu_info = cst_encode_String(apiObj.gpuInfo);
wireObj.disk_info = cst_encode_String(apiObj.diskInfo);
}
@protected
void cst_api_fill_to_wire_web_view_configuration(
WebViewConfiguration apiObj,
@@ -829,6 +846,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
SseSerializer serializer,
);
@protected
void sse_encode_system_info(SystemInfo self, SseSerializer serializer);
@protected
void sse_encode_u_16(int self, SseSerializer serializer);
@@ -1036,6 +1056,34 @@ class RustLibWire implements BaseWire {
)
>();
void wire__crate__api__win32_api__get_gpu_info_from_registry(int port_) {
return _wire__crate__api__win32_api__get_gpu_info_from_registry(port_);
}
late final _wire__crate__api__win32_api__get_gpu_info_from_registryPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_gpu_info_from_registry',
);
late final _wire__crate__api__win32_api__get_gpu_info_from_registry =
_wire__crate__api__win32_api__get_gpu_info_from_registryPtr
.asFunction<void Function(int)>();
void wire__crate__api__win32_api__get_number_of_logical_processors(
int port_,
) {
return _wire__crate__api__win32_api__get_number_of_logical_processors(
port_,
);
}
late final _wire__crate__api__win32_api__get_number_of_logical_processorsPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_number_of_logical_processors',
);
late final _wire__crate__api__win32_api__get_number_of_logical_processors =
_wire__crate__api__win32_api__get_number_of_logical_processorsPtr
.asFunction<void Function(int)>();
void wire__crate__api__win32_api__get_process_list_by_name(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> process_name,
@@ -1117,6 +1165,30 @@ class RustLibWire implements BaseWire {
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
>();
void wire__crate__api__win32_api__get_system_info(int port_) {
return _wire__crate__api__win32_api__get_system_info(port_);
}
late final _wire__crate__api__win32_api__get_system_infoPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_system_info',
);
late final _wire__crate__api__win32_api__get_system_info =
_wire__crate__api__win32_api__get_system_infoPtr
.asFunction<void Function(int)>();
void wire__crate__api__win32_api__get_system_memory_size_gb(int port_) {
return _wire__crate__api__win32_api__get_system_memory_size_gb(port_);
}
late final _wire__crate__api__win32_api__get_system_memory_size_gbPtr =
_lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64)>>(
'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_system_memory_size_gb',
);
late final _wire__crate__api__win32_api__get_system_memory_size_gb =
_wire__crate__api__win32_api__get_system_memory_size_gbPtr
.asFunction<void Function(int)>();
void wire__crate__api__ort_api__load_translation_model(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> model_path,
@@ -1159,6 +1231,36 @@ class RustLibWire implements BaseWire {
)
>();
void wire__crate__api__win32_api__open_dir_with_explorer(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> path,
bool is_file,
) {
return _wire__crate__api__win32_api__open_dir_with_explorer(
port_,
path,
is_file,
);
}
late final _wire__crate__api__win32_api__open_dir_with_explorerPtr =
_lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Int64,
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
ffi.Bool,
)
>
>(
'frbgen_starcitizen_doctor_wire__crate__api__win32_api__open_dir_with_explorer',
);
late final _wire__crate__api__win32_api__open_dir_with_explorer =
_wire__crate__api__win32_api__open_dir_with_explorerPtr
.asFunction<
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>, bool)
>();
void wire__crate__api__unp4k_api__p4k_close(int port_) {
return _wire__crate__api__unp4k_api__p4k_close(port_);
}
@@ -1278,6 +1380,30 @@ class RustLibWire implements BaseWire {
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
>();
void wire__crate__api__win32_api__resolve_shortcut(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> lnk_path,
) {
return _wire__crate__api__win32_api__resolve_shortcut(port_, lnk_path);
}
late final _wire__crate__api__win32_api__resolve_shortcutPtr =
_lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Int64,
ffi.Pointer<wire_cst_list_prim_u_8_strict>,
)
>
>(
'frbgen_starcitizen_doctor_wire__crate__api__win32_api__resolve_shortcut',
);
late final _wire__crate__api__win32_api__resolve_shortcut =
_wire__crate__api__win32_api__resolve_shortcutPtr
.asFunction<
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)
>();
void wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js(
int port_,
ffi.Pointer<wire_cst_rsi_launcher_asar_data> that,
@@ -2321,6 +2447,16 @@ final class wire_cst_rust_http_response extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> data;
}
final class wire_cst_system_info extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> os_name;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> cpu_name;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> gpu_info;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> disk_info;
}
final class wire_cst_web_view_navigation_state extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> url;

View File

@@ -4,7 +4,8 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:starcitizen_doctor/common/rust/api/webview_api.dart' as rust_webview;
import 'package:starcitizen_doctor/common/rust/api/webview_api.dart'
as rust_webview;
import 'package:starcitizen_doctor/common/utils/log.dart';
typedef OnWebMessageCallback = void Function(String message);
@@ -76,7 +77,9 @@ class RustWebViewController {
Future<void> _loadScripts() async {
try {
_localizationScript = await rootBundle.loadString('assets/web_script.js');
_requestInterceptorScript = await rootBundle.loadString('assets/request_interceptor.js');
_requestInterceptorScript = await rootBundle.loadString(
'assets/request_interceptor.js',
);
} catch (e) {
dPrint("Failed to load scripts: $e");
}
@@ -286,12 +289,16 @@ class RustWebViewController {
}
/// 添加导航完成回调(用于在页面加载完成后注入脚本)
void addOnNavigationCompletedCallback(OnNavigationCompletedCallback callback) {
void addOnNavigationCompletedCallback(
OnNavigationCompletedCallback callback,
) {
_navigationCompletedCallbacks.add(callback);
}
/// 移除导航完成回调
void removeOnNavigationCompletedCallback(OnNavigationCompletedCallback callback) {
void removeOnNavigationCompletedCallback(
OnNavigationCompletedCallback callback,
) {
_navigationCompletedCallbacks.remove(callback);
}
@@ -320,7 +327,9 @@ class RustWebViewController {
/// 更新翻译词典
void updateReplaceWords(List<Map<String, String>> words, bool enableCapture) {
final jsonWords = json.encode(words);
executeScript("WebLocalizationUpdateReplaceWords($jsonWords, $enableCapture)");
executeScript(
"WebLocalizationUpdateReplaceWords($jsonWords, $enableCapture)",
);
}
/// 执行 RSI 登录脚本