Add typed ipc
This commit is contained in:
@@ -9,7 +9,7 @@ const NANO_BAUD_RATE = 115200
|
|||||||
|
|
||||||
class NanoDevices extends EventEmitter {
|
class NanoDevices extends EventEmitter {
|
||||||
all_nano_devices: { [key: string]: PortInfo } = {}
|
all_nano_devices: { [key: string]: PortInfo } = {}
|
||||||
connected_nano_devices: { [key: string]: { port: SerialPort; data: string } } = {}
|
connected_nano_devices: { [key: string]: { port: SerialPort } } = {}
|
||||||
|
|
||||||
_list() {
|
_list() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -105,7 +105,7 @@ class NanoDevices extends EventEmitter {
|
|||||||
})
|
})
|
||||||
port.on('open', () => {
|
port.on('open', () => {
|
||||||
resolve(nano_device.serialNumber)
|
resolve(nano_device.serialNumber)
|
||||||
this.connected_nano_devices[nano_device.serialNumber!] = { port: port, data: '' }
|
this.connected_nano_devices[nano_device.serialNumber!] = { port: port }
|
||||||
this.emit('nanodevices:connected', nano_device.serialNumber)
|
this.emit('nanodevices:connected', nano_device.serialNumber)
|
||||||
})
|
})
|
||||||
port.on('data', (data) => {
|
port.on('data', (data) => {
|
||||||
|
|||||||
29
src/preload/index.d.ts
vendored
29
src/preload/index.d.ts
vendored
@@ -1,8 +1,31 @@
|
|||||||
import { ElectronAPI } from '@electron-toolkit/preload'
|
export interface INanoDevicesAPI {
|
||||||
|
list_devices(): Promise<string[]>
|
||||||
|
connect(deviceid: string): Promise<string>
|
||||||
|
disconnect(deviceid: string): Promise<string>
|
||||||
|
on_event(
|
||||||
|
eventid_filter: string,
|
||||||
|
callback: (eventid: string, deviceid: string, data: any) => void
|
||||||
|
): void
|
||||||
|
send(deviceid: string, jsonstr: string): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IElectronAPI {
|
||||||
|
platform: NodeJS.Platform
|
||||||
|
isDevelopment: boolean
|
||||||
|
minimizeWindow: () => void
|
||||||
|
toggleMaximizeWindow: () => void
|
||||||
|
closeWindow: () => void
|
||||||
|
openExternal: (url: string) => void
|
||||||
|
onMaximized: (callback: () => void) => void
|
||||||
|
onUnmaximized: (callback: () => void) => void
|
||||||
|
onMenu: (callback: (key: string) => void) => void
|
||||||
|
openDevTools: () => void
|
||||||
|
reload: () => void
|
||||||
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
electron: ElectronAPI
|
nanoDevicesAPI: INanoDevicesAPI
|
||||||
api: unknown
|
electronAPI: IElectronAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,43 @@
|
|||||||
import { contextBridge, ipcRenderer } from 'electron'
|
import { contextBridge, ipcRenderer } from 'electron'
|
||||||
import { electronAPI } from '@electron-toolkit/preload'
|
|
||||||
|
|
||||||
// Custom APIs for renderer
|
// expose an API to choose available devices
|
||||||
const api = {}
|
contextBridge.exposeInMainWorld('nanoDevicesAPI', {
|
||||||
|
list_devices() {
|
||||||
// Use `contextBridge` APIs to expose Electron APIs to
|
return ipcRenderer.invoke('nanodevices:list_devices')
|
||||||
// renderer only if context isolation is enabled, otherwise
|
},
|
||||||
// just add to the DOM global.
|
connect(deviceid) {
|
||||||
if (process.contextIsolated) {
|
return ipcRenderer.invoke('nanodevices:connect', deviceid)
|
||||||
try {
|
},
|
||||||
// expose an API to choose available devices
|
disconnect(deviceid) {
|
||||||
contextBridge.exposeInMainWorld('nanodevices', {
|
return ipcRenderer.invoke('nanodevices:disconnect', deviceid)
|
||||||
list_devices() {
|
},
|
||||||
return ipcRenderer.invoke('nanodevices:list_devices')
|
on_event(eventid_filter, callback) {
|
||||||
},
|
console.log('attaching filter for ', eventid_filter)
|
||||||
connect(deviceid) {
|
ipcRenderer.on('nanodevices:event', (_event, eventid, deviceid, ...data) => {
|
||||||
return ipcRenderer.invoke('nanodevices:connect', deviceid)
|
console.log('Event in ipcRenderer ', eventid, deviceid, data)
|
||||||
},
|
if (eventid_filter == '*' || eventid_filter == eventid) {
|
||||||
disconnect(deviceid) {
|
callback(eventid, deviceid, ...data)
|
||||||
return ipcRenderer.invoke('nanodevices:disconnect', deviceid)
|
|
||||||
},
|
|
||||||
on_event(eventid_filter, callback) {
|
|
||||||
console.log('attaching filter for ', eventid_filter)
|
|
||||||
ipcRenderer.on('nanodevices:event', (_event, eventid, deviceid, ...data) => {
|
|
||||||
console.log('Event in ipcRenderer ', eventid, deviceid, data)
|
|
||||||
if (eventid_filter == '*' || eventid_filter == eventid) {
|
|
||||||
callback(eventid, deviceid, ...data)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
send(deviceid, jsonstr) {
|
|
||||||
return ipcRenderer.invoke('nanodevices:send', deviceid, jsonstr)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
contextBridge.exposeInMainWorld('electron', {
|
send(deviceid, jsonstr) {
|
||||||
platform: process.platform,
|
return ipcRenderer.invoke('nanodevices:send', deviceid, jsonstr)
|
||||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
|
||||||
minimizeWindow: () => ipcRenderer.send('electron:minimizeWindow'),
|
|
||||||
toggleMaximizeWindow: () => ipcRenderer.send('electron:toggleMaximizeWindow'),
|
|
||||||
closeWindow: () => ipcRenderer.send('electron:closeWindow'),
|
|
||||||
openExternal: (url) => ipcRenderer.send('electron:openExternal', url),
|
|
||||||
onMaximized: (callback) => ipcRenderer.on('electron:maximized', callback),
|
|
||||||
onUnmaximized: (callback) => ipcRenderer.on('electron:unmaximized', callback),
|
|
||||||
onMenu: (callback) =>
|
|
||||||
ipcRenderer.on('electron:menu', (event, key) => {
|
|
||||||
callback(key)
|
|
||||||
}),
|
|
||||||
openDevTools: () => ipcRenderer.send('electron:openDevTools'),
|
|
||||||
reload: () => ipcRenderer.send('electron:reload')
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
// @ts-ignore (define in dts)
|
|
||||||
window.electron = electronAPI
|
contextBridge.exposeInMainWorld('electronAPI', {
|
||||||
// @ts-ignore (define in dts)
|
platform: process.platform,
|
||||||
window.api = api
|
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||||
}
|
minimizeWindow: () => ipcRenderer.send('electron:minimizeWindow'),
|
||||||
|
toggleMaximizeWindow: () => ipcRenderer.send('electron:toggleMaximizeWindow'),
|
||||||
|
closeWindow: () => ipcRenderer.send('electron:closeWindow'),
|
||||||
|
openExternal: (url) => ipcRenderer.send('electron:openExternal', url),
|
||||||
|
onMaximized: (callback) => ipcRenderer.on('electron:maximized', callback),
|
||||||
|
onUnmaximized: (callback) => ipcRenderer.on('electron:unmaximized', callback),
|
||||||
|
onMenu: (callback) =>
|
||||||
|
ipcRenderer.on('electron:menu', (event, key) => {
|
||||||
|
callback(key)
|
||||||
|
}),
|
||||||
|
openDevTools: () => ipcRenderer.send('electron:openDevTools'),
|
||||||
|
reload: () => ipcRenderer.send('electron:reload')
|
||||||
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import Navbar from '@renderer/components/navbar/Navbar.vue'
|
|||||||
import { useStore } from '@renderer/store'
|
import { useStore } from '@renderer/store'
|
||||||
import { useMessageHandlers } from '@renderer/device'
|
import { useMessageHandlers } from '@renderer/device'
|
||||||
|
|
||||||
const { electron } = window
|
const { electronAPI, nanoDevicesAPI } = window
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
const menuActions = {
|
const menuActions = {
|
||||||
@@ -15,7 +15,7 @@ const menuActions = {
|
|||||||
skin: () => store.switchPreviewDeviceModel()
|
skin: () => store.switchPreviewDeviceModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
electron?.onMenu((key) => {
|
electronAPI.onMenu((key) => {
|
||||||
console.log('menu', key)
|
console.log('menu', key)
|
||||||
if (menuActions[key]) {
|
if (menuActions[key]) {
|
||||||
menuActions[key]()
|
menuActions[key]()
|
||||||
@@ -26,24 +26,20 @@ store.fetchProfiles() // TODO remove me!
|
|||||||
|
|
||||||
// handle device events
|
// handle device events
|
||||||
const handlers = useMessageHandlers(store)
|
const handlers = useMessageHandlers(store)
|
||||||
window.nanodevices.on_event('device-attached', (evt, deviceid, data) =>
|
nanoDevicesAPI.on_event('device-attached', (evt, deviceid, data) => store.device_attached(deviceid))
|
||||||
store.device_attached(deviceid)
|
nanoDevicesAPI.on_event('device-detached', (evt, deviceid, data) => store.device_detached(deviceid))
|
||||||
)
|
nanoDevicesAPI.on_event('device-error', (evt, deviceid, data) => {
|
||||||
window.nanodevices.on_event('device-detached', (evt, deviceid, data) =>
|
|
||||||
store.device_detached(deviceid)
|
|
||||||
)
|
|
||||||
window.nanodevices.on_event('device-error', (evt, deviceid, data) => {
|
|
||||||
/* TODO handle connection errors */
|
/* TODO handle connection errors */
|
||||||
})
|
})
|
||||||
window.nanodevices.on_event('connected', (evt, deviceid, data) => store.device_connected(deviceid))
|
nanoDevicesAPI.on_event('connected', (evt, deviceid, data) => store.device_connected(deviceid))
|
||||||
window.nanodevices.on_event('disconnected', (evt, deviceid, data) =>
|
nanoDevicesAPI.on_event('disconnected', (evt, deviceid, data) =>
|
||||||
store.device_disconnected(deviceid)
|
store.device_disconnected(deviceid)
|
||||||
)
|
)
|
||||||
window.nanodevices.on_event('update', (evt, deviceid, data) => {
|
nanoDevicesAPI.on_event('update', (evt, deviceid, data) => {
|
||||||
handlers.handle_message(data)
|
handlers.handle_message(data)
|
||||||
})
|
})
|
||||||
// get list of the currently attached devices
|
// get list of the currently attached devices
|
||||||
window.nanodevices.list_devices().then((devs) => store.init_devices(devs))
|
nanoDevicesAPI.list_devices().then((devs) => store.init_devices(devs))
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<main class="flex h-screen w-screen select-none flex-col">
|
<main class="flex h-screen w-screen select-none flex-col">
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { reactive } from 'vue'
|
|
||||||
|
|
||||||
const versions = reactive({ ...window.electron.process.versions })
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<ul class="versions">
|
|
||||||
<li class="electron-version">Electron v{{ versions.electron }}</li>
|
|
||||||
<li class="chrome-version">Chromium v{{ versions.chrome }}</li>
|
|
||||||
<li class="node-version">Node v{{ versions.node }}</li>
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
</MenubarMenu>
|
</MenubarMenu>
|
||||||
<MenubarButton
|
<MenubarButton
|
||||||
class="app-titlebar-button"
|
class="app-titlebar-button"
|
||||||
@click="electron?.openExternal('https://discord.gg/jgRd77YN5T')"
|
@click="electronAPI.openExternal('https://discord.gg/jgRd77YN5T')"
|
||||||
>
|
>
|
||||||
Community
|
Community
|
||||||
</MenubarButton>
|
</MenubarButton>
|
||||||
@@ -104,10 +104,10 @@
|
|||||||
<p>v0.1</p>
|
<p>v0.1</p>
|
||||||
</MenubarItem>
|
</MenubarItem>
|
||||||
<MenubarItem>Contact Support</MenubarItem>
|
<MenubarItem>Contact Support</MenubarItem>
|
||||||
<template v-if="electron?.isDevelopment">
|
<template v-if="electronAPI.isDevelopment">
|
||||||
<MenubarSeparator />
|
<MenubarSeparator />
|
||||||
<MenubarItem @click="electron?.openDevTools">Developer Tools</MenubarItem>
|
<MenubarItem @click="electronAPI.openDevTools">Developer Tools</MenubarItem>
|
||||||
<MenubarItem @click="electron?.reload">Reload</MenubarItem>
|
<MenubarItem @click="electronAPI.reload">Reload</MenubarItem>
|
||||||
</template>
|
</template>
|
||||||
</MenubarContent>
|
</MenubarContent>
|
||||||
</MenubarMenu>
|
</MenubarMenu>
|
||||||
@@ -124,21 +124,21 @@
|
|||||||
<button
|
<button
|
||||||
v-if="minimizable"
|
v-if="minimizable"
|
||||||
class="app-titlebar-button flex grow items-center justify-center px-2 hover:text-white"
|
class="app-titlebar-button flex grow items-center justify-center px-2 hover:text-white"
|
||||||
@click="electron?.minimizeWindow"
|
@click="electronAPI.minimizeWindow"
|
||||||
>
|
>
|
||||||
<Minus class="size-5" />
|
<Minus class="size-5" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="maximizable"
|
v-if="maximizable"
|
||||||
class="app-titlebar-button flex grow items-center justify-center px-2 hover:text-white"
|
class="app-titlebar-button flex grow items-center justify-center px-2 hover:text-white"
|
||||||
@click="electron?.toggleMaximizeWindow"
|
@click="electronAPI.toggleMaximizeWindow"
|
||||||
>
|
>
|
||||||
<Copy v-if="isMaximized" class="size-4" />
|
<Copy v-if="isMaximized" class="size-4" />
|
||||||
<Square v-else class="mr-0.5 size-3.5" />
|
<Square v-else class="mr-0.5 size-3.5" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="app-titlebar-button flex grow items-center justify-center px-2 hover:text-white"
|
class="app-titlebar-button flex grow items-center justify-center px-2 hover:text-white"
|
||||||
@click="electron?.closeWindow"
|
@click="electronAPI.closeWindow"
|
||||||
>
|
>
|
||||||
<X class="mr-0.5 size-5" />
|
<X class="mr-0.5 size-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -171,9 +171,9 @@ const showDisconnectButton = ref(false)
|
|||||||
|
|
||||||
const isMaximized = ref(false)
|
const isMaximized = ref(false)
|
||||||
|
|
||||||
const { electron } = window
|
const { electronAPI } = window
|
||||||
|
|
||||||
const isMacOS = electron?.platform === 'darwin'
|
const isMacOS = electronAPI.platform === 'darwin'
|
||||||
const zoomFactor = ref(1)
|
const zoomFactor = ref(1)
|
||||||
|
|
||||||
const previewDeviceNames = ref({
|
const previewDeviceNames = ref({
|
||||||
@@ -185,12 +185,12 @@ onMounted(() => {
|
|||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
zoomFactor.value = window.outerWidth / window.innerWidth
|
zoomFactor.value = window.outerWidth / window.innerWidth
|
||||||
})
|
})
|
||||||
electron?.onMaximized((maximized) => {
|
electronAPI.onMaximized((maximized) => {
|
||||||
console.log(maximized)
|
console.log(maximized)
|
||||||
isMaximized.value = true
|
isMaximized.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
electron?.onUnmaximized(() => {
|
electronAPI.onUnmaximized(() => {
|
||||||
isMaximized.value = false
|
isMaximized.value = false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,10 +20,8 @@ const app = createApp(App)
|
|||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
|
|
||||||
app.config.globalProperties.window = window
|
|
||||||
|
|
||||||
// TODO remove this
|
// TODO remove this
|
||||||
window.nanodevices.on_event('*', (eventid, deviceid, ...data) => {
|
window.nanoDevicesAPI.on_event('*', (eventid, deviceid, ...data) => {
|
||||||
console.log('Event on window ', eventid, deviceid, data)
|
console.log('Event on window ', eventid, deviceid, data)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ export const useStore = defineStore('main', {
|
|||||||
// TODO auto-connect to the device
|
// TODO auto-connect to the device
|
||||||
const deviceid = Object.keys(this.devices)[0]
|
const deviceid = Object.keys(this.devices)[0]
|
||||||
console.log('Auto-connecting to device ', deviceid)
|
console.log('Auto-connecting to device ', deviceid)
|
||||||
window.nanodevices.connect(deviceid)
|
window.nanoDevicesAPI.connect(deviceid)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update_devices(deviceid, attached) {
|
update_devices(deviceid, attached) {
|
||||||
@@ -227,7 +227,7 @@ export const useStore = defineStore('main', {
|
|||||||
if (Object.keys(this.devices).length == 1) {
|
if (Object.keys(this.devices).length == 1) {
|
||||||
// TODO auto-connect to the device
|
// TODO auto-connect to the device
|
||||||
console.log('Auto-connecting to device ', deviceid)
|
console.log('Auto-connecting to device ', deviceid)
|
||||||
window.nanodevices.connect(deviceid)
|
window.nanoDevicesAPI.connect(deviceid)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
device_detached(deviceid) {
|
device_detached(deviceid) {
|
||||||
|
|||||||
Reference in New Issue
Block a user