Update Electron

This commit is contained in:
Kenta420 2024-03-15 14:10:24 +07:00
parent cae6d582ac
commit c84ee948f5
22 changed files with 763 additions and 152 deletions

View file

@ -1,62 +1,120 @@
import { type BrowserWindow } from 'electron/main'
import { AdbServerNodeTcpConnector } from '@yume-chan/adb-server-node-tcp'
import type { AdbServerDevice, AdbServerTransport } from '@yume-chan/adb'
import { Adb, AdbServerClient } from '@yume-chan/adb'
import { DecodeUtf8Stream, WritableStream } from '@yume-chan/stream-extra'
import type { AdbPacketData, AdbPacketInit } from '@yume-chan/adb'
import { Adb, AdbDaemonTransport } from '@yume-chan/adb'
import type { Consumable, ReadableWritablePair } from '@yume-chan/stream-extra'
import { WritableStream } from '@yume-chan/stream-extra'
import { AdbDaemonDirectSocketsDevice } from './adbaemonDirectSocketsDevice'
import AdbWebCredentialStore from '@yume-chan/adb-credential-web'
let adb: Adb | undefined
export function AdbTcpSocket(win: BrowserWindow | null, ipcMain: Electron.IpcMain) {
if (!win) return
export function AdbDaemon(_win: BrowserWindow | null, ipcMain: Electron.IpcMain) {
ipcMain.handle('adb', async () => {
await createConnection()
const adbConnectionList: { [key: string]: Adb } = {}
ipcMain.handle('adb:tcp:socket:getprop', async (_event, serial: string, key: string) => {
if (!adbConnectionList[serial]) return Promise.reject('adb is not connected')
return adbConnectionList[serial].getProp(key)
})
ipcMain.handle('adb:shell', async (_event, command: string) => {
if (!adb) {
return
ipcMain.handle('adb:tcp:socket:getDevices', () => {
return Object.keys(adbConnectionList).map(serial => {
return {
name: adbConnectionList[serial].banner.product,
serial: serial
}
})
})
ipcMain.handle('adb:tcp:socket:connect', async (_event, { host, port }: { host: string; port: number }) => {
const device: AdbDaemonDirectSocketsDevice = new AdbDaemonDirectSocketsDevice({
host,
port
})
if (Object.keys(adbConnectionList).includes(device.serial)) {
return Promise.resolve({ name: device.name, serial: device.serial })
}
const process = await adb.subprocess.shell(command)
let result: string | null = null
await process.stdout.pipeThrough(new DecodeUtf8Stream()).pipeTo(
new WritableStream({
write(chunk) {
result += chunk
}
try {
const connection: ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>> = await device.connect()
const credentialStore: AdbWebCredentialStore = new AdbWebCredentialStore()
const transport = await AdbDaemonTransport.authenticate({
serial: device.serial,
connection: connection,
credentialStore: credentialStore
})
)
return result
})
}
async function createConnection() {
const connector: AdbServerNodeTcpConnector = new AdbServerNodeTcpConnector({
host: 'localhost',
port: 5037
adbConnectionList[device.serial] = new Adb(transport)
const productName = await adbConnectionList[device.serial].getProp('ro.product.name')
return { name: productName, serial: device.serial }
} catch (e) {
return Promise.reject(e)
}
})
console.log('Connecting to ADB server...')
connector.connect()
ipcMain.handle(
'adb:tcp:socket:shell',
async (_event, { serial, command, callbackId }: { serial: string; command: string; callbackId: string }) => {
if (!adbConnectionList[serial]) return Promise.reject('adb is not connected')
const client: AdbServerClient = new AdbServerClient(connector)
const process = await adbConnectionList[serial].subprocess.shell(command)
const devices: AdbServerDevice[] = await client.getDevices()
if (devices.length === 0) {
console.log('No device found')
return
}
await process.stdout
.pipeTo(
new WritableStream({
write(chunk) {
win.webContents.send(callbackId, chunk)
}
})
)
.then(() => {
process.stdin.close()
process.stderr.cancel()
process.stdout.cancel()
process.kill()
})
}
)
console.log('Devices found:', devices.map(device => device.serial).join(', '))
ipcMain.handle(
'adb:tcp:socket:spawn',
async (_event, { serial, command, callbackId }: { serial: string; command: string; callbackId: string }) => {
if (!adbConnectionList[serial]) return Promise.reject('adb is not connected')
const device: AdbServerDevice | undefined = devices.find(device => device.serial === 'd')
const process = await adbConnectionList[serial].subprocess.spawn(command)
if (!device) {
console.log('No device found')
return
}
let buffer: Uint8Array = new Uint8Array()
console.log('Device found:', device.serial)
const reader = process.stdout.getReader()
const transport: AdbServerTransport = await client.createTransport(device)
adb = new Adb(transport)
// eslint-disable-next-line no-constant-condition
while (true) {
const { value, done } = await reader.read()
if (done) break
const oldBuffer = buffer
buffer = new Uint8Array(value.length + buffer.length)
buffer.set(oldBuffer)
buffer.set(value, oldBuffer.length)
}
reader.releaseLock()
await reader.cancel()
await process.stdin.close()
await process.stderr.cancel()
await process.stdout.cancel()
await process.kill()
win.webContents.send(callbackId, buffer)
}
)
ipcMain.handle('adb:tcp:socket:disconnect', async (_event, serial: string) => {
await adbConnectionList[serial].close()
delete adbConnectionList[serial]
})
}