mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-06 17:59:11 +00:00
fix android vpn permission grant (#2023)
* fix android vpn permission grant * fix url input behaviour
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
"core:tray:allow-set-show-menu-on-left-click",
|
||||
"core:tray:allow-set-tooltip",
|
||||
"vpnservice:allow-ping",
|
||||
"vpnservice:allow-get-vpn-status",
|
||||
"vpnservice:allow-prepare-vpn",
|
||||
"vpnservice:allow-start-vpn",
|
||||
"vpnservice:allow-stop-vpn",
|
||||
@@ -47,4 +48,4 @@
|
||||
"os:allow-platform",
|
||||
"os:allow-locale"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +206,16 @@ async fn update_network_config_state(
|
||||
.parse()
|
||||
.map_err(|e: uuid::Error| e.to_string())?;
|
||||
let client_manager = get_client_manager!()?;
|
||||
if !disabled {
|
||||
let cfg = client_manager
|
||||
.handle_get_network_config(app.clone(), instance_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let toml_config = cfg.gen_config().map_err(|e| e.to_string())?;
|
||||
client_manager
|
||||
.pre_run_network_instance_hook(&app, &toml_config)
|
||||
.await?;
|
||||
}
|
||||
client_manager
|
||||
.handle_update_network_state(app.clone(), instance_id, disabled)
|
||||
.await
|
||||
@@ -215,6 +225,10 @@ async fn update_network_config_state(
|
||||
client_manager
|
||||
.post_stop_network_instances_hook(&app)
|
||||
.await?;
|
||||
} else {
|
||||
client_manager
|
||||
.post_run_network_instance_hook(&app, &instance_id)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -830,7 +844,7 @@ mod manager {
|
||||
cfg: &easytier::common::config::TomlConfigLoader,
|
||||
) -> Result<(), String> {
|
||||
let instance_id = cfg.get_id();
|
||||
app.emit("pre_run_network_instance", instance_id)
|
||||
app.emit("pre_run_network_instance", instance_id.to_string())
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
@@ -867,20 +881,21 @@ mod manager {
|
||||
let app_clone = app.clone();
|
||||
let instance_id_clone = *instance_id;
|
||||
tokio::spawn(async move {
|
||||
let instance_id_str = instance_id_clone.to_string();
|
||||
loop {
|
||||
match event_receiver.recv().await {
|
||||
Ok(easytier::common::global_ctx::GlobalCtxEvent::DhcpIpv4Changed(_, _)) => {
|
||||
let _ = app_clone.emit("dhcp_ip_changed", instance_id_clone);
|
||||
let _ = app_clone.emit("dhcp_ip_changed", &instance_id_str);
|
||||
}
|
||||
Ok(easytier::common::global_ctx::GlobalCtxEvent::ProxyCidrsUpdated(_, _)) => {
|
||||
let _ = app_clone.emit("proxy_cidrs_updated", instance_id_clone);
|
||||
let _ = app_clone.emit("proxy_cidrs_updated", &instance_id_str);
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(tokio::sync::broadcast::error::RecvError::Closed) => {
|
||||
break;
|
||||
}
|
||||
Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => {
|
||||
let _ = app_clone.emit("event_lagged", instance_id_clone);
|
||||
let _ = app_clone.emit("event_lagged", &instance_id_str);
|
||||
event_receiver = event_receiver.resubscribe();
|
||||
}
|
||||
}
|
||||
@@ -892,7 +907,7 @@ mod manager {
|
||||
|
||||
self.storage.enabled_networks.insert(*instance_id);
|
||||
|
||||
app.emit("post_run_network_instance", instance_id)
|
||||
app.emit("post_run_network_instance", instance_id.to_string())
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
@@ -971,20 +986,26 @@ mod manager {
|
||||
.network_configs
|
||||
.get(&uuid)
|
||||
.map(|i| i.value().1.clone());
|
||||
if config.is_none() {
|
||||
let Some(config) = config else {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let toml_config = config.gen_config()?;
|
||||
self.pre_run_network_instance_hook(&app, &toml_config)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(e))?;
|
||||
client
|
||||
.run_network_instance(
|
||||
BaseController::default(),
|
||||
RunNetworkInstanceRequest {
|
||||
inst_id: None,
|
||||
config,
|
||||
config: Some(config),
|
||||
overwrite: false,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
self.storage.enabled_networks.insert(uuid);
|
||||
self.post_run_network_instance_hook(&app, &uuid)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!(e))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
@@ -93,6 +93,7 @@ declare global {
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||
const syncMobileVpnService: typeof import('./composables/mobile_vpn')['syncMobileVpnService']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
@@ -217,6 +218,7 @@ declare module 'vue' {
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
|
||||
readonly syncMobileVpnService: UnwrapRef<typeof import('./composables/mobile_vpn')['syncMobileVpnService']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Event, listen } from "@tauri-apps/api/event";
|
||||
import { type } from "@tauri-apps/plugin-os";
|
||||
import { NetworkTypes } from "easytier-frontend-lib"
|
||||
import { Utils } from "easytier-frontend-lib";
|
||||
|
||||
const EVENTS = Object.freeze({
|
||||
SAVE_CONFIGS: 'save_configs',
|
||||
@@ -17,39 +18,71 @@ function onSaveConfigs(event: Event<NetworkTypes.NetworkConfig[]>) {
|
||||
localStorage.setItem('networkList', JSON.stringify(event.payload.map((config) => NetworkTypes.normalizeNetworkConfig(config))));
|
||||
}
|
||||
|
||||
async function onPreRunNetworkInstance(event: Event<string>) {
|
||||
function normalizeInstanceIdPayload(payload: unknown): string {
|
||||
if (typeof payload === 'string') {
|
||||
return payload
|
||||
}
|
||||
|
||||
if (payload && typeof payload === 'object') {
|
||||
const uuid = payload as Partial<Utils.UUID>
|
||||
if (
|
||||
typeof uuid.part1 === 'number'
|
||||
&& typeof uuid.part2 === 'number'
|
||||
&& typeof uuid.part3 === 'number'
|
||||
&& typeof uuid.part4 === 'number'
|
||||
) {
|
||||
return Utils.UuidToStr(uuid as Utils.UUID)
|
||||
}
|
||||
}
|
||||
|
||||
if (payload == null) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const fallback = String(payload)
|
||||
return fallback === '[object Object]' ? '' : fallback
|
||||
}
|
||||
|
||||
async function onPreRunNetworkInstance(event: Event<unknown>) {
|
||||
const instanceId = normalizeInstanceIdPayload(event.payload)
|
||||
console.log(`Received event '${EVENTS.PRE_RUN_NETWORK_INSTANCE}', raw payload:`, event.payload, 'normalized:', instanceId)
|
||||
if (type() === 'android') {
|
||||
await prepareVpnService(event.payload);
|
||||
await prepareVpnService(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
async function onPostRunNetworkInstance(event: Event<string>) {
|
||||
async function onPostRunNetworkInstance(event: Event<unknown>) {
|
||||
const instanceId = normalizeInstanceIdPayload(event.payload)
|
||||
console.log(`Received event '${EVENTS.POST_RUN_NETWORK_INSTANCE}', raw payload:`, event.payload, 'normalized:', instanceId)
|
||||
if (type() === 'android') {
|
||||
await onNetworkInstanceChange(event.payload);
|
||||
await onNetworkInstanceChange(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
async function onVpnServiceStop(event: Event<string>) {
|
||||
await onNetworkInstanceChange(event.payload);
|
||||
async function onVpnServiceStop(event: Event<unknown>) {
|
||||
console.log(`Received event '${EVENTS.VPN_SERVICE_STOP}', raw payload:`, event.payload)
|
||||
await syncMobileVpnService();
|
||||
}
|
||||
|
||||
async function onDhcpIpChanged(event: Event<string>) {
|
||||
console.log(`Received event '${EVENTS.DHCP_IP_CHANGED}' for instance: ${event.payload}`);
|
||||
async function onDhcpIpChanged(event: Event<unknown>) {
|
||||
const instanceId = normalizeInstanceIdPayload(event.payload)
|
||||
console.log(`Received event '${EVENTS.DHCP_IP_CHANGED}' for instance: ${instanceId}`);
|
||||
if (type() === 'android') {
|
||||
await onNetworkInstanceChange(event.payload);
|
||||
await onNetworkInstanceChange(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
async function onProxyCidrsUpdated(event: Event<string>) {
|
||||
console.log(`Received event '${EVENTS.PROXY_CIDRS_UPDATED}' for instance: ${event.payload}`);
|
||||
async function onProxyCidrsUpdated(event: Event<unknown>) {
|
||||
const instanceId = normalizeInstanceIdPayload(event.payload)
|
||||
console.log(`Received event '${EVENTS.PROXY_CIDRS_UPDATED}' for instance: ${instanceId}`);
|
||||
if (type() === 'android') {
|
||||
await onNetworkInstanceChange(event.payload);
|
||||
await onNetworkInstanceChange(instanceId);
|
||||
}
|
||||
}
|
||||
|
||||
async function onEventLagged(event: Event<string>) {
|
||||
async function onEventLagged(event: Event<unknown>) {
|
||||
if (type() === 'android') {
|
||||
await onNetworkInstanceChange(event.payload);
|
||||
await onNetworkInstanceChange(normalizeInstanceIdPayload(event.payload));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { NetworkTypes } from 'easytier-frontend-lib'
|
||||
import { addPluginListener } from '@tauri-apps/api/core'
|
||||
import { Utils } from 'easytier-frontend-lib'
|
||||
import { prepare_vpn, start_vpn, stop_vpn } from 'tauri-plugin-vpnservice-api'
|
||||
import { get_vpn_status, prepare_vpn, start_vpn, stop_vpn } from 'tauri-plugin-vpnservice-api'
|
||||
|
||||
type Route = NetworkTypes.Route
|
||||
|
||||
@@ -24,6 +24,53 @@ const curVpnStatus: vpnStatus = {
|
||||
dns: undefined,
|
||||
}
|
||||
|
||||
async function requestVpnPermission() {
|
||||
console.log('prepare vpn')
|
||||
const prepare_ret = await prepare_vpn()
|
||||
console.log('prepare vpn', JSON.stringify((prepare_ret)))
|
||||
if (prepare_ret?.errorMsg?.length) {
|
||||
throw new Error(prepare_ret.errorMsg)
|
||||
}
|
||||
|
||||
const granted = prepare_ret?.granted ?? true
|
||||
if (!granted) {
|
||||
console.info('vpn permission request was denied or dismissed')
|
||||
}
|
||||
|
||||
return granted
|
||||
}
|
||||
|
||||
function resetVpnConfigStatus() {
|
||||
curVpnStatus.ipv4Addr = undefined
|
||||
curVpnStatus.ipv4Cidr = undefined
|
||||
curVpnStatus.routes = []
|
||||
curVpnStatus.dns = undefined
|
||||
}
|
||||
|
||||
function syncVpnStatusFromNative(status: Awaited<ReturnType<typeof get_vpn_status>>) {
|
||||
curVpnStatus.running = status?.running ?? false
|
||||
if (!curVpnStatus.running) {
|
||||
resetVpnConfigStatus()
|
||||
return
|
||||
}
|
||||
|
||||
const ipv4WithCidr = status?.ipv4Addr
|
||||
if (ipv4WithCidr?.length) {
|
||||
const [ipv4Addr, cidr] = ipv4WithCidr.split('/')
|
||||
curVpnStatus.ipv4Addr = ipv4Addr
|
||||
|
||||
const parsedCidr = Number(cidr)
|
||||
curVpnStatus.ipv4Cidr = Number.isInteger(parsedCidr) ? parsedCidr : undefined
|
||||
}
|
||||
else {
|
||||
curVpnStatus.ipv4Addr = undefined
|
||||
curVpnStatus.ipv4Cidr = undefined
|
||||
}
|
||||
|
||||
curVpnStatus.routes = [...(status?.routes ?? [])]
|
||||
curVpnStatus.dns = status?.dns ?? undefined
|
||||
}
|
||||
|
||||
async function waitVpnStatus(target_status: boolean, timeout_sec: number) {
|
||||
const start_time = Date.now()
|
||||
while (curVpnStatus.running !== target_status) {
|
||||
@@ -34,18 +81,19 @@ async function waitVpnStatus(target_status: boolean, timeout_sec: number) {
|
||||
}
|
||||
}
|
||||
|
||||
async function doStopVpn() {
|
||||
if (!curVpnStatus.running) {
|
||||
async function doStopVpn(force = false) {
|
||||
const wasRunning = curVpnStatus.running
|
||||
if (!force && !wasRunning) {
|
||||
return
|
||||
}
|
||||
console.log('stop vpn')
|
||||
const stop_ret = await stop_vpn()
|
||||
console.log('stop vpn', JSON.stringify((stop_ret)))
|
||||
await waitVpnStatus(false, 3)
|
||||
if (wasRunning) {
|
||||
await waitVpnStatus(false, 3)
|
||||
}
|
||||
|
||||
curVpnStatus.ipv4Addr = undefined
|
||||
curVpnStatus.routes = []
|
||||
curVpnStatus.dns = undefined
|
||||
resetVpnConfigStatus()
|
||||
}
|
||||
|
||||
async function doStartVpn(ipv4Addr: string, cidr: number, routes: string[], dns?: string) {
|
||||
@@ -54,19 +102,32 @@ async function doStartVpn(ipv4Addr: string, cidr: number, routes: string[], dns?
|
||||
}
|
||||
|
||||
console.log('start vpn service', ipv4Addr, cidr, routes, dns)
|
||||
const start_ret = await start_vpn({
|
||||
const request = {
|
||||
ipv4Addr: `${ipv4Addr}/${cidr}`,
|
||||
routes,
|
||||
dns,
|
||||
disallowedApplications: ['com.kkrainbow.easytier'],
|
||||
mtu: 1300,
|
||||
})
|
||||
}
|
||||
|
||||
let start_ret = await start_vpn(request)
|
||||
console.log('start vpn response', JSON.stringify(start_ret))
|
||||
if (start_ret?.errorMsg === 'need_prepare') {
|
||||
const granted = await requestVpnPermission()
|
||||
if (!granted) {
|
||||
throw new Error('vpn_permission_denied')
|
||||
}
|
||||
start_ret = await start_vpn(request)
|
||||
console.log('start vpn retry response', JSON.stringify(start_ret))
|
||||
}
|
||||
|
||||
if (start_ret?.errorMsg?.length) {
|
||||
throw new Error(start_ret.errorMsg)
|
||||
}
|
||||
await waitVpnStatus(true, 3)
|
||||
|
||||
curVpnStatus.ipv4Addr = ipv4Addr
|
||||
curVpnStatus.ipv4Cidr = cidr
|
||||
curVpnStatus.routes = routes
|
||||
curVpnStatus.dns = dns
|
||||
}
|
||||
@@ -75,13 +136,16 @@ async function onVpnServiceStart(payload: any) {
|
||||
console.log('vpn service start', JSON.stringify(payload))
|
||||
curVpnStatus.running = true
|
||||
if (payload.fd) {
|
||||
setTunFd(payload.fd)
|
||||
await setTunFd(payload.fd).catch((e) => {
|
||||
console.error('set tun fd failed', e)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function onVpnServiceStop(payload: any) {
|
||||
console.log('vpn service stop', JSON.stringify(payload))
|
||||
curVpnStatus.running = false
|
||||
resetVpnConfigStatus()
|
||||
}
|
||||
|
||||
async function registerVpnServiceListener() {
|
||||
@@ -135,15 +199,25 @@ export async function onNetworkInstanceChange(instanceId: string) {
|
||||
}
|
||||
|
||||
if (!instanceId) {
|
||||
await doStopVpn()
|
||||
console.warn('vpn service skipped because instance id is empty')
|
||||
if (curVpnStatus.running) {
|
||||
await doStopVpn()
|
||||
}
|
||||
return
|
||||
}
|
||||
const config = await getConfig(instanceId)
|
||||
console.log('vpn service loaded config', instanceId, JSON.stringify({
|
||||
no_tun: config.no_tun,
|
||||
dhcp: config.dhcp,
|
||||
enable_magic_dns: config.enable_magic_dns,
|
||||
}))
|
||||
if (config.no_tun) {
|
||||
console.log('vpn service skipped because no_tun is enabled', instanceId)
|
||||
return
|
||||
}
|
||||
const curNetworkInfo = (await collectNetworkInfo(instanceId)).info.map[instanceId]
|
||||
if (!curNetworkInfo || curNetworkInfo?.error_msg?.length) {
|
||||
console.warn('vpn service skipped because network info is unavailable', instanceId, curNetworkInfo?.error_msg)
|
||||
await doStopVpn()
|
||||
return
|
||||
}
|
||||
@@ -170,27 +244,39 @@ export async function onNetworkInstanceChange(instanceId: string) {
|
||||
|
||||
const routes = getRoutesForVpn(curNetworkInfo?.routes, config)
|
||||
|
||||
const dns = config.enable_magic_dns ? '100.100.100.101' : undefined;
|
||||
const dns = config.enable_magic_dns ? '100.100.100.101' : undefined
|
||||
|
||||
const ipChanged = virtual_ip !== curVpnStatus.ipv4Addr
|
||||
const cidrChanged = network_length !== curVpnStatus.ipv4Cidr
|
||||
const routesChanged = JSON.stringify(routes) !== JSON.stringify(curVpnStatus.routes)
|
||||
const dnsChanged = dns != curVpnStatus.dns
|
||||
const configChanged = ipChanged || cidrChanged || routesChanged || dnsChanged
|
||||
const shouldStartVpn = !curVpnStatus.running
|
||||
|
||||
if (ipChanged || routesChanged || dnsChanged) {
|
||||
if (shouldStartVpn || configChanged) {
|
||||
console.info('vpn service virtual ip changed', JSON.stringify(curVpnStatus), virtual_ip)
|
||||
try {
|
||||
await doStopVpn()
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
if (curVpnStatus.running) {
|
||||
try {
|
||||
await doStopVpn()
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await doStartVpn(virtual_ip, network_length, routes, dns)
|
||||
}
|
||||
catch (e) {
|
||||
console.error('start vpn service failed, stop all other network insts.', e)
|
||||
await runNetworkInstance(config, true); //on android config should always be saved
|
||||
if (e instanceof Error && e.message === 'need_prepare') {
|
||||
console.info('vpn permission is required before starting the Android VPN service')
|
||||
return
|
||||
}
|
||||
if (e instanceof Error && e.message === 'vpn_permission_denied') {
|
||||
console.info('vpn permission request was denied or dismissed')
|
||||
return
|
||||
}
|
||||
console.error('start vpn service failed', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,6 +288,22 @@ async function isNoTunEnabled(instanceId: string | undefined) {
|
||||
return (await getConfig(instanceId)).no_tun ?? false
|
||||
}
|
||||
|
||||
async function findRunningTunInstanceId() {
|
||||
const instanceIds = await listNetworkInstanceIds()
|
||||
const runningIds = instanceIds.running_inst_ids.map(Utils.UuidToStr)
|
||||
console.log('vpn service sync running instances', JSON.stringify(runningIds))
|
||||
|
||||
for (const instanceId of runningIds) {
|
||||
if (await isNoTunEnabled(instanceId)) {
|
||||
continue
|
||||
}
|
||||
|
||||
return instanceId
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export async function initMobileVpnService() {
|
||||
await registerVpnServiceListener()
|
||||
}
|
||||
@@ -210,10 +312,22 @@ export async function prepareVpnService(instanceId: string) {
|
||||
if (await isNoTunEnabled(instanceId)) {
|
||||
return
|
||||
}
|
||||
console.log('prepare vpn')
|
||||
const prepare_ret = await prepare_vpn()
|
||||
console.log('prepare vpn', JSON.stringify((prepare_ret)))
|
||||
if (prepare_ret?.errorMsg?.length) {
|
||||
throw new Error(prepare_ret.errorMsg)
|
||||
}
|
||||
await requestVpnPermission()
|
||||
}
|
||||
|
||||
export async function syncMobileVpnService() {
|
||||
syncVpnStatusFromNative(await get_vpn_status())
|
||||
const instanceId = await findRunningTunInstanceId()
|
||||
if (instanceId) {
|
||||
console.log('vpn service sync selected instance', instanceId)
|
||||
await onNetworkInstanceChange(instanceId)
|
||||
return
|
||||
}
|
||||
|
||||
if (dhcpPollingTimer) {
|
||||
clearTimeout(dhcpPollingTimer)
|
||||
dhcpPollingTimer = null
|
||||
}
|
||||
|
||||
await doStopVpn(true)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { exit } from '@tauri-apps/plugin-process'
|
||||
import { I18nUtils, RemoteManagement, Utils } from "easytier-frontend-lib"
|
||||
import type { MenuItem } from 'primevue/menuitem'
|
||||
import { useTray } from '~/composables/tray'
|
||||
import { initMobileVpnService } from '~/composables/mobile_vpn'
|
||||
import { GUIRemoteClient } from '~/modules/api'
|
||||
|
||||
import { useToast, useConfirm } from 'primevue'
|
||||
@@ -189,9 +190,25 @@ async function initWithMode(mode: Mode) {
|
||||
clientRunning.value = await isClientRunning()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
const cleanupFns: Array<() => void> = []
|
||||
|
||||
if (type() === 'android') {
|
||||
try {
|
||||
await initMobileVpnService()
|
||||
console.error("easytier init vpn service done")
|
||||
} catch (e: any) {
|
||||
console.error("easytier init vpn service failed", e)
|
||||
}
|
||||
}
|
||||
|
||||
cleanupFns.push(await listenGlobalEvents())
|
||||
currentMode.value = loadMode()
|
||||
initWithMode(currentMode.value);
|
||||
await initWithMode(currentMode.value);
|
||||
|
||||
onUnmounted(() => {
|
||||
cleanupFns.forEach(unlisten => unlisten())
|
||||
})
|
||||
});
|
||||
|
||||
useTray(true)
|
||||
@@ -347,22 +364,6 @@ async function connectRpcClient(isNormalMode: boolean, url?: string) {
|
||||
console.log("easytier rpc connection established, isNormalMode: ", isNormalMode)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (type() === 'android') {
|
||||
try {
|
||||
await initMobileVpnService()
|
||||
console.error("easytier init vpn service done")
|
||||
} catch (e: any) {
|
||||
console.error("easytier init vpn service failed", e)
|
||||
}
|
||||
}
|
||||
const unlisten = await listenGlobalEvents()
|
||||
|
||||
onUnmounted(() => {
|
||||
unlisten()
|
||||
})
|
||||
})
|
||||
|
||||
async function openConfigServerDialog() {
|
||||
editingMode.value = JSON.parse(JSON.stringify(loadMode()))
|
||||
configServerDialogVisible.value = true
|
||||
|
||||
Reference in New Issue
Block a user