base vpn android plugin
This commit is contained in:
@@ -19,4 +19,8 @@ dist
|
||||
|
||||
/android/.tauri
|
||||
/android/.gradle
|
||||
/android/build
|
||||
/android/build
|
||||
*jniLibs
|
||||
*uniffi
|
||||
*rollup.cache
|
||||
/android/gradle
|
||||
|
||||
@@ -15,3 +15,7 @@ thiserror = "2"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-plugin = { version = "2.5.4", features = ["build"] }
|
||||
|
||||
[features]
|
||||
mobile = []
|
||||
desktop = []
|
||||
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -10,6 +11,7 @@ android {
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
@@ -18,9 +20,19 @@ android {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
getByName("main") {
|
||||
// Добавляем папку с исходным кодом (где лежат твои uniffi .kt файлы)
|
||||
java.srcDirs("src/main/java")
|
||||
// Оставляем jniLibs для .so файлов
|
||||
jniLibs.srcDirs("src/main/jniLibs")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("net.java.dev.jna:jna:5.13.0@aar")
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.appcompat:appcompat:1.6.0")
|
||||
implementation(project(":tauri-android"))
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="app.netrunner.vpn">
|
||||
|
||||
<uses-permission android:name="android.permission.BIND_VPN_SERVICE" />
|
||||
|
||||
<application>
|
||||
<service
|
||||
android:name=".ExampleVpnService"
|
||||
android:name="app.netrunner.vpn.VpnPlugin"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package app.netrunner.vpn;
|
||||
import android.net.VpnService;
|
||||
|
||||
class VpnEngine : VpnService() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package app.netrunner.vpn
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import app.tauri.plugin.Plugin
|
||||
import app.tauri.plugin.Invoke
|
||||
import app.tauri.annotation.InvokeArg
|
||||
import app.tauri.annotation.Command
|
||||
import app.tauri.annotation.TauriPlugin
|
||||
import app.tauri.annotation.Permission
|
||||
import android.Manifest
|
||||
import app.netrunner.vpn.VpnController
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.content.Context
|
||||
import uniffi.netrunner_client.SessionManager
|
||||
import uniffi.netrunner_client.Session
|
||||
import uniffi.netrunner_client.NoHandle
|
||||
import android.net.VpnService as AndroidVpnService
|
||||
import app.netrunner.vpn.TunInterface
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.io.Closeable
|
||||
|
||||
@Parcelize
|
||||
data class TunnelConfig(
|
||||
val address: String,
|
||||
val prefix: Int,
|
||||
val dns: String,
|
||||
val mtu: Int
|
||||
) : Parcelable
|
||||
|
||||
|
||||
class TunInterface : Closeable {
|
||||
|
||||
private var vpnInterface: ParcelFileDescriptor? = null
|
||||
|
||||
fun establish(builder: AndroidVpnService.Builder, config: TunnelConfig): Int {
|
||||
// Принудительно закрываем текущий, если вдруг вызываем повторно
|
||||
close()
|
||||
|
||||
val descriptor = builder
|
||||
.addAddress(config.address, config.prefix)
|
||||
.addRoute("0.0.0.0", 0)
|
||||
.setMtu(config.mtu)
|
||||
.establish()
|
||||
|
||||
vpnInterface = descriptor
|
||||
return descriptor?.fd ?: -1
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
try {
|
||||
vpnInterface?.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
vpnInterface = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class VpnController(private val service: VpnService) {
|
||||
init {
|
||||
System.loadLibrary("netrunner_client")
|
||||
}
|
||||
|
||||
private var activeSession: Session? = null
|
||||
private val tunInterface = TunInterface()
|
||||
|
||||
fun startVpn(config: TunnelConfig, ip: String, port: Int) {
|
||||
val builder = service.Builder()
|
||||
|
||||
val fd = tunInterface.establish(builder, config)
|
||||
|
||||
if (fd != -1) {
|
||||
val manager = SessionManager(NoHandle)
|
||||
android.util.Log.d("VPN_DEBUG", "Starting session with FD: $fd")
|
||||
activeSession = manager.start("$ip:$port", fd)
|
||||
} else {
|
||||
android.util.Log.d("VPN_DEBUG", "Starting session with FD: $fd")
|
||||
}
|
||||
}
|
||||
|
||||
fun stopVpn() {
|
||||
activeSession?.stop()
|
||||
activeSession = null
|
||||
tunInterface.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class VpnService : AndroidVpnService() {
|
||||
private var controller: VpnController? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
android.util.Log.d("VPN_DEBUG", "VpnService: onCreate() executed")
|
||||
try {
|
||||
controller = VpnController(this)
|
||||
android.util.Log.d("VPN_DEBUG", "VpnService: VpnController initialized successfully")
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("VPN_DEBUG", "VpnService: CRITICAL - VpnController init failed", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
val action = intent?.action
|
||||
android.util.Log.d("VPN_DEBUG", "VpnService: onStartCommand() action='$action'")
|
||||
|
||||
when (action) {
|
||||
"START_VPN" -> {
|
||||
val ip = intent.getStringExtra("ip")
|
||||
val port = intent.getIntExtra("port", -1)
|
||||
android.util.Log.d("VPN_DEBUG", "VpnService: Extracting extras -> IP: '$ip', Port: $port")
|
||||
|
||||
val config = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
intent.getParcelableExtra("config", TunnelConfig::class.java)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
intent.getParcelableExtra("config")
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
android.util.Log.e("VPN_DEBUG", "VpnService: ERROR - TunnelConfig is NULL! Check if parcelable passed correctly.")
|
||||
} else {
|
||||
android.util.Log.d("VPN_DEBUG", "VpnService: Config received: $config. Calling controller.startVpn()...")
|
||||
controller?.startVpn(config, ip ?: "", port)
|
||||
}
|
||||
}
|
||||
"STOP_VPN" -> {
|
||||
android.util.Log.d("VPN_DEBUG", "VpnService: Stopping VPN...")
|
||||
controller?.stopVpn()
|
||||
stopSelf()
|
||||
}
|
||||
else -> {
|
||||
android.util.Log.w("VPN_DEBUG", "VpnService: Unknown action received: '$action'")
|
||||
}
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
controller?.stopVpn()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@InvokeArg
|
||||
class VpnArgs {
|
||||
var config: TunnelConfig? = null
|
||||
var ip: String = ""
|
||||
var port: Int = 0
|
||||
}
|
||||
|
||||
@TauriPlugin
|
||||
class VpnPlugin(private val activity: Activity) : Plugin(activity) {
|
||||
|
||||
@Command
|
||||
fun startVpn(invoke: Invoke) {
|
||||
android.util.Log.d("VPN_DEBUG", "Plugin: startVpn invoked")
|
||||
val args = invoke.parseArgs(VpnArgs::class.java)
|
||||
|
||||
|
||||
val intent = Intent(activity, VpnService::class.java).apply {
|
||||
action = "START_VPN"
|
||||
putExtra("ip", args.ip)
|
||||
putExtra("port", args.port)
|
||||
putExtra("config", args.config)
|
||||
}
|
||||
|
||||
android.util.Log.d("VPN_DEBUG", "Plugin: Starting VpnService...")
|
||||
val result = activity.startService(intent)
|
||||
|
||||
if (result == null) {
|
||||
android.util.Log.e("VPN_DEBUG", "Plugin: startService returned null (Service not found?)")
|
||||
} else {
|
||||
android.util.Log.d("VPN_DEBUG", "Plugin: startService triggered successfully")
|
||||
}
|
||||
invoke.resolve()
|
||||
}
|
||||
|
||||
@Command
|
||||
fun stopVpn(invoke: Invoke) {
|
||||
val intent = Intent(activity, VpnService::class.java).apply {
|
||||
action = "STOP_VPN"
|
||||
}
|
||||
activity.startService(intent)
|
||||
invoke.resolve()
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
const COMMANDS: &[&str] = &["ping"];
|
||||
// src-tauri/src/plugins/vpn-plugin/build.rs
|
||||
|
||||
const COMMANDS: &[&str] = &["start_tunnel", "stop_tunnel"];
|
||||
|
||||
fn main() {
|
||||
tauri_plugin::Builder::new(COMMANDS)
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export async function ping(value: string): Promise<string | null> {
|
||||
return await invoke<{value?: string}>('plugin:vpn|ping', {
|
||||
payload: {
|
||||
value,
|
||||
},
|
||||
}).then((r) => (r.value ? r.value : null));
|
||||
export interface TunnelConfig {
|
||||
address: string;
|
||||
prefix: number;
|
||||
dns: string;
|
||||
mtu: number;
|
||||
}
|
||||
|
||||
export async function startVpn(config: TunnelConfig, ip: string, port: number) {
|
||||
return await invoke("plugin:vpn|start_vpn", {
|
||||
config,
|
||||
ip,
|
||||
port,
|
||||
});
|
||||
}
|
||||
|
||||
export async function stopVpn() {
|
||||
return await invoke("plugin:vpn|stop_vpn");
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-ping"
|
||||
description = "Enables the ping command without any pre-configured scope."
|
||||
commands.allow = ["ping"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-ping"
|
||||
description = "Denies the ping command without any pre-configured scope."
|
||||
commands.deny = ["ping"]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-start-tunnel"
|
||||
description = "Enables the start_tunnel command without any pre-configured scope."
|
||||
commands.allow = ["start_tunnel"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-start-tunnel"
|
||||
description = "Denies the start_tunnel command without any pre-configured scope."
|
||||
commands.deny = ["start_tunnel"]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-stop-tunnel"
|
||||
description = "Enables the stop_tunnel command without any pre-configured scope."
|
||||
commands.allow = ["stop_tunnel"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-stop-tunnel"
|
||||
description = "Denies the stop_tunnel command without any pre-configured scope."
|
||||
commands.deny = ["stop_tunnel"]
|
||||
@@ -10,12 +10,12 @@
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:allow-ping`
|
||||
`vpn:allow-start-tunnel`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the ping command without any pre-configured scope.
|
||||
Enables the start_tunnel command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@@ -23,12 +23,12 @@ Enables the ping command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:deny-ping`
|
||||
`vpn:deny-start-tunnel`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the ping command without any pre-configured scope.
|
||||
Denies the start_tunnel command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
@@ -36,12 +36,38 @@ Denies the ping command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:vpn-control`
|
||||
`vpn:allow-stop-tunnel`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Allows access to VPN Service
|
||||
Enables the stop_tunnel command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:deny-stop-tunnel`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the stop_tunnel command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`vpn:allow-vpn-control`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Allows Vpn Control
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[[permission]]
|
||||
identifier = "vpn-control"
|
||||
description = "Allows access to VPN Service"
|
||||
name = "allow-vpn-control"
|
||||
commands = { allow = ["ping", "prepare_vpn", "start_vpn", "stop_vpn"] }
|
||||
identifier = "allow-vpn-control"
|
||||
description = "Allows Vpn Control"
|
||||
|
||||
[permission.commands]
|
||||
allow = ["start_vpn", "stop_vpn"]
|
||||
@@ -295,22 +295,34 @@
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Enables the ping command without any pre-configured scope.",
|
||||
"description": "Enables the start_tunnel command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-ping",
|
||||
"markdownDescription": "Enables the ping command without any pre-configured scope."
|
||||
"const": "allow-start-tunnel",
|
||||
"markdownDescription": "Enables the start_tunnel command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the ping command without any pre-configured scope.",
|
||||
"description": "Denies the start_tunnel command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-ping",
|
||||
"markdownDescription": "Denies the ping command without any pre-configured scope."
|
||||
"const": "deny-start-tunnel",
|
||||
"markdownDescription": "Denies the start_tunnel command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Allows access to VPN Service",
|
||||
"description": "Enables the stop_tunnel command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "vpn-control",
|
||||
"markdownDescription": "Allows access to VPN Service"
|
||||
"const": "allow-stop-tunnel",
|
||||
"markdownDescription": "Enables the stop_tunnel command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the stop_tunnel command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-stop-tunnel",
|
||||
"markdownDescription": "Denies the stop_tunnel command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Allows Vpn Control",
|
||||
"type": "string",
|
||||
"const": "allow-vpn-control",
|
||||
"markdownDescription": "Allows Vpn Control"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@tauri-apps/api':
|
||||
specifier: ^2.0.0
|
||||
version: 2.10.1
|
||||
devDependencies:
|
||||
'@rollup/plugin-typescript':
|
||||
specifier: ^12.0.0
|
||||
version: 12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3)
|
||||
rollup:
|
||||
specifier: ^4.9.6
|
||||
version: 4.59.0
|
||||
tslib:
|
||||
specifier: ^2.6.2
|
||||
version: 2.8.1
|
||||
typescript:
|
||||
specifier: ^5.3.3
|
||||
version: 5.9.3
|
||||
|
||||
packages:
|
||||
|
||||
'@rollup/plugin-typescript@12.3.0':
|
||||
resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.14.0||^3.0.0||^4.0.0
|
||||
tslib: '*'
|
||||
typescript: '>=3.7.0'
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
tslib:
|
||||
optional: true
|
||||
|
||||
'@rollup/pluginutils@5.3.0':
|
||||
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.59.0':
|
||||
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.59.0':
|
||||
resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.59.0':
|
||||
resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.59.0':
|
||||
resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
||||
resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.59.0':
|
||||
resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.59.0':
|
||||
resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.59.0':
|
||||
resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.59.0':
|
||||
resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.59.0':
|
||||
resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.59.0':
|
||||
resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.59.0':
|
||||
resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@tauri-apps/api@2.10.1':
|
||||
resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==}
|
||||
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
estree-walker@2.0.2:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
|
||||
function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
|
||||
hasown@2.0.2:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-core-module@2.16.1:
|
||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
|
||||
picomatch@4.0.3:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
resolve@1.22.11:
|
||||
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
hasBin: true
|
||||
|
||||
rollup@4.59.0:
|
||||
resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
supports-preserve-symlinks-flag@1.0.0:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
tslib@2.8.1:
|
||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||
|
||||
typescript@5.9.3:
|
||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
'@rollup/plugin-typescript@12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.59.0)
|
||||
resolve: 1.22.11
|
||||
typescript: 5.9.3
|
||||
optionalDependencies:
|
||||
rollup: 4.59.0
|
||||
tslib: 2.8.1
|
||||
|
||||
'@rollup/pluginutils@5.3.0(rollup@4.59.0)':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 4.0.3
|
||||
optionalDependencies:
|
||||
rollup: 4.59.0
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.59.0':
|
||||
optional: true
|
||||
|
||||
'@tauri-apps/api@2.10.1': {}
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
function-bind@1.1.2: {}
|
||||
|
||||
hasown@2.0.2:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
is-core-module@2.16.1:
|
||||
dependencies:
|
||||
hasown: 2.0.2
|
||||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
resolve@1.22.11:
|
||||
dependencies:
|
||||
is-core-module: 2.16.1
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
rollup@4.59.0:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.59.0
|
||||
'@rollup/rollup-android-arm64': 4.59.0
|
||||
'@rollup/rollup-darwin-arm64': 4.59.0
|
||||
'@rollup/rollup-darwin-x64': 4.59.0
|
||||
'@rollup/rollup-freebsd-arm64': 4.59.0
|
||||
'@rollup/rollup-freebsd-x64': 4.59.0
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.59.0
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.59.0
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.59.0
|
||||
'@rollup/rollup-linux-arm64-musl': 4.59.0
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.59.0
|
||||
'@rollup/rollup-linux-loong64-musl': 4.59.0
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.59.0
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.59.0
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.59.0
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.59.0
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.59.0
|
||||
'@rollup/rollup-linux-x64-gnu': 4.59.0
|
||||
'@rollup/rollup-linux-x64-musl': 4.59.0
|
||||
'@rollup/rollup-openbsd-x64': 4.59.0
|
||||
'@rollup/rollup-openharmony-arm64': 4.59.0
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.59.0
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.59.0
|
||||
'@rollup/rollup-win32-x64-gnu': 4.59.0
|
||||
'@rollup/rollup-win32-x64-msvc': 4.59.0
|
||||
fsevents: 2.3.3
|
||||
|
||||
supports-preserve-symlinks-flag@1.0.0: {}
|
||||
|
||||
tslib@2.8.1: {}
|
||||
|
||||
typescript@5.9.3: {}
|
||||
@@ -1,13 +1,20 @@
|
||||
use tauri::{AppHandle, command, Runtime};
|
||||
|
||||
use crate::models::*;
|
||||
use crate::Result;
|
||||
use crate::VpnExt;
|
||||
use crate::{models::*, Vpn, VpnInterface};
|
||||
use tauri::{command, AppHandle, Manager, Runtime};
|
||||
|
||||
#[command]
|
||||
pub(crate) async fn ping<R: Runtime>(
|
||||
pub(crate) fn start_vpn<R: Runtime>(
|
||||
app: AppHandle<R>,
|
||||
payload: PingRequest,
|
||||
) -> Result<PingResponse> {
|
||||
app.vpn().ping(payload)
|
||||
config: TunnelConfig,
|
||||
ip: String,
|
||||
port: i32,
|
||||
) -> crate::Result<()> {
|
||||
// Получаем состояние Vpn<R> и вызываем метод интерфейса
|
||||
eprintln!("--- [DEBUG] START_VPN COMMAND CALLED! ---");
|
||||
app.state::<Vpn<R>>().start_vpn(config, ip, port)
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub(crate) fn stop_vpn<R: Runtime>(app: AppHandle<R>) -> crate::Result<()> {
|
||||
// Получаем состояние Vpn<R> и вызываем метод интерфейса
|
||||
app.state::<Vpn<R>>().stop_vpn()
|
||||
}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
use crate::models::*;
|
||||
use crate::VpnInterface;
|
||||
use serde::de::DeserializeOwned;
|
||||
use tauri::{plugin::PluginApi, AppHandle, Runtime};
|
||||
|
||||
use crate::models::*;
|
||||
|
||||
// Инициализация для ПК
|
||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||
app: &AppHandle<R>,
|
||||
_api: PluginApi<R, C>,
|
||||
app: &AppHandle<R>,
|
||||
_api: PluginApi<R, C>,
|
||||
) -> crate::Result<Vpn<R>> {
|
||||
Ok(Vpn(app.clone()))
|
||||
Ok(Vpn(app.clone()))
|
||||
}
|
||||
|
||||
/// Access to the vpn APIs.
|
||||
pub struct Vpn<R: Runtime>(AppHandle<R>);
|
||||
|
||||
impl<R: Runtime> Vpn<R> {
|
||||
pub fn ping(&self, payload: PingRequest) -> crate::Result<PingResponse> {
|
||||
Ok(PingResponse {
|
||||
value: payload.value,
|
||||
})
|
||||
}
|
||||
impl<R: Runtime> VpnInterface<R> for Vpn<R> {
|
||||
fn start_vpn(&self, _config: TunnelConfig, _ip: String, _port: i32) -> crate::Result<()> {
|
||||
// Логика для ПК: например, запуск системного процесса
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_vpn(&self) -> crate::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::ops::Deref;
|
||||
use tauri::{
|
||||
plugin::{Builder, TauriPlugin},
|
||||
Manager, Runtime,
|
||||
plugin::{Builder, TauriPlugin},
|
||||
Manager, Runtime,
|
||||
};
|
||||
|
||||
pub use models::*;
|
||||
@@ -16,33 +17,40 @@ mod models;
|
||||
|
||||
pub use error::{Error, Result};
|
||||
|
||||
#[cfg(desktop)]
|
||||
use desktop::Vpn;
|
||||
#[cfg(mobile)]
|
||||
use mobile::Vpn;
|
||||
// В lib.rs
|
||||
pub trait VpnInterface<R: Runtime>: Send + Sync + 'static {
|
||||
fn start_vpn(&self, config: TunnelConfig, ip: String, port: i32) -> crate::Result<()>;
|
||||
fn stop_vpn(&self) -> crate::Result<()>;
|
||||
}
|
||||
pub struct Vpn<R: Runtime>(Box<dyn VpnInterface<R>>);
|
||||
|
||||
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the vpn APIs.
|
||||
pub trait VpnExt<R: Runtime> {
|
||||
fn vpn(&self) -> &Vpn<R>;
|
||||
impl<R: Runtime> Vpn<R> {
|
||||
pub fn new<I: VpnInterface<R>>(inner: I) -> Self {
|
||||
Self(Box::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Runtime, T: Manager<R>> crate::VpnExt<R> for T {
|
||||
fn vpn(&self) -> &Vpn<R> {
|
||||
self.state::<Vpn<R>>().inner()
|
||||
}
|
||||
impl<R: Runtime> Deref for Vpn<R> {
|
||||
type Target = dyn VpnInterface<R>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the plugin.
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("vpn")
|
||||
.invoke_handler(tauri::generate_handler![commands::ping])
|
||||
.setup(|app, api| {
|
||||
#[cfg(mobile)]
|
||||
let vpn = mobile::init(app, api)?;
|
||||
#[cfg(desktop)]
|
||||
let vpn = desktop::init(app, api)?;
|
||||
app.manage(vpn);
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
Builder::new("vpn")
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
commands::start_vpn,
|
||||
commands::stop_vpn
|
||||
])
|
||||
.setup(|app, api| {
|
||||
#[cfg(mobile)]
|
||||
let vpn_impl = mobile::init(app, api)?;
|
||||
#[cfg(desktop)]
|
||||
let vpn_impl = desktop::init(app, api)?;
|
||||
app.manage(Vpn::new(vpn_impl));
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -1,34 +1,43 @@
|
||||
use crate::models::*;
|
||||
use crate::VpnInterface;
|
||||
use serde::de::DeserializeOwned;
|
||||
use tauri::{
|
||||
plugin::{PluginApi, PluginHandle},
|
||||
AppHandle, Runtime,
|
||||
plugin::{PluginApi, PluginHandle},
|
||||
AppHandle, Runtime,
|
||||
};
|
||||
|
||||
use crate::models::*;
|
||||
#[cfg(target_os = "android")]
|
||||
const PLUGIN_IDENTIFIER: &str = "app.netrunner.vpn";
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
tauri::ios_plugin_binding!(init_plugin_vpn);
|
||||
|
||||
// initializes the Kotlin or Swift plugin classes
|
||||
pub fn init<R: Runtime, C: DeserializeOwned>(
|
||||
_app: &AppHandle<R>,
|
||||
api: PluginApi<R, C>,
|
||||
_app: &AppHandle<R>,
|
||||
api: PluginApi<R, C>,
|
||||
) -> crate::Result<Vpn<R>> {
|
||||
#[cfg(target_os = "android")]
|
||||
let handle = api.register_android_plugin("", "ExamplePlugin")?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let handle = api.register_ios_plugin(init_plugin_vpn)?;
|
||||
Ok(Vpn(handle))
|
||||
#[cfg(target_os = "android")]
|
||||
let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "VpnPlugin")?;
|
||||
#[cfg(target_os = "ios")]
|
||||
let handle = api.register_ios_plugin(init_plugin_vpn)?;
|
||||
Ok(Vpn(handle))
|
||||
}
|
||||
|
||||
/// Access to the vpn APIs.
|
||||
pub struct Vpn<R: Runtime>(PluginHandle<R>);
|
||||
|
||||
impl<R: Runtime> Vpn<R> {
|
||||
pub fn ping(&self, payload: PingRequest) -> crate::Result<PingResponse> {
|
||||
self
|
||||
.0
|
||||
.run_mobile_plugin("ping", payload)
|
||||
.map_err(Into::into)
|
||||
}
|
||||
impl<R: Runtime> VpnInterface<R> for Vpn<R> {
|
||||
fn start_vpn(&self, config: TunnelConfig, ip: String, port: i32) -> crate::Result<()> {
|
||||
self.send("startVpn", StartVpnRequest { config, ip, port })
|
||||
}
|
||||
|
||||
fn stop_vpn(&self) -> crate::Result<()> {
|
||||
self.send("stopVpn", StopVpnRequest {})
|
||||
}
|
||||
}
|
||||
|
||||
// Приватный метод для уменьшения дублирования кода
|
||||
impl<R: Runtime> Vpn<R> {
|
||||
fn send<S: serde::Serialize>(&self, cmd: &str, payload: S) -> crate::Result<()> {
|
||||
self.0.run_mobile_plugin(cmd, payload).map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TunnelConfig {
|
||||
pub address: String,
|
||||
pub prefix: i32, // Соответствует Int в Kotlin
|
||||
pub dns: String,
|
||||
pub mtu: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PingRequest {
|
||||
pub value: Option<String>,
|
||||
pub struct StartVpnRequest {
|
||||
pub config: TunnelConfig,
|
||||
pub ip: String,
|
||||
pub port: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PingResponse {
|
||||
pub value: Option<String>,
|
||||
}
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct StopVpnRequest {}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user