chore(stage-tamagotchi): improve tauri

This commit is contained in:
Neko Ayaka
2025-06-29 03:11:59 +08:00
parent de326cf72c
commit 94048b0f71
4 changed files with 76 additions and 8 deletions
+70 -5
View File
@@ -1,8 +1,11 @@
import type { InvokeArgs, InvokeOptions } from '@tauri-apps/api/core'
import type { EventCallback, EventName, UnlistenFn } from '@tauri-apps/api/event'
import { withRetry } from '@moeru/std'
import { computedAsync, until } from '@vueuse/core'
import { useAppRuntime } from './runtime'
async function untilNoError<T>(fn: () => Promise<T>, onError?: (err?: unknown | null) => void): Promise<T> {
const fnRetry = withRetry(fn, { retryDelay: 5000, retry: Number.MAX_SAFE_INTEGER - 2, onError })
return await fnRetry()
@@ -50,14 +53,20 @@ export interface AiriTamagotchiEvents extends Events {
'mcp_plugin_destroyed': undefined
}
export type Event<E extends { [key: string]: any }> = {
[K in keyof E]: E[K];
}[keyof E]
export function useTauriEvent<ES = Events>() {
const tauriEventApi = computedAsync(() => untilImported(() => import('@tauri-apps/api/event'), console.warn))
const { platform } = useAppRuntime()
const tauriEventApi = computedAsync(() => {
if (platform.value !== 'web') {
return untilImported(() => import('@tauri-apps/api/event'), console.warn)
}
})
async function _listen<E extends keyof ES>(event: E, callback: EventCallback<ES[E]>) {
if (platform.value === 'web') {
return () => {}
}
await until(tauriEventApi).toBeTruthy()
const imported = await tauriEventApi.value
if (!imported) {
@@ -68,6 +77,11 @@ export function useTauriEvent<ES = Events>() {
}
async function listen<E extends keyof ES>(event: E, callback: EventCallback<ES[E]>) {
if (platform.value === 'web') {
console.warn(`Attempted to listen to Tauri event "${String(event)}" in web platform, however, currently we are not in a Tauri environment.`)
return () => {}
}
let cleanupListener: UnlistenFn | undefined
_listen(event, callback).then((listener) => {
@@ -83,3 +97,54 @@ export function useTauriEvent<ES = Events>() {
listen,
}
}
export interface InvokeMethods {
open_settings_window: { args: undefined, options: undefined, returns: void }
start_monitor: { args: undefined, options: undefined, returns: void }
stop_monitor: { args: undefined, options: undefined, returns: void }
open_chat_window: { args: undefined, options: undefined, returns: void }
load_models: { args: undefined, options: undefined, returns: void }
stop_click_through: { args: undefined, options: undefined, returns: void }
start_click_through: { args: undefined, options: undefined, returns: void }
}
interface InvokeMethodShape {
args: InvokeArgs | undefined
options: InvokeOptions | undefined
returns: any
}
export function useTauriCore<IM extends Record<keyof IM, InvokeMethodShape> = InvokeMethods>() {
const { platform } = useAppRuntime()
const tauriCoreApi = computedAsync(() => {
if (platform.value !== 'web') {
return untilImported(() => import('@tauri-apps/api/core'), console.warn)
}
})
async function invoke<
C extends keyof IM,
>(
command: C,
args?: IM[C]['args'],
options?: IM[C]['options'],
): Promise<IM[C]['returns'] | undefined> {
if (platform.value === 'web') {
console.warn(`Attempted to invoke Tauri command "${String(command)}" in web platform, however, currently we are not in a Tauri environment.`)
return
}
await until(tauriCoreApi).toBeTruthy()
const imported = await tauriCoreApi.value
if (!imported) {
throw new Error('Tauri core API not available')
}
return await untilNoError(() => imported.invoke(command as string, args as InvokeArgs | undefined, options as InvokeOptions | undefined), console.warn)
}
return {
invoke,
}
}
+2 -2
View File
@@ -4,13 +4,12 @@ import type { AiriTamagotchiEvents, Point, WindowFrame } from '../composables/ta
import { WidgetStage } from '@proj-airi/stage-ui/components'
import { useMcpStore } from '@proj-airi/stage-ui/stores'
import { connectServer } from '@proj-airi/tauri-plugin-mcp'
import { invoke } from '@tauri-apps/api/core'
import { storeToRefs } from 'pinia'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import ResourceStatusIsland from '../components/Widgets/ResourceStatusIsland/index.vue'
import { useAppRuntime } from '../composables/runtime'
import { useTauriEvent } from '../composables/tauri'
import { useTauriCore, useTauriEvent } from '../composables/tauri'
import { useWindowShortcuts } from '../composables/window-shortcuts'
import { useResourcesStore } from '../stores/resources'
import { useWindowControlStore } from '../stores/window-controls'
@@ -22,6 +21,7 @@ const { platform } = useAppRuntime()
const windowStore = useWindowControlStore()
const mcpStore = useMcpStore()
const { listen } = useTauriEvent<AiriTamagotchiEvents>()
const { invoke } = useTauriCore()
const isCursorInside = ref(false)
const { connected, serverCmd, serverArgs } = storeToRefs(mcpStore)
+3 -1
View File
@@ -1,9 +1,11 @@
import { invoke } from '@tauri-apps/api/core'
import { useTauriCore } from '../composables/tauri'
export async function startClickThrough() {
const { invoke } = useTauriCore()
await invoke('start_click_through')
}
export async function stopClickThrough() {
const { invoke } = useTauriCore()
await invoke('stop_click_through')
}
+1
View File
@@ -91,6 +91,7 @@ words:
- intlify
- Kawaii
- kebabcase
- Keyyable
- kwaa
- lemonnekogh
- libsodium