presave
This commit is contained in:
@@ -11,7 +11,11 @@ name = "netrunner_app"
|
||||
tauri-build = { version = "2.0.0", features = [] }
|
||||
|
||||
[dependencies]
|
||||
jni = "0.21"
|
||||
netrunner-client = { path = "../../client" }
|
||||
netrunner-core = { path = "../../core" }
|
||||
tauri = { version = "2.0.0", features = [] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
ndk-context = "0.1"
|
||||
log = "0.4"
|
||||
android_logger = "0.14"
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
fn main() {
|
||||
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
|
||||
println!("cargo:warning=MANIFEST_DIR is: {}", manifest_dir);
|
||||
|
||||
let path = std::path::Path::new(&manifest_dir).join("../../gen/arm64-v8a");
|
||||
println!(
|
||||
"cargo:warning=LINKER_SEARCH_PATH is: {:?}",
|
||||
path.canonicalize()
|
||||
);
|
||||
|
||||
println!("cargo:rustc-link-search=native={}", path.display());
|
||||
println!("cargo:rustc-link-lib=dylib=netrunner_client");
|
||||
|
||||
tauri_build::build();
|
||||
}
|
||||
|
||||
@@ -3,5 +3,11 @@
|
||||
"identifier": "default",
|
||||
"description": "Capability for the main window",
|
||||
"windows": ["main"],
|
||||
"permissions": ["core:default"]
|
||||
"permissions": [
|
||||
"core:default",
|
||||
{
|
||||
"identifier": "core:app:default",
|
||||
"allow": ["start_vpn_android"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod start_vpn_android;
|
||||
@@ -0,0 +1,56 @@
|
||||
use jni::errors::Error as JniError;
|
||||
use jni::objects::{JObject, JString, JValue};
|
||||
use tauri::command;
|
||||
|
||||
#[command]
|
||||
pub fn start_vpn_android(remote_address: String) -> Result<i32, String> {
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
let ctx = ndk_context::android_context();
|
||||
let vm_ptr = ctx.vm() as *mut jni::sys::JavaVM;
|
||||
|
||||
let vm = unsafe { jni::JavaVM::from_raw(vm_ptr) }.map_err(|e: JniError| e.to_string())?;
|
||||
|
||||
let mut env = vm
|
||||
.attach_current_thread()
|
||||
.map_err(|e: JniError| e.to_string())?;
|
||||
|
||||
let class_name = "com/netrunner/vpn/NetrunnerVpnService";
|
||||
let class = env
|
||||
.find_class(class_name)
|
||||
.map_err(|e: JniError| e.to_string())?;
|
||||
|
||||
let companion = env
|
||||
.get_static_field(
|
||||
class,
|
||||
"Companion",
|
||||
"Lcom/netrunner/vpn/NetrunnerVpnService$Companion;",
|
||||
)
|
||||
.map_err(|e: JniError| e.to_string())?
|
||||
.l()
|
||||
.map_err(|e: JniError| e.to_string())?;
|
||||
|
||||
let j_remote_addr = env
|
||||
.new_string(remote_address)
|
||||
.map_err(|e: JniError| e.to_string())?;
|
||||
|
||||
// Явное приведение контекста к JObject
|
||||
let context_obj = unsafe { JObject::from_raw(ctx.context() as *mut _) };
|
||||
|
||||
let result = env
|
||||
.call_method(
|
||||
companion,
|
||||
"startVpn",
|
||||
"(Landroid/app/Activity;Ljava/lang/String;)I",
|
||||
&[JValue::Object(&context_obj), JValue::Object(&j_remote_addr)],
|
||||
)
|
||||
.map_err(|e: JniError| e.to_string())?;
|
||||
|
||||
result.i().map_err(|e: JniError| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
Err("VPN доступен только на Android".into())
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
mod core;
|
||||
use core::start_vpn_android::start_vpn_android;
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
#[cfg(target_os = "android")]
|
||||
android_logger::init_once(
|
||||
android_logger::Config::default()
|
||||
.with_max_level(log::LevelFilter::Debug)
|
||||
.with_tag("NetrunnerRust"),
|
||||
);
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![start_vpn_android])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.netrunner.vpn
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.VpnService
|
||||
import android.os.ParcelFileDescriptor
|
||||
import uniffi.netrunner_client.SessionManager
|
||||
|
||||
class NetrunnerVpnService : VpnService() {
|
||||
|
||||
companion object {
|
||||
|
||||
private var vpnInterface: ParcelFileDescriptor? = null
|
||||
|
||||
fun start(activity: Activity): Int {
|
||||
val intent = VpnService.prepare(activity)
|
||||
|
||||
if (intent != null) {
|
||||
activity.startActivityForResult(intent, 1001)
|
||||
return -1
|
||||
}
|
||||
|
||||
return startVpn(activity)
|
||||
}
|
||||
@JvmStatic
|
||||
fun startVpn(activity: Activity, remoteAddress: String): Int {
|
||||
val builder = Builder()
|
||||
|
||||
builder.setSession("NetrunnerVPN")
|
||||
.addAddress("10.0.0.1", 32)
|
||||
.addRoute("0.0.0.0", 0)
|
||||
.setMtu(1500)
|
||||
|
||||
vpnInterface = builder.establish()
|
||||
val fd = vpnInterface?.fd ?: -1
|
||||
|
||||
if (fd != -1) {
|
||||
try {
|
||||
// 1. Создаем менеджер сессий
|
||||
val sessionManager = uniffi.netrunner_client.SessionManager()
|
||||
|
||||
// 2. Вызываем метод start, прокидывая адрес и дескриптор
|
||||
// Обратите внимание: метод .start() возвращает объект Session
|
||||
sessionManager.start(
|
||||
remoteAddress = remoteAddress, // Ваша пустая строка или адрес
|
||||
tunFd = fd
|
||||
)
|
||||
|
||||
Log.d("NetrunnerVPN", "Сессия успешно запущена с FD: $fd")
|
||||
} catch (e: Exception) {
|
||||
Log.e("NetrunnerVPN", "Ошибка при запуске Rust-сессии: ${e.message}")
|
||||
stop() // Закрываем интерфейс, если нативная часть не стартанула
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
return fd
|
||||
}
|
||||
fun stop() {
|
||||
vpnInterface?.close()
|
||||
vpnInterface = null
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user