mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-03 01:25:37 +00:00
feat(mobile): add embedded runtime and managed network updates (#2532)
* feat(mobile): add embedded iOS runtime API Add a thin panic-safe C ABI crate for embedding no-TUN instances on iOS. Expose lifecycle, status, JSON-RPC, string ownership, and error handling. Build device and simulator XCFramework static libraries on macOS. Add exact named-instance deletion to the iOS and Android wrappers. Cover wrapper lifecycle and the port-forward patch flow on host targets. * fix(gateway): recover TCP port-forward listeners Release an unusable TCP port-forward listener after an accept failure. Retry binding until the forward is cancelled. Keep the old listener released while rebinding so mobile sockets can recover. Expose opt-in iOS diagnostics for listener and connection events. Trace configuration removal and adapter shutdown. Add tests for recovery, release-before-rebind, and cancellation. * feat(web): persist incremental managed config patches Add a revision-CAS PATCH contract for managed configs while keeping the existing Full PUT path for compatibility and recovery. Apply Full and Patch mutations with their revision in one SQLite transaction. Reject ownership conflicts and invalidate revisions on alternate web-owned writes. Document limits, failure semantics, rollout order, and verification. Cover delta updates, conflicts, idempotency, and transaction rollback. * feat(web): apply managed config patches to live sessions Carry Patch fences and touched instance IDs into live sessions. Reconcile only those instances when the applied revision matches the Patch base. Fall back to Full reconciliation for gaps and restarts. Invalidate the applied revision around every direct runtime mutation. Fence revision advancement with the runtime cache epoch so stale reconcile rounds cannot overwrite a newer invalidation. Require deletion responses to confirm each requested instance before advancing the revision. Raise the managed PUT and PATCH body limit to 32 MiB and return typed conflicts for publisher recovery. * fix(core): retry transient accepted TCP errors Keep TCP tunnel listeners alive when an accepted socket fails during upgrade with a retryable connection-state error. Share the retryable I/O classifier with the socket listener. Cover a rejected connection followed by success and propagation of permanent errors. * feat(core): add internal Peer Relay edge projection Derive the local advertised OSPF row from physical adjacency and transport-authenticated credential relay coverage. Keep full local adjacency only in the temporary SPF snapshot so direct destinations retain a fallback route. Leave Peer Relay disabled at the public configuration seam. A follow-up change can expose the preference without coupling route projection to credential reauthorization. feat(config): expose Peer Relay routing preference Add prefer_peer_relay to public protobuf, TOML, management patch, and hosted runtime surfaces. Read the preference from live peer context so runtime config updates take effect. Refresh authenticated peer metadata when the option is enabled. Cover dynamic enable and disable in a five-node, dual-admin credential topology, including forwarded relay coverage and local fallback.
This commit is contained in:
@@ -73,6 +73,14 @@ object EasyTierJNI {
|
||||
*/
|
||||
@JvmStatic external fun retainNetworkInstance(instanceNames: Array<String>?): Int
|
||||
|
||||
/**
|
||||
* 停止指定的网络实例,其他实例不受影响
|
||||
* @param instanceName 要停止的实例名称,不存在时为 no-op
|
||||
* @return 0 表示成功,-1 表示失败
|
||||
* @throws RuntimeException 当操作失败时抛出异常
|
||||
*/
|
||||
@JvmStatic external fun deleteNetworkInstance(instanceName: String): Int
|
||||
|
||||
/**
|
||||
* 收集网络信息
|
||||
* @param maxLength 最大返回条目数
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
//! - `parseConfig(config)`: validate TOML config text.
|
||||
//! - `runNetworkInstance(config)`: start a local network instance.
|
||||
//! - `retainNetworkInstance(instanceNames)`: retain named instances and stop the rest.
|
||||
//! - `deleteNetworkInstance(instanceName)`: stop exactly one named instance.
|
||||
//! - `listInstances()`: return running instance names and IDs as JSON.
|
||||
//! - `collectNetworkInfos()`: return running instance info as a JSON string.
|
||||
//! - `callJsonRpc(...)`: call an exposed EasyTier RPC service with JSON payload.
|
||||
@@ -106,6 +107,23 @@ pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance(
|
||||
network_api::retain_network_instance_jni(env, class, instance_names)
|
||||
}
|
||||
|
||||
/// Stop exactly one named network instance without affecting other instances.
|
||||
///
|
||||
/// Java signature:
|
||||
/// `EasyTierJNI.deleteNetworkInstance(instanceName: String): Int`
|
||||
///
|
||||
/// An unknown name is a no-op. On failure this returns `-1` and throws
|
||||
/// `RuntimeException`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_deleteNetworkInstance(
|
||||
env: JNIEnv,
|
||||
class: JClass,
|
||||
instance_name: JString,
|
||||
) -> jint {
|
||||
logger::init();
|
||||
network_api::delete_network_instance_jni(env, class, instance_name)
|
||||
}
|
||||
|
||||
/// Collect running network instance information.
|
||||
///
|
||||
/// Java signature:
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::{ffi::CStr, ptr};
|
||||
|
||||
use easytier::proto::api::manage::{NetworkInstanceRunningInfo, NetworkInstanceRunningInfoMap};
|
||||
use easytier_ffi::{
|
||||
KeyValuePair, collect_network_infos, free_string, list_instance, parse_config,
|
||||
retain_network_instance, run_network_instance, set_tun_fd,
|
||||
KeyValuePair, collect_network_infos, delete_network_instance, free_string, list_instance,
|
||||
parse_config, retain_network_instance, run_network_instance, set_tun_fd,
|
||||
};
|
||||
use jni::JNIEnv;
|
||||
use jni::objects::{JClass, JObjectArray, JString};
|
||||
@@ -76,6 +76,30 @@ pub(crate) fn run_network_instance_jni(mut env: JNIEnv, _class: JClass, config:
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn delete_network_instance_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
instance_name: JString,
|
||||
) -> jint {
|
||||
let instance_name = match jstring_to_cstring(&mut env, &instance_name) {
|
||||
Ok(name) => name,
|
||||
Err(error) => {
|
||||
throw_exception(&mut env, &format!("Invalid instance name: {error}"));
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
let instance_names = [instance_name.as_ptr()];
|
||||
unsafe {
|
||||
let result = delete_network_instance(instance_names.as_ptr(), instance_names.len());
|
||||
if result != 0
|
||||
&& let Some(error) = get_last_error()
|
||||
{
|
||||
throw_exception(&mut env, &error);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn retain_network_instance_jni(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
|
||||
Reference in New Issue
Block a user