hardware-example 1.1.34-alpha.3 → 1.2.0-alpha.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -2
- package/electron-builder.config.js +1 -28
- package/package.json +7 -10
- package/src/config.ts +0 -4
- package/src/index.ts +3 -70
- package/src/preload.ts +16 -19
- package/public/bin/bridge/linux-arm64/onekeyd +0 -0
- package/public/bin/bridge/linux-x64/onekeyd +0 -0
- package/public/bin/bridge/mac-arm64/onekeyd +0 -0
- package/public/bin/bridge/mac-x64/onekeyd +0 -0
- package/public/bin/bridge/win-x64/onekeyd.exe +0 -0
- package/scripts/copy-injected.js +0 -38
- package/src/process/BaseProcess.ts +0 -212
- package/src/process/Bridge.ts +0 -93
- package/src/process/index.ts +0 -36
package/README.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
|
|
2
|
-
#
|
|
2
|
+
# Electron Connect Example
|
|
3
|
+
|
|
4
|
+
此示例使用 `@onekeyfe/hd-common-connect-sdk` 的 `desktop-web-ble` 环境,并通过 Electron
|
|
5
|
+
Noble BLE Transport 连接设备。示例不再启动 OneKey Bridge,也不再注入 `hd-web-sdk` iframe。
|
|
6
|
+
|
|
7
|
+
Pro2 会在真实连接响应中完成 Protocol V2 探测;应用层不要根据 BLE 名称或设备型号猜测协议。
|
|
8
|
+
连接后的 SDK 调用和自动化测试沿用 `expo-example` 的 Core API,因此 V1 与 V2 共用同一套生命周期。
|
|
9
|
+
|
|
10
|
+
开发运行:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
yarn example:desktop
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
打包前会先构建 Electron 主进程和 Expo Web 资源:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
yarn build:example:desktop:mac
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Q & A
|
|
23
|
+
|
|
3
24
|
## The mac running message is damaged and cannot be opened. You should move it to the trash.
|
|
4
25
|
### Intel Mac
|
|
5
26
|
1. Open settings
|
|
@@ -19,4 +40,3 @@ sudo /usr/bin/xattr -c /Applications/YourAppName.app
|
|
|
19
40
|
```bash
|
|
20
41
|
sudo xattr -r -d com.apple.quarantine /Applications/YourAppName.app
|
|
21
42
|
```
|
|
22
|
-
|
|
@@ -20,16 +20,7 @@ module.exports = {
|
|
|
20
20
|
directories: {
|
|
21
21
|
output: 'out',
|
|
22
22
|
},
|
|
23
|
-
files: [
|
|
24
|
-
'web-build',
|
|
25
|
-
'public',
|
|
26
|
-
'bin',
|
|
27
|
-
'!public/bin/**/*',
|
|
28
|
-
'dist/**/*.js',
|
|
29
|
-
'!dist/__**',
|
|
30
|
-
'package.json',
|
|
31
|
-
'!scripts/**',
|
|
32
|
-
],
|
|
23
|
+
files: ['web-build', 'public', 'dist/**/*.js', '!dist/__**', 'package.json', '!scripts/**'],
|
|
33
24
|
extraResources: [
|
|
34
25
|
{
|
|
35
26
|
from: 'public/icons/512x512.png',
|
|
@@ -60,12 +51,6 @@ module.exports = {
|
|
|
60
51
|
mac: {
|
|
61
52
|
// skip code signing
|
|
62
53
|
identity: null,
|
|
63
|
-
extraResources: [
|
|
64
|
-
{
|
|
65
|
-
from: 'public/bin/bridge/mac-${arch}',
|
|
66
|
-
to: 'bin/bridge',
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
54
|
icon: 'public/icons/512x512.png',
|
|
70
55
|
artifactName: 'Hardware-Example-mac-${arch}.${ext}',
|
|
71
56
|
hardenedRuntime: true,
|
|
@@ -82,12 +67,6 @@ module.exports = {
|
|
|
82
67
|
},
|
|
83
68
|
},
|
|
84
69
|
win: {
|
|
85
|
-
extraResources: [
|
|
86
|
-
{
|
|
87
|
-
from: 'public/bin/bridge/win-${arch}',
|
|
88
|
-
to: 'bin/bridge',
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
70
|
icon: 'public/icons/512x512.png',
|
|
92
71
|
artifactName: 'Hardware-Example-win-${arch}.${ext}',
|
|
93
72
|
verifyUpdateCodeSignature: false,
|
|
@@ -99,12 +78,6 @@ module.exports = {
|
|
|
99
78
|
],
|
|
100
79
|
},
|
|
101
80
|
linux: {
|
|
102
|
-
extraResources: [
|
|
103
|
-
{
|
|
104
|
-
from: 'public/bin/bridge/linux-${arch}',
|
|
105
|
-
to: 'bin/bridge',
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
81
|
icon: 'public/icons/512x512.png',
|
|
109
82
|
artifactName: 'Hardware-Example-linux-${arch}.${ext}',
|
|
110
83
|
executableName: 'onekey-hardware-example',
|
package/package.json
CHANGED
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
"name": "hardware-example",
|
|
3
3
|
"productName": "HardwareExample",
|
|
4
4
|
"executableName": "onekey-hardware-example",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.2.0-alpha.100",
|
|
6
6
|
"author": "OneKey",
|
|
7
|
-
"description": "
|
|
7
|
+
"description": "OneKey Hardware SDK Electron BLE example",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"license": "GPL-3.0-only",
|
|
10
10
|
"scripts": {
|
|
11
|
-
"copy:inject": "node scripts/copy-injected.js",
|
|
12
11
|
"clean:build": "rimraf out",
|
|
13
|
-
"dev-electron-web": "cross-env NODE_ENV=development yarn
|
|
14
|
-
"build-electron-web": "yarn
|
|
12
|
+
"dev-electron-web": "cross-env NODE_ENV=development yarn build:main && cd ../expo-example && yarn dev:electron-web",
|
|
13
|
+
"build-electron-web": "yarn build:main && cd ../expo-example && yarn build:electron-web",
|
|
15
14
|
"dev": "npx concurrently \"yarn dev:electron\" \"cross-env TRANSFORM_REGENERATOR_DISABLED=true BROWSER=none yarn dev-electron-web\"",
|
|
16
15
|
"dev:electron": "electron --inspect=5858 dist/index.js",
|
|
17
16
|
"build:main": "webpack --config webpack.config.ts",
|
|
@@ -22,14 +21,12 @@
|
|
|
22
21
|
"ts:check": "yarn tsc --noEmit"
|
|
23
22
|
},
|
|
24
23
|
"dependencies": {
|
|
25
|
-
"@onekeyfe/hd-transport-electron": "1.
|
|
24
|
+
"@onekeyfe/hd-transport-electron": "1.2.0-alpha.100",
|
|
26
25
|
"@stoprocent/noble": "2.3.16",
|
|
27
26
|
"debug": "4.3.4",
|
|
28
27
|
"electron-is-dev": "^3.0.1",
|
|
29
28
|
"electron-log": "^5.1.5",
|
|
30
|
-
"electron-updater": "^6.2.1"
|
|
31
|
-
"fs-extra": "^11.2.0",
|
|
32
|
-
"node-fetch": "^2.6.7"
|
|
29
|
+
"electron-updater": "^6.2.1"
|
|
33
30
|
},
|
|
34
31
|
"devDependencies": {
|
|
35
32
|
"@types/webpack": "^5.28.5",
|
|
@@ -45,5 +42,5 @@
|
|
|
45
42
|
"**/node-gyp": "^10.0.1",
|
|
46
43
|
"tmp": "0.2.4"
|
|
47
44
|
},
|
|
48
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "4e70f0a01da0c3c2dab687b8c4bf4f18cf4ad0c0"
|
|
49
46
|
}
|
package/src/config.ts
CHANGED
|
@@ -4,9 +4,5 @@ export const ipcMessageKeys = {
|
|
|
4
4
|
UPDATE_DOWNLOADED: 'update/downloaded',
|
|
5
5
|
UPDATE_RESTART: 'update/restartApp',
|
|
6
6
|
|
|
7
|
-
APP_RELOAD_BRIDGE_PROCESS: 'app/reloadBridgeProcess',
|
|
8
|
-
|
|
9
|
-
INJECT_ONEKEY_DESKTOP_GLOBALS: 'inject/onekeyDesktop',
|
|
10
|
-
|
|
11
7
|
APP_RESTART: 'app/restart',
|
|
12
8
|
};
|
package/src/index.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { autoUpdater } from 'electron-updater';
|
|
|
7
7
|
import { exec } from 'child_process';
|
|
8
8
|
import { initNobleBleSupport } from '@onekeyfe/hd-transport-electron';
|
|
9
9
|
|
|
10
|
-
import initProcess, { restartBridge } from './process';
|
|
11
10
|
import { ipcMessageKeys } from './config';
|
|
12
11
|
|
|
13
12
|
// Set log level
|
|
@@ -24,21 +23,6 @@ let mainWindow: BrowserWindow | null;
|
|
|
24
23
|
|
|
25
24
|
let isAppReady = false;
|
|
26
25
|
|
|
27
|
-
(global as any).resourcesPath = isDevelopment
|
|
28
|
-
? path.join(__dirname, '../public')
|
|
29
|
-
: path.join(process.resourcesPath, 'app');
|
|
30
|
-
const staticPath = isDevelopment
|
|
31
|
-
? path.join(__dirname, '../public')
|
|
32
|
-
: path.join((global as any).resourcesPath, 'public');
|
|
33
|
-
|
|
34
|
-
const sdkConnectSrc = isDevelopment
|
|
35
|
-
? `file://${path.join(staticPath, 'js-sdk/')}`
|
|
36
|
-
: path.join('public', 'js-sdk/');
|
|
37
|
-
|
|
38
|
-
function initChildProcess() {
|
|
39
|
-
return initProcess({ isDevelopment });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
26
|
function showMainWindow() {
|
|
43
27
|
if (!mainWindow) {
|
|
44
28
|
return;
|
|
@@ -80,13 +64,11 @@ function createMainWindow() {
|
|
|
80
64
|
height: Math.min(1920 / ratio, dimensions.height),
|
|
81
65
|
webPreferences: {
|
|
82
66
|
spellcheck: false,
|
|
83
|
-
webviewTag: true,
|
|
84
67
|
webSecurity: !isDevelopment,
|
|
85
68
|
// @ts-expect-error
|
|
86
69
|
nativeWindowOpen: true,
|
|
87
70
|
allowRunningInsecureContent: isDevelopment,
|
|
88
|
-
|
|
89
|
-
contextIsolation: false,
|
|
71
|
+
contextIsolation: true,
|
|
90
72
|
preload: path.join(__dirname, 'preload.js'),
|
|
91
73
|
sandbox: false,
|
|
92
74
|
},
|
|
@@ -96,15 +78,6 @@ function createMainWindow() {
|
|
|
96
78
|
browserWindow.webContents.openDevTools();
|
|
97
79
|
}
|
|
98
80
|
|
|
99
|
-
browserWindow.webContents.on('did-finish-load', () => {
|
|
100
|
-
console.log('browserWindow >>>> did-finish-load');
|
|
101
|
-
browserWindow.webContents.send(ipcMessageKeys.INJECT_ONEKEY_DESKTOP_GLOBALS, {
|
|
102
|
-
resourcesPath: (global as any).resourcesPath,
|
|
103
|
-
staticPath: `file://${staticPath}`,
|
|
104
|
-
sdkConnectSrc,
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
81
|
const src = isDevelopment
|
|
109
82
|
? 'http://localhost:19006/'
|
|
110
83
|
: formatUrl({
|
|
@@ -134,25 +107,9 @@ function createMainWindow() {
|
|
|
134
107
|
console.log('set isAppReady on browserWindow dom-ready', isAppReady);
|
|
135
108
|
});
|
|
136
109
|
|
|
137
|
-
const filter = {
|
|
138
|
-
urls: ['http://127.0.0.1:21320/*', 'http://localhost:21320/*'],
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
|
|
142
|
-
const { url } = details;
|
|
143
|
-
if (url.startsWith('http://127.0.0.1:21320/') || url.startsWith('http://localhost:21320/')) {
|
|
144
|
-
// resolve onekey bridge CORS error
|
|
145
|
-
details.requestHeaders.Origin = 'https://jssdk.onekey.so';
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
callback({ cancel: false, requestHeaders: details.requestHeaders });
|
|
149
|
-
});
|
|
150
|
-
|
|
151
110
|
// 记录已授权的设备
|
|
152
|
-
let grantedDeviceThroughPermHandler = null;
|
|
153
|
-
|
|
154
111
|
browserWindow.webContents.session.setPermissionCheckHandler(
|
|
155
|
-
(
|
|
112
|
+
(_webContents, permission, requestingOrigin, details) => {
|
|
156
113
|
log.debug('WebUSB: 权限检查被调用:', {
|
|
157
114
|
permission,
|
|
158
115
|
requestingOrigin,
|
|
@@ -177,7 +134,6 @@ function createMainWindow() {
|
|
|
177
134
|
// 允许所有 USB 设备请求
|
|
178
135
|
if (details.deviceType === 'usb') {
|
|
179
136
|
log.debug('WebUSB: 记录已授权的设备');
|
|
180
|
-
grantedDeviceThroughPermHandler = details.device;
|
|
181
137
|
return true;
|
|
182
138
|
}
|
|
183
139
|
return false;
|
|
@@ -213,24 +169,6 @@ function createMainWindow() {
|
|
|
213
169
|
if (!isDevelopment) {
|
|
214
170
|
const PROTOCOL = 'file';
|
|
215
171
|
session.defaultSession.protocol.interceptFileProtocol(PROTOCOL, (request, callback) => {
|
|
216
|
-
const isJsSdkFile = request.url.indexOf('/public/js-sdk') > -1;
|
|
217
|
-
const isIFrameHtml = request.url.indexOf('/public/js-sdk/iframe.html') > -1;
|
|
218
|
-
|
|
219
|
-
// resolve iframe path
|
|
220
|
-
if (isJsSdkFile && isIFrameHtml) {
|
|
221
|
-
callback({
|
|
222
|
-
path: path.join(__dirname, '..', 'public', 'js-sdk', 'iframe.html'),
|
|
223
|
-
});
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// resolve jssdk path
|
|
228
|
-
if (isJsSdkFile) {
|
|
229
|
-
const url = request.url.substr(PROTOCOL.length + 1);
|
|
230
|
-
callback(path.join(__dirname, '..', url));
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
172
|
// resolve main app path
|
|
235
173
|
let url = request.url.substr(PROTOCOL.length + 1);
|
|
236
174
|
url = path.join(__dirname, '..', 'web-build', url);
|
|
@@ -271,7 +209,7 @@ const singleInstance = app.requestSingleInstanceLock();
|
|
|
271
209
|
if (!singleInstance && !process.mas) {
|
|
272
210
|
quitOrMinimizeApp();
|
|
273
211
|
} else {
|
|
274
|
-
app.on('second-instance', (
|
|
212
|
+
app.on('second-instance', (_event, _argv) => {
|
|
275
213
|
if (mainWindow) {
|
|
276
214
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
|
277
215
|
showMainWindow();
|
|
@@ -292,7 +230,6 @@ if (!singleInstance && !process.mas) {
|
|
|
292
230
|
log.error('Failed to initialize Noble BLE support:', e);
|
|
293
231
|
}
|
|
294
232
|
|
|
295
|
-
initChildProcess();
|
|
296
233
|
showMainWindow();
|
|
297
234
|
console.log('日志文件位置:', log.transports.file.getFile().path);
|
|
298
235
|
});
|
|
@@ -303,10 +240,6 @@ ipcMain.on(ipcMessageKeys.UPDATE_RESTART, () => {
|
|
|
303
240
|
autoUpdater.quitAndInstall();
|
|
304
241
|
});
|
|
305
242
|
|
|
306
|
-
ipcMain.on(ipcMessageKeys.APP_RELOAD_BRIDGE_PROCESS, () => {
|
|
307
|
-
restartBridge();
|
|
308
|
-
});
|
|
309
|
-
|
|
310
243
|
// Simplified Bluetooth System API Implementation
|
|
311
244
|
class BluetoothSystemManager {
|
|
312
245
|
openBluetoothSettings(): void {
|
package/src/preload.ts
CHANGED
|
@@ -5,7 +5,11 @@ import { EOneKeyBleMessageKeys } from '@onekeyfe/hd-shared';
|
|
|
5
5
|
|
|
6
6
|
import { ipcMessageKeys } from './config';
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
DesktopAPI as BaseDesktopAPI,
|
|
10
|
+
NobleBleAPI,
|
|
11
|
+
NobleBleWriteOptions,
|
|
12
|
+
} from '@onekeyfe/hd-transport-electron';
|
|
9
13
|
|
|
10
14
|
// Simplified Bluetooth system API - only for opening settings
|
|
11
15
|
export interface BluetoothSystemAPI {
|
|
@@ -17,7 +21,6 @@ export interface BluetoothSystemAPI {
|
|
|
17
21
|
// Extend the base DesktopAPI with this specific application's needs
|
|
18
22
|
export interface DesktopAPI extends BaseDesktopAPI {
|
|
19
23
|
restart: () => void;
|
|
20
|
-
reloadBridgeProcess: () => void;
|
|
21
24
|
|
|
22
25
|
// Generic IPC methods
|
|
23
26
|
invoke: (channel: string, ...args: any[]) => Promise<any>;
|
|
@@ -44,17 +47,6 @@ const validChannels = [
|
|
|
44
47
|
ipcMessageKeys.UPDATE_DOWNLOADED,
|
|
45
48
|
];
|
|
46
49
|
|
|
47
|
-
ipcRenderer.on(ipcMessageKeys.INJECT_ONEKEY_DESKTOP_GLOBALS, (_, globals) => {
|
|
48
|
-
try {
|
|
49
|
-
contextBridge.exposeInMainWorld('ONEKEY_DESKTOP_GLOBALS', globals);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
// @ts-expect-error
|
|
52
|
-
window.ONEKEY_DESKTOP_GLOBALS = globals;
|
|
53
|
-
// Fallback for development or when contextBridge is not available
|
|
54
|
-
console.warn('Failed to expose ONEKEY_DESKTOP_GLOBALS via contextBridge:', error);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
50
|
const desktopApi = {
|
|
59
51
|
// Generic IPC methods
|
|
60
52
|
invoke: (channel: string, ...args: any[]) => ipcRenderer.invoke(channel, ...args),
|
|
@@ -75,10 +67,6 @@ const desktopApi = {
|
|
|
75
67
|
updateReload: () => {
|
|
76
68
|
ipcRenderer.send(ipcMessageKeys.UPDATE_RESTART);
|
|
77
69
|
},
|
|
78
|
-
reloadBridgeProcess: () => {
|
|
79
|
-
ipcRenderer.send(ipcMessageKeys.APP_RELOAD_BRIDGE_PROCESS);
|
|
80
|
-
},
|
|
81
|
-
|
|
82
70
|
// Noble BLE specific methods
|
|
83
71
|
nobleBle: {
|
|
84
72
|
enumerate: () => ipcRenderer.invoke(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE),
|
|
@@ -91,8 +79,8 @@ const desktopApi = {
|
|
|
91
79
|
ipcRenderer.invoke(EOneKeyBleMessageKeys.NOBLE_BLE_SUBSCRIBE, uuid),
|
|
92
80
|
unsubscribe: (uuid: string) =>
|
|
93
81
|
ipcRenderer.invoke(EOneKeyBleMessageKeys.NOBLE_BLE_UNSUBSCRIBE, uuid),
|
|
94
|
-
write: (uuid: string, data: string) =>
|
|
95
|
-
ipcRenderer.invoke(EOneKeyBleMessageKeys.NOBLE_BLE_WRITE, uuid, data),
|
|
82
|
+
write: (uuid: string, data: string, options?: NobleBleWriteOptions) =>
|
|
83
|
+
ipcRenderer.invoke(EOneKeyBleMessageKeys.NOBLE_BLE_WRITE, uuid, data, options),
|
|
96
84
|
onNotification: (callback: (deviceId: string, data: string) => void) => {
|
|
97
85
|
const subscription = (_: unknown, deviceId: string, data: string) => {
|
|
98
86
|
callback(deviceId, data);
|
|
@@ -102,6 +90,15 @@ const desktopApi = {
|
|
|
102
90
|
ipcRenderer.removeListener(EOneKeyBleMessageKeys.NOBLE_BLE_NOTIFICATION, subscription);
|
|
103
91
|
};
|
|
104
92
|
},
|
|
93
|
+
onMtuChanged: (callback: (device: { id: string; mtu: number }) => void) => {
|
|
94
|
+
const subscription = (_: unknown, device: { id: string; mtu: number }) => {
|
|
95
|
+
callback(device);
|
|
96
|
+
};
|
|
97
|
+
ipcRenderer.on(EOneKeyBleMessageKeys.NOBLE_BLE_MTU_CHANGED, subscription);
|
|
98
|
+
return () => {
|
|
99
|
+
ipcRenderer.removeListener(EOneKeyBleMessageKeys.NOBLE_BLE_MTU_CHANGED, subscription);
|
|
100
|
+
};
|
|
101
|
+
},
|
|
105
102
|
onDeviceDisconnected: (callback: (device: { id: string; name: string }) => void) => {
|
|
106
103
|
const subscription = (_: unknown, device: { id: string; name: string }) => {
|
|
107
104
|
callback(device);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/scripts/copy-injected.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const rootDir = path.join(__dirname, '../../../../');
|
|
6
|
-
|
|
7
|
-
const sourceDir = path.join(rootDir, 'node_modules/@onekeyfe/hd-web-sdk/build/');
|
|
8
|
-
const targetDir = path.join(rootDir, 'packages/connect-examples/electron-example/public/js-sdk/');
|
|
9
|
-
|
|
10
|
-
async function copyFiles() {
|
|
11
|
-
try {
|
|
12
|
-
await fs.remove(targetDir);
|
|
13
|
-
await fs.ensureDir(targetDir);
|
|
14
|
-
console.log(`Target directory ${targetDir} is ensured`);
|
|
15
|
-
|
|
16
|
-
await fs.copy(sourceDir, targetDir, {
|
|
17
|
-
recursive: true,
|
|
18
|
-
overwrite: true,
|
|
19
|
-
filter: (src, dest) => {
|
|
20
|
-
// Don't copy onekey-js-sdk
|
|
21
|
-
if (src.endsWith('onekey-js-sdk.min.js') || src.endsWith('onekey-js-sdk.js')) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Don't copy source maps
|
|
26
|
-
if (src.endsWith('.map')) {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
return true;
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
console.log(`Files copied from ${sourceDir} to ${targetDir}`);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
console.error('Error copying files:', error);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
copyFiles();
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import electron from 'electron';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
import type { ChildProcess } from 'child_process';
|
|
6
|
-
|
|
7
|
-
export type Status = {
|
|
8
|
-
service: boolean;
|
|
9
|
-
process: boolean;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export type Options = {
|
|
13
|
-
startupThrottleTime?: number;
|
|
14
|
-
stopWaitTimes?: number;
|
|
15
|
-
autoRestart?: number;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const defaultOptions: Options = {
|
|
19
|
-
startupThrottleTime: 0,
|
|
20
|
-
stopWaitTimes: 10,
|
|
21
|
-
autoRestart: 2,
|
|
22
|
-
} as const;
|
|
23
|
-
|
|
24
|
-
export default abstract class BaseProcess {
|
|
25
|
-
process: ChildProcess | null;
|
|
26
|
-
|
|
27
|
-
resource: string;
|
|
28
|
-
|
|
29
|
-
processName: string;
|
|
30
|
-
|
|
31
|
-
options: Options;
|
|
32
|
-
|
|
33
|
-
launchThrottle: ReturnType<typeof setTimeout> | null;
|
|
34
|
-
|
|
35
|
-
supportedSystems = ['mac-x64', 'win-x64', 'linux-arm64', 'linux-x64'];
|
|
36
|
-
|
|
37
|
-
stopped = false;
|
|
38
|
-
|
|
39
|
-
constructor(resource: string, processName: string, options: Options = defaultOptions) {
|
|
40
|
-
this.process = null;
|
|
41
|
-
this.launchThrottle = null;
|
|
42
|
-
this.resource = resource;
|
|
43
|
-
this.processName = processName;
|
|
44
|
-
this.options = {
|
|
45
|
-
...defaultOptions,
|
|
46
|
-
...options,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const { system } = this.getPlatformInfo();
|
|
50
|
-
if (!this.isSystemSupported(system)) {
|
|
51
|
-
console.error('Unsupported system:', system);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
abstract getStatus(): Promise<{ service: boolean; process: boolean }>;
|
|
56
|
-
|
|
57
|
-
async start(params: string[] = [], isDev = false) {
|
|
58
|
-
const { system, ext } = this.getPlatformInfo();
|
|
59
|
-
if (this.launchThrottle) {
|
|
60
|
-
console.debug('Throttling launch, cancel process');
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const status = await this.getStatus();
|
|
65
|
-
|
|
66
|
-
if (status.service) {
|
|
67
|
-
console.debug('Service already running');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (status.process) {
|
|
72
|
-
console.debug('Process already running, service not');
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (this.options.startupThrottleTime && this.options.startupThrottleTime > 0) {
|
|
77
|
-
console.debug('Throttling startup');
|
|
78
|
-
|
|
79
|
-
this.launchThrottle = setTimeout(() => {
|
|
80
|
-
console.debug('Cleaning up launch throttle');
|
|
81
|
-
this.launchThrottle = null;
|
|
82
|
-
}, this.options.startupThrottleTime * 1000);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
this.stopped = false;
|
|
86
|
-
|
|
87
|
-
const appPath = electron.app.getAppPath();
|
|
88
|
-
let processDir;
|
|
89
|
-
if (isDev) {
|
|
90
|
-
processDir = path.resolve(appPath, '../', 'public', 'bin', this.resource, system);
|
|
91
|
-
} else {
|
|
92
|
-
processDir = path.resolve(appPath, '../', 'bin', this.resource);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const processPath = path.join(processDir, `${this.processName}${ext}`);
|
|
96
|
-
const processEnv = { ...process.env };
|
|
97
|
-
// library search path for macOS
|
|
98
|
-
processEnv.DYLD_LIBRARY_PATH = processEnv.DYLD_LIBRARY_PATH
|
|
99
|
-
? `${processEnv.DYLD_LIBRARY_PATH}:${processDir}`
|
|
100
|
-
: `${processDir}`;
|
|
101
|
-
// library search path for Linux
|
|
102
|
-
processEnv.LD_LIBRARY_PATH = processEnv.LD_LIBRARY_PATH
|
|
103
|
-
? `${processEnv.LD_LIBRARY_PATH}:${processDir}`
|
|
104
|
-
: `${processDir}`;
|
|
105
|
-
|
|
106
|
-
console.info([
|
|
107
|
-
'Starting process:',
|
|
108
|
-
`- Path: ${processPath}`,
|
|
109
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
110
|
-
`- Params: ${params}`,
|
|
111
|
-
`- CWD: ${processDir}`,
|
|
112
|
-
]);
|
|
113
|
-
this.process = spawn(processPath, params, {
|
|
114
|
-
cwd: processDir,
|
|
115
|
-
env: processEnv,
|
|
116
|
-
stdio: ['ignore', 'ignore', 'ignore'],
|
|
117
|
-
});
|
|
118
|
-
this.process.on('error', err => this.onError(err));
|
|
119
|
-
this.process.on('exit', code => this.onExit(code));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Stops the process
|
|
124
|
-
*/
|
|
125
|
-
stop() {
|
|
126
|
-
return new Promise<void>(resolve => {
|
|
127
|
-
this.stopped = true;
|
|
128
|
-
|
|
129
|
-
if (!this.process) {
|
|
130
|
-
console.warn('process already stopped');
|
|
131
|
-
resolve();
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.debug('Stopping process');
|
|
136
|
-
this.process.kill();
|
|
137
|
-
|
|
138
|
-
let timeout = 0;
|
|
139
|
-
const interval = setInterval(() => {
|
|
140
|
-
if (!this.process || this.process.killed) {
|
|
141
|
-
console.info('Process killed successfully');
|
|
142
|
-
clearInterval(interval);
|
|
143
|
-
this.process = null;
|
|
144
|
-
resolve();
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (this.options.stopWaitTimes && timeout < this.options.stopWaitTimes) {
|
|
149
|
-
console.info('Process Still alive, checking again...');
|
|
150
|
-
timeout += 1;
|
|
151
|
-
} else {
|
|
152
|
-
console.info('Process Still alive, going for the SIGKILL');
|
|
153
|
-
this.process.kill('SIGKILL');
|
|
154
|
-
}
|
|
155
|
-
}, 1000);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async restart() {
|
|
160
|
-
console.info('Restarting');
|
|
161
|
-
await this.stop();
|
|
162
|
-
await this.start();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
onError(err: Error) {
|
|
166
|
-
console.error('Process exit error: ', err.message);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
onExit(code: number | null) {
|
|
170
|
-
console.info(
|
|
171
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
172
|
-
`Exited, code: ${code ?? 'unknown'} (Stopped: ${this.stopped})`
|
|
173
|
-
);
|
|
174
|
-
this.process = null;
|
|
175
|
-
|
|
176
|
-
if (this.options.autoRestart && this.options.autoRestart > 0 && !this.stopped) {
|
|
177
|
-
console.debug('restarting...');
|
|
178
|
-
let restartDelay = this.options.autoRestart;
|
|
179
|
-
|
|
180
|
-
// Add throttle delay to prevent the process from never restarting if the throttle is hit
|
|
181
|
-
if (this.launchThrottle && this.options.startupThrottleTime) {
|
|
182
|
-
restartDelay += this.options.startupThrottleTime;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
setTimeout(() => this.start(), restartDelay * 1000);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
isSystemSupported(system: string) {
|
|
190
|
-
return this.supportedSystems.includes(system);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
getPlatformInfo() {
|
|
194
|
-
const { arch } = process;
|
|
195
|
-
const platform = this.getPlatform();
|
|
196
|
-
const ext = platform === 'win' ? '.exe' : '';
|
|
197
|
-
const system = `${platform}-${arch}`;
|
|
198
|
-
console.debug('arch: ', arch);
|
|
199
|
-
return { system, platform, arch, ext };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
getPlatform() {
|
|
203
|
-
switch (process.platform) {
|
|
204
|
-
case 'darwin':
|
|
205
|
-
return 'mac';
|
|
206
|
-
case 'win32':
|
|
207
|
-
return 'win';
|
|
208
|
-
default:
|
|
209
|
-
return process.platform;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
package/src/process/Bridge.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
2
|
-
import fetch from 'node-fetch';
|
|
3
|
-
|
|
4
|
-
import BaseProcess from './BaseProcess';
|
|
5
|
-
|
|
6
|
-
import type { Status } from './BaseProcess';
|
|
7
|
-
|
|
8
|
-
class BridgeProcess extends BaseProcess {
|
|
9
|
-
constructor() {
|
|
10
|
-
super('bridge', 'onekeyd', {
|
|
11
|
-
startupThrottleTime: 3,
|
|
12
|
-
});
|
|
13
|
-
console.info('logger file name =====> :');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async getStatus(): Promise<Status> {
|
|
17
|
-
try {
|
|
18
|
-
const resp = await fetch(`http://127.0.0.1:21320/`, {
|
|
19
|
-
method: 'POST',
|
|
20
|
-
headers: {
|
|
21
|
-
Origin: 'https://electron.onekey.so',
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
console.debug(`Checking status (${resp.status})`);
|
|
25
|
-
if (resp.status === 200) {
|
|
26
|
-
const data = await resp.json();
|
|
27
|
-
if (data?.version) {
|
|
28
|
-
return {
|
|
29
|
-
service: true,
|
|
30
|
-
process: true,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
} catch (err: any) {
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
36
|
-
console.error(`Status error: ${err.message}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// process
|
|
40
|
-
return {
|
|
41
|
-
service: false,
|
|
42
|
-
process: Boolean(this.process),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function fetchWithTimeout(url: string, options: RequestInit & { timeout: number }) {
|
|
48
|
-
const { timeout = 3000 } = options;
|
|
49
|
-
|
|
50
|
-
const controller = new AbortController();
|
|
51
|
-
const id = setTimeout(() => controller.abort(), timeout);
|
|
52
|
-
// @ts-expect-error
|
|
53
|
-
const response = await fetch(url, {
|
|
54
|
-
...options,
|
|
55
|
-
signal: controller.signal as any,
|
|
56
|
-
});
|
|
57
|
-
clearTimeout(id);
|
|
58
|
-
return response;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export const BridgeHeart = {
|
|
62
|
-
timer: null as ReturnType<typeof setInterval> | null,
|
|
63
|
-
start: (callback: () => void) => {
|
|
64
|
-
const checkBridge = async () => {
|
|
65
|
-
try {
|
|
66
|
-
const localBridgeUrl = 'http://127.0.0.1:21320/';
|
|
67
|
-
const resp = await fetchWithTimeout(localBridgeUrl, {
|
|
68
|
-
method: 'POST',
|
|
69
|
-
headers: {
|
|
70
|
-
Origin: 'https://electron.onekey.so',
|
|
71
|
-
},
|
|
72
|
-
timeout: 3000,
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
if (resp.status !== 200) {
|
|
76
|
-
console.debug(`Bridge Heart Checking ${localBridgeUrl} (${resp.status})`);
|
|
77
|
-
// check bridge failed, restart it
|
|
78
|
-
callback?.();
|
|
79
|
-
}
|
|
80
|
-
} catch (err: any) {
|
|
81
|
-
console.error(
|
|
82
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
83
|
-
`Bridge heart check error, will restart bridge process: ${err.message}`
|
|
84
|
-
);
|
|
85
|
-
callback?.();
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
BridgeHeart.timer = setInterval(checkBridge, 10000);
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export default BridgeProcess;
|
package/src/process/index.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { app } from 'electron';
|
|
2
|
-
|
|
3
|
-
import BridgeProcess, { BridgeHeart } from './Bridge';
|
|
4
|
-
|
|
5
|
-
let bridgeInstance: BridgeProcess;
|
|
6
|
-
export const launchBridge = async (isDevelopment: boolean) => {
|
|
7
|
-
const bridge = new BridgeProcess();
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
console.info('bridge: Staring');
|
|
11
|
-
await bridge.start([], isDevelopment);
|
|
12
|
-
bridgeInstance = bridge;
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
14
|
-
BridgeHeart.start(() => restartBridge());
|
|
15
|
-
} catch (err) {
|
|
16
|
-
console.error(`bridge: Start failed: ${(err as Error).message}`);
|
|
17
|
-
console.error(err);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
app.on('before-quit', () => {
|
|
21
|
-
console.info('bridge', 'Stopping when app quit');
|
|
22
|
-
bridge.stop();
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const restartBridge = async () => {
|
|
27
|
-
console.debug('bridge: ', 'Restarting');
|
|
28
|
-
await bridgeInstance?.restart();
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const init = async ({ isDevelopment }: { isDevelopment: boolean }) => {
|
|
32
|
-
console.info('Electron main process log path: ');
|
|
33
|
-
await launchBridge(isDevelopment);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export default init;
|