mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-09 03:04:31 +00:00
005b321f62
* allow open rpc port for gui normal mode * downgrade dev tool console
237 lines
7.8 KiB
Vue
237 lines
7.8 KiB
Vue
<script setup lang="ts">
|
|
import { computed, watch, onMounted, ref } from 'vue';
|
|
import type { Mode, ServiceMode, RemoteMode, NormalMode } from '~/composables/mode';
|
|
import { appConfigDir, appLogDir } from '@tauri-apps/api/path';
|
|
import { join } from '@tauri-apps/api/path';
|
|
import { getServiceStatus, type ServiceStatus } from '~/composables/backend';
|
|
|
|
const { t } = useI18n()
|
|
|
|
const model = defineModel<Mode>({ required: true })
|
|
const emit = defineEmits(['uninstall-service', 'stop-service'])
|
|
|
|
const defaultConfigDir = ref('')
|
|
const defaultLogDir = ref('')
|
|
const serviceStatus = ref<ServiceStatus>('NotInstalled')
|
|
const isServiceStatusLoaded = ref(false)
|
|
|
|
function normalizeRpcListenPort(port: unknown): number {
|
|
const defaultPort = 15999
|
|
const numericPort = typeof port === 'number' ? port : Number.parseInt(String(port ?? ''), 10)
|
|
if (Number.isNaN(numericPort))
|
|
return defaultPort
|
|
return Math.min(65535, Math.max(1, Math.floor(numericPort)))
|
|
}
|
|
|
|
onMounted(async () => {
|
|
defaultConfigDir.value = await join(await appConfigDir(), 'config.d')
|
|
defaultLogDir.value = await appLogDir()
|
|
})
|
|
|
|
const modeOptions = computed(() => [
|
|
{ label: t('mode.normal'), value: 'normal' },
|
|
{ label: t('mode.service'), value: 'service' },
|
|
{ label: t('mode.remote'), value: 'remote' },
|
|
]);
|
|
|
|
const normalMode = computed({
|
|
get: () => model.value.mode === 'normal' ? model.value as NormalMode : undefined,
|
|
set: (value) => {
|
|
if (value) {
|
|
model.value = value
|
|
}
|
|
}
|
|
})
|
|
|
|
const rpcListenOptions = computed(() => [
|
|
{ label: t('web.common.disable'), value: false },
|
|
{ label: t('web.common.enable'), value: true },
|
|
])
|
|
|
|
const rpcListenEnabled = computed<boolean>({
|
|
get: () => !!normalMode.value?.enable_rpc_port_listen,
|
|
set: (value) => {
|
|
if (!normalMode.value)
|
|
return
|
|
normalMode.value.enable_rpc_port_listen = value
|
|
},
|
|
})
|
|
|
|
const rpcListenPort = computed<string>({
|
|
get: () => String(normalMode.value?.rpc_listen_port ?? 15999),
|
|
set: (value) => {
|
|
if (!normalMode.value)
|
|
return
|
|
const trimmed = value.trim()
|
|
if (trimmed === '')
|
|
return
|
|
if (!/^\d+$/.test(trimmed))
|
|
return
|
|
normalMode.value.rpc_listen_port = Number.parseInt(trimmed, 10)
|
|
},
|
|
})
|
|
|
|
const serviceMode = computed({
|
|
get: () => model.value.mode === 'service' ? model.value as ServiceMode : undefined,
|
|
set: (value) => {
|
|
if (value) {
|
|
model.value = value
|
|
}
|
|
}
|
|
})
|
|
|
|
const remoteMode = computed({
|
|
get: () => model.value.mode === 'remote' ? model.value as RemoteMode : undefined,
|
|
set: (value) => {
|
|
if (value) {
|
|
model.value = value
|
|
}
|
|
}
|
|
})
|
|
|
|
const statusColorClass = computed(() => {
|
|
switch (serviceStatus.value) {
|
|
case 'Running':
|
|
return 'text-green-600'
|
|
case 'Stopped':
|
|
return 'text-orange-600'
|
|
case 'NotInstalled':
|
|
return 'text-gray-600'
|
|
default:
|
|
return 'text-gray-600'
|
|
}
|
|
})
|
|
|
|
watch(() => [normalMode.value?.enable_rpc_port_listen, normalMode.value?.rpc_listen_port], ([enabled, port]) => {
|
|
if (!normalMode.value)
|
|
return
|
|
|
|
if (!enabled) {
|
|
normalMode.value.rpc_portal = undefined
|
|
return
|
|
}
|
|
|
|
const normalizedPort = normalizeRpcListenPort(port)
|
|
if (normalMode.value.rpc_listen_port !== normalizedPort)
|
|
normalMode.value.rpc_listen_port = normalizedPort
|
|
|
|
const desiredPortal = `tcp://0.0.0.0:${normalizedPort}`
|
|
if (normalMode.value.rpc_portal !== desiredPortal)
|
|
normalMode.value.rpc_portal = desiredPortal
|
|
}, { immediate: true })
|
|
|
|
watch(() => model.value.mode, async (newMode, oldMode) => {
|
|
if (newMode === oldMode)
|
|
return
|
|
|
|
if (newMode === 'service' && !isServiceStatusLoaded.value) {
|
|
serviceStatus.value = await getServiceStatus()
|
|
isServiceStatusLoaded.value = true
|
|
}
|
|
|
|
const oldModelValue = { ...model.value }
|
|
|
|
if (newMode === 'normal') {
|
|
const portal = normalMode.value?.rpc_portal?.trim()
|
|
model.value = {
|
|
...oldModelValue,
|
|
rpc_portal: portal || undefined,
|
|
enable_rpc_port_listen: normalMode.value?.enable_rpc_port_listen,
|
|
rpc_listen_port: normalMode.value?.rpc_listen_port,
|
|
mode: 'normal',
|
|
}
|
|
}
|
|
else if (newMode === 'service') {
|
|
model.value = {
|
|
...oldModelValue,
|
|
mode: 'service',
|
|
config_dir: serviceMode.value?.config_dir || defaultConfigDir.value,
|
|
rpc_portal: serviceMode.value?.rpc_portal || '127.0.0.1:15999',
|
|
file_log_level: serviceMode.value?.file_log_level || 'off',
|
|
file_log_dir: serviceMode.value?.file_log_dir || defaultLogDir.value,
|
|
}
|
|
}
|
|
else if (newMode === 'remote') {
|
|
model.value = {
|
|
...oldModelValue,
|
|
mode: 'remote',
|
|
remote_rpc_address: remoteMode.value?.remote_rpc_address || 'tcp://127.0.0.1:15999',
|
|
}
|
|
}
|
|
}, { immediate: true })
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col gap-4">
|
|
<div>
|
|
<SelectButton id="mode-select" v-model="model.mode" :options="modeOptions" option-label="label"
|
|
option-value="value" fluid />
|
|
</div>
|
|
|
|
<!-- Mode descriptions -->
|
|
<div v-if="model.mode === 'normal'" class="text-sm text-gray-500">
|
|
{{ t('mode.normal_description') }}
|
|
</div>
|
|
<div v-else-if="model.mode === 'service'" class="text-sm text-gray-500">
|
|
{{ t('mode.service_description') }}
|
|
</div>
|
|
<div v-else-if="model.mode === 'remote'" class="text-sm text-gray-500">
|
|
{{ t('mode.remote_description') }}
|
|
</div>
|
|
|
|
<div v-if="normalMode" class="flex flex-col gap-2">
|
|
<div class="flex items-center gap-2">
|
|
<label for="rpc-listen-toggle">{{ t('mode.enable_rpc_tcp_listen') }}</label>
|
|
<SelectButton id="rpc-listen-toggle" v-model="rpcListenEnabled" :options="rpcListenOptions" option-label="label"
|
|
option-value="value" />
|
|
</div>
|
|
<div v-if="rpcListenEnabled" class="flex flex-col gap-2">
|
|
<div class="flex items-center gap-2">
|
|
<label for="rpc-listen-port">{{ t('mode.rpc_listen_port') }}</label>
|
|
<InputText id="rpc-listen-port" v-model="rpcListenPort" class="flex-1" inputmode="numeric" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="serviceMode" class="flex flex-col gap-2">
|
|
<div class="flex items-center gap-2">
|
|
<label for="config-dir">{{ t('mode.config_dir') }}</label>
|
|
<InputText id="config-dir" v-model="serviceMode.config_dir" class="flex-1" />
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<label for="rpc-portal">{{ t('mode.rpc_portal') }}</label>
|
|
<InputText id="rpc-portal" v-model="serviceMode.rpc_portal" class="flex-1" />
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<label for="log-level">{{ t('mode.log_level') }}</label>
|
|
<Select id="log-level" v-model="serviceMode.file_log_level"
|
|
:options="['off', 'warn', 'info', 'debug', 'trace']" />
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<label for="log-dir">{{ t('mode.log_dir') }}</label>
|
|
<InputText id="log-dir" v-model="serviceMode.file_log_dir" class="flex-1" />
|
|
</div>
|
|
<div class="flex items-center gap-2 justify-between">
|
|
<div class="flex items-center gap-2">
|
|
<label>{{ t('mode.service_status') }}</label>
|
|
<span :class="statusColorClass">{{ t(`mode.service_status_${serviceStatus.toLowerCase()}`) }}</span>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<Button :label="t('mode.stop_service')" icon="pi pi-stop-circle" v-if="serviceStatus === 'Running'"
|
|
@click="emit('stop-service')" severity="warn" text />
|
|
<Button :label="t('mode.uninstall_service')" icon="pi pi-trash" v-if="serviceStatus !== 'NotInstalled'"
|
|
@click="emit('uninstall-service')" severity="danger" text />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="remoteMode" class="flex flex-col gap-2">
|
|
<div class="flex items-center gap-2">
|
|
<label for="remote-addr">{{ t('mode.remote_rpc_address') }}</label>
|
|
<InputText id="remote-addr" v-model="remoteMode.remote_rpc_address" class="flex-1" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|