web/front/composables/usePythonBridge.ts

120 lines
3.0 KiB
TypeScript

import { ref, onMounted } from 'vue'
declare global {
interface Window {
QWebChannel?: typeof QWebChannel
qt?: {
webChannelTransport?: any
}
}
const QWebChannel: {
new(transport: any, ready: (channel: any) => void): void
}
}
interface PythonEvent {
type: string
data: any
}
const pyjs = ref<any>(null)
const isReady = ref<boolean>(false)
// Хранилище обработчиков событий
const pythonEventHandlers = new Map<string, Array<(data: any) => void>>()
function receiveFromPython(eventType: string, data: any) {
console.warn("🟢 Событие из Python:", eventType, data)
const handlers = pythonEventHandlers.get(eventType) || []
handlers.forEach(handler => handler(data))
}
export function usePythonBridge() {
function setupQWebChannel() {
if (window.QWebChannel && window.qt && window.qt.webChannelTransport) {
new window.QWebChannel(window.qt.webChannelTransport, function (channel) {
isReady.value = true
pyjs.value = channel.objects.pyjs
// Получаем доступ к эмиттеру событий
const eventEmitter = channel.objects.pyjs_events
// Подписываемся на событие один раз
if (eventEmitter && eventEmitter.onEvent) {
eventEmitter.onEvent.connect(receiveFromPython)
}
})
} else {
console.error('Qt WebChannel недоступен')
}
}
async function sendCommandToPython<T = any>(
command: string,
data: Record<string, any> = {}
): Promise<T> {
return new Promise((resolve, reject) => {
if (!isReady.value) {
reject(new Error('Мост еще не готов'))
return
}
if (!pyjs.value || !pyjs.value.callFromJS) {
reject(new Error('Python недоступен'))
return
}
pyjs.value.callFromJS(command, JSON.stringify(data), (result: string) => {
try {
resolve(JSON.parse(result))
} catch (e) {
reject(e)
}
})
})
}
// Регистрация обработчика событий по типу
function onPythonEvent(eventType: string, handler: (data: any) => void) {
if (!pythonEventHandlers.has(eventType)) {
pythonEventHandlers.set(eventType, [])
}
pythonEventHandlers.get(eventType)?.push(handler)
}
// Отписка от события
function offPythonEvent(eventType: string, handler: (data: any) => void) {
const handlers = pythonEventHandlers.get(eventType)
if (handlers) {
const index = handlers.indexOf(handler)
if (index > -1) {
handlers.splice(index, 1)
}
}
}
const checkBridge = () => {
if (window.QWebChannel && window.qt?.webChannelTransport) {
setupQWebChannel()
}
if (pyjs.value) {
console.warn('✅ pyjs готов')
} else {
setTimeout(checkBridge, 500)
}
}
onMounted(() => {
checkBridge()
})
return {
isReady,
sendCommandToPython,
onPythonEvent,
offPythonEvent,
}
}