mirror of
https://github.com/usatiuk/door-thing.git
synced 2025-10-26 19:17:49 +01:00
a truly horrifying autoconnect
This commit is contained in:
@@ -12,5 +12,11 @@
|
|||||||
"plugin:import/electron",
|
"plugin:import/electron",
|
||||||
"plugin:import/typescript"
|
"plugin:import/typescript"
|
||||||
],
|
],
|
||||||
|
"settings": {
|
||||||
|
"import/resolver": {
|
||||||
|
"typescript": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"parser": "@typescript-eslint/parser"
|
"parser": "@typescript-eslint/parser"
|
||||||
}
|
}
|
||||||
|
|||||||
75
door-thing-app/package-lock.json
generated
75
door-thing-app/package-lock.json
generated
@@ -9,7 +9,8 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-squirrel-startup": "^1.0.0"
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
|
"lowdb": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron-forge/cli": "^6.0.0-beta.63",
|
"@electron-forge/cli": "^6.0.0-beta.63",
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"electron": "18.0.4",
|
"electron": "18.0.4",
|
||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
|
"eslint-import-resolver-typescript": "^2.7.1",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"fork-ts-checker-webpack-plugin": "^6.5.1",
|
"fork-ts-checker-webpack-plugin": "^6.5.1",
|
||||||
"node-loader": "^2.0.0",
|
"node-loader": "^2.0.0",
|
||||||
@@ -4368,6 +4370,26 @@
|
|||||||
"ms": "^2.1.1"
|
"ms": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-import-resolver-typescript": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"glob": "^7.2.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"resolve": "^1.22.0",
|
||||||
|
"tsconfig-paths": "^3.14.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "*",
|
||||||
|
"eslint-plugin-import": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint-module-utils": {
|
"node_modules/eslint-module-utils": {
|
||||||
"version": "2.7.3",
|
"version": "2.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
|
||||||
@@ -7000,6 +7022,20 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lowdb": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lowdb/-/lowdb-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-9KZRulmIcU8fZuWiaM0d5e2/nPnrFyXkeXVpqT+MJS+vgbgOf1EbtvgQmba8HwUFgDl1oeZR6XqEJnkJmQdKmg==",
|
||||||
|
"dependencies": {
|
||||||
|
"steno": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/typicode"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lower-case": {
|
"node_modules/lower-case": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||||
@@ -9642,6 +9678,17 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/steno": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-mauOsiaqTNGFkWqIfwcm3y/fq+qKKaIWf1vf3ocOuTdco9XoHCO2AGF1gFYXuZFSWuP38Q8LBHBGJv2KnJSXyA==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/typicode"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string_decoder": {
|
"node_modules/string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
@@ -14547,6 +14594,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eslint-import-resolver-typescript": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"glob": "^7.2.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"resolve": "^1.22.0",
|
||||||
|
"tsconfig-paths": "^3.14.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"eslint-module-utils": {
|
"eslint-module-utils": {
|
||||||
"version": "2.7.3",
|
"version": "2.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
|
||||||
@@ -16564,6 +16624,14 @@
|
|||||||
"is-unicode-supported": "^0.1.0"
|
"is-unicode-supported": "^0.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lowdb": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lowdb/-/lowdb-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-9KZRulmIcU8fZuWiaM0d5e2/nPnrFyXkeXVpqT+MJS+vgbgOf1EbtvgQmba8HwUFgDl1oeZR6XqEJnkJmQdKmg==",
|
||||||
|
"requires": {
|
||||||
|
"steno": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lower-case": {
|
"lower-case": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
|
||||||
@@ -18565,6 +18633,11 @@
|
|||||||
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
|
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"steno": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/steno/-/steno-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-mauOsiaqTNGFkWqIfwcm3y/fq+qKKaIWf1vf3ocOuTdco9XoHCO2AGF1gFYXuZFSWuP38Q8LBHBGJv2KnJSXyA=="
|
||||||
|
},
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
|||||||
@@ -53,7 +53,10 @@
|
|||||||
{
|
{
|
||||||
"html": "./src/index.html",
|
"html": "./src/index.html",
|
||||||
"js": "./src/renderer.tsx",
|
"js": "./src/renderer.tsx",
|
||||||
"name": "main_window"
|
"name": "main_window",
|
||||||
|
"preload": {
|
||||||
|
"js": "./src/preload.ts"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -76,6 +79,7 @@
|
|||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"electron": "18.0.4",
|
"electron": "18.0.4",
|
||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
|
"eslint-import-resolver-typescript": "^2.7.1",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"fork-ts-checker-webpack-plugin": "^6.5.1",
|
"fork-ts-checker-webpack-plugin": "^6.5.1",
|
||||||
"node-loader": "^2.0.0",
|
"node-loader": "^2.0.0",
|
||||||
@@ -85,6 +89,7 @@
|
|||||||
"typescript": "~4.5.4"
|
"typescript": "~4.5.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-squirrel-startup": "^1.0.0"
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
|
"lowdb": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
const doorServiceUUIDString = "0x1811";
|
||||||
const doorServiceUUID: BluetoothServiceUUID = 0x1811;
|
const doorServiceUUID: BluetoothServiceUUID = 0x1811;
|
||||||
const doorSwitchUUID: BluetoothCharacteristicUUID = 0x2ae2;
|
const doorSwitchUUID: BluetoothCharacteristicUUID = 0x2ae2;
|
||||||
|
|
||||||
@@ -11,49 +12,93 @@ export function App() {
|
|||||||
characteristic: BluetoothRemoteGATTCharacteristic;
|
characteristic: BluetoothRemoteGATTCharacteristic;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
const [doorOpen, setDoorOpen] = useState<boolean | null>(null);
|
const [doorOpen, setDoorOpen] = useState<boolean | null>(null);
|
||||||
|
const [autoConnect, setAutoConnect] = useState(false);
|
||||||
|
|
||||||
const onConnectClick = async () => {
|
useEffect(() => {
|
||||||
try {
|
window.api.send("read-setting", "autoConnect");
|
||||||
setConnecting(true);
|
window.api.receive(
|
||||||
const foundDevice = await navigator.bluetooth.requestDevice({
|
"read-setting-success",
|
||||||
|
(res: { key: string; value: any }) => {
|
||||||
|
if (res.key == "autoConnect") {
|
||||||
|
setAutoConnect(res.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
window.api.receive(
|
||||||
|
"user-gesture-reply",
|
||||||
|
async (res: { type: string; promise: Promise<any> }) => {
|
||||||
|
if (res.type == "find-device") {
|
||||||
|
try {
|
||||||
|
const foundDevice = await window.newDevice;
|
||||||
|
console.log("Found device:");
|
||||||
|
console.log(foundDevice);
|
||||||
|
|
||||||
|
await foundDevice.gatt.connect();
|
||||||
|
foundDevice.ongattserverdisconnected = onDisconnect;
|
||||||
|
|
||||||
|
const doorService = await foundDevice.gatt.getPrimaryService(
|
||||||
|
doorServiceUUID,
|
||||||
|
);
|
||||||
|
const doorSwitch = await doorService.getCharacteristic(
|
||||||
|
doorSwitchUUID,
|
||||||
|
);
|
||||||
|
setDevice({
|
||||||
|
device: foundDevice,
|
||||||
|
service: doorService,
|
||||||
|
characteristic: doorSwitch,
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await (await doorSwitch.readValue()).getUint8(0);
|
||||||
|
setDoorOpen(Boolean(data));
|
||||||
|
|
||||||
|
doorSwitch.oncharacteristicvaluechanged = onDoorUpdate;
|
||||||
|
doorSwitch.startNotifications();
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error connecting:");
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
setConnecting(false);
|
||||||
|
window.newDevice = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoConnect && !device && !connecting) {
|
||||||
|
tryConnect();
|
||||||
|
}
|
||||||
|
}, [autoConnect, device, connecting]);
|
||||||
|
|
||||||
|
function onAutoConnectChange(e: Event) {
|
||||||
|
const newVal = (e.currentTarget as any).checked;
|
||||||
|
setAutoConnect(newVal);
|
||||||
|
window.api.send("write-setting", { key: "autoConnect", value: newVal });
|
||||||
|
}
|
||||||
|
|
||||||
|
const tryConnect = async () => {
|
||||||
|
setConnecting(true);
|
||||||
|
//we actually need all this, because otherwise it gives "Must be handling a user gesture..." error
|
||||||
|
//and there doesn't seem to be a way to circumvent this yet
|
||||||
|
//todo: make this at least somewhat less ugly?
|
||||||
|
//similar issue: https://github.com/electron/electron/issues/27625
|
||||||
|
window.api.send("exec-user-gesture", {
|
||||||
|
type: "find-device",
|
||||||
|
function: `
|
||||||
|
window.newDevice = navigator.bluetooth.requestDevice({
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
namePrefix: "Nano",
|
namePrefix: "Nano",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
optionalServices: [doorServiceUUID],
|
optionalServices: [${doorServiceUUIDString}],
|
||||||
});
|
})`,
|
||||||
console.log("Found device:");
|
});
|
||||||
console.log(foundDevice);
|
|
||||||
|
|
||||||
await foundDevice.gatt.connect();
|
|
||||||
foundDevice.ongattserverdisconnected = onDisconnect;
|
|
||||||
|
|
||||||
const doorService = await foundDevice.gatt.getPrimaryService(
|
|
||||||
doorServiceUUID,
|
|
||||||
);
|
|
||||||
const doorSwitch = await doorService.getCharacteristic(doorSwitchUUID);
|
|
||||||
setDevice({
|
|
||||||
device: foundDevice,
|
|
||||||
service: doorService,
|
|
||||||
characteristic: doorSwitch,
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await (await doorSwitch.readValue()).getUint8(0);
|
|
||||||
setDoorOpen(Boolean(data));
|
|
||||||
|
|
||||||
doorSwitch.oncharacteristicvaluechanged = onDoorUpdate;
|
|
||||||
doorSwitch.startNotifications();
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error connecting:");
|
|
||||||
console.log(error);
|
|
||||||
} finally {
|
|
||||||
setConnecting(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDoorUpdate = async (ev: Event) => {
|
const onDoorUpdate = async (e: Event) => {
|
||||||
const characteristic = ev.target as BluetoothRemoteGATTCharacteristic;
|
const characteristic = e.target as BluetoothRemoteGATTCharacteristic;
|
||||||
const parsed = Boolean(await characteristic.value.getUint8(0));
|
const parsed = Boolean(await characteristic.value.getUint8(0));
|
||||||
setDoorOpen(parsed);
|
setDoorOpen(parsed);
|
||||||
new Notification("Door update", { body: parsed ? "Open" : "Closed" });
|
new Notification("Door update", { body: parsed ? "Open" : "Closed" });
|
||||||
@@ -76,9 +121,14 @@ export function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<input
|
||||||
|
onChange={onAutoConnectChange}
|
||||||
|
checked={autoConnect}
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
{connecting && !device && <span>Trying to connect</span>}
|
{connecting && !device && <span>Trying to connect</span>}
|
||||||
{device == null && !connecting && (
|
{device == null && !connecting && (
|
||||||
<button onClick={onConnectClick}>Connect</button>
|
<button onClick={tryConnect}>Connect</button>
|
||||||
)}
|
)}
|
||||||
{device && (
|
{device && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,8 +1,59 @@
|
|||||||
import { app, BrowserWindow } from "electron";
|
import { app, BrowserWindow, ipcMain } from "electron";
|
||||||
|
import * as path from "path";
|
||||||
|
import { JSONFile, Low } from "lowdb";
|
||||||
|
|
||||||
|
interface ISettings {
|
||||||
|
autoConnect: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsPath = path.join(app.getPath("appData"), "settings.json");
|
||||||
|
const settings = new Low<ISettings>(new JSONFile(settingsPath));
|
||||||
|
const settingsRead = false;
|
||||||
|
|
||||||
|
async function initSettings() {
|
||||||
|
if (!settingsRead) {
|
||||||
|
await settings.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.data ||= {
|
||||||
|
autoConnect: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcMain.on("read-setting", async (event, arg: string) => {
|
||||||
|
await initSettings();
|
||||||
|
if (Object.keys(settings.data).includes(arg)) {
|
||||||
|
event.reply("read-setting-success", {
|
||||||
|
key: arg,
|
||||||
|
value: settings.data[arg as keyof ISettings],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
event.reply("read-setting-error", {
|
||||||
|
key: arg,
|
||||||
|
error: "bad key",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
"write-setting",
|
||||||
|
async (event, arg: { key: keyof ISettings; value: any }) => {
|
||||||
|
await initSettings();
|
||||||
|
settings.data[arg.key] = arg.value;
|
||||||
|
try {
|
||||||
|
await settings.write();
|
||||||
|
event.reply("write-setting-success", arg.key);
|
||||||
|
} catch (e) {
|
||||||
|
event.reply("write-setting-fail", { key: arg.key, error: e });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack
|
// This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack
|
||||||
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
|
// plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on
|
||||||
// whether you're running in development or production).
|
// whether you're running in development or production).
|
||||||
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
declare const MAIN_WINDOW_WEBPACK_ENTRY: string;
|
||||||
|
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: any;
|
||||||
|
|
||||||
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
|
||||||
if (require("electron-squirrel-startup")) {
|
if (require("electron-squirrel-startup")) {
|
||||||
@@ -15,6 +66,9 @@ const createWindow = (): void => {
|
|||||||
const mainWindow = new BrowserWindow({
|
const mainWindow = new BrowserWindow({
|
||||||
height: 600,
|
height: 600,
|
||||||
width: 800,
|
width: 800,
|
||||||
|
webPreferences: {
|
||||||
|
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.webContents.on(
|
mainWindow.webContents.on(
|
||||||
@@ -27,6 +81,17 @@ const createWindow = (): void => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ipcMain.on(
|
||||||
|
"exec-user-gesture",
|
||||||
|
async (event, arg: { type: string; function: string }) => {
|
||||||
|
await mainWindow.webContents.executeJavaScript(arg.function, true);
|
||||||
|
event.reply("user-gesture-reply", {
|
||||||
|
type: arg.type,
|
||||||
|
promise: "aaaah",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// and load the index.html of the app.
|
// and load the index.html of the app.
|
||||||
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
|
mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
|
||||||
|
|
||||||
|
|||||||
29
door-thing-app/src/preload.ts
Normal file
29
door-thing-app/src/preload.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { contextBridge, ipcRenderer } from "electron";
|
||||||
|
|
||||||
|
//todo: renderer.d.ts
|
||||||
|
contextBridge.exposeInMainWorld("api", {
|
||||||
|
send: (channel: string, data: any) => {
|
||||||
|
// whitelist channels
|
||||||
|
const validChannels = [
|
||||||
|
"read-setting",
|
||||||
|
"write-setting",
|
||||||
|
"exec-user-gesture",
|
||||||
|
];
|
||||||
|
if (validChannels.includes(channel)) {
|
||||||
|
ipcRenderer.send(channel, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
receive: (channel: string, func: any) => {
|
||||||
|
const validChannels = [
|
||||||
|
"read-setting-success",
|
||||||
|
"read-setting-error",
|
||||||
|
"write-setting-success",
|
||||||
|
"write-setting-fail",
|
||||||
|
"user-gesture-reply",
|
||||||
|
];
|
||||||
|
if (validChannels.includes(channel)) {
|
||||||
|
// Deliberately strip event as it includes `sender`
|
||||||
|
ipcRenderer.on(channel, (event, ...args) => func(...args));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
11
door-thing-app/src/renderer.d.ts
vendored
Normal file
11
door-thing-app/src/renderer.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export interface IElectronAPI {
|
||||||
|
send: (channel: string, data: any) => Promise<void>;
|
||||||
|
receive: (channel: string, func: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
api: IElectronAPI;
|
||||||
|
newDevice: Promise<BluetoothDevice> | null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "preact"
|
"jsxImportSource": "preact"
|
||||||
},
|
},
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"],
|
||||||
|
"files": ["src/renderer.d.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user