Taobin-Recipe-Manager/client-electron/src/pages/android/components/shell-tab.tsx

135 lines
3.7 KiB
TypeScript
Raw Normal View History

2024-02-05 16:24:11 +07:00
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
2024-02-07 18:25:11 +07:00
import { encodeUtf8, type AdbSubprocessProtocol, type Adb } from '@yume-chan/adb'
2024-02-05 16:24:11 +07:00
import { Consumable, WritableStream } from '@yume-chan/stream-extra'
2024-02-07 18:25:11 +07:00
import { memo, useCallback, useEffect, useRef, useState } from 'react'
2024-02-05 16:24:11 +07:00
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
2024-02-07 18:25:11 +07:00
interface ShellTabProps {
adb: Adb | undefined
}
2024-02-05 16:24:11 +07:00
2024-02-07 18:25:11 +07:00
export const ShellTab: React.FC<ShellTabProps> = memo(({ adb }) => {
2024-02-05 16:24:11 +07:00
const [process, setProcess] = useState<AdbSubprocessProtocol | undefined>()
2024-02-07 18:25:11 +07:00
const [terminal, setTerminal] = useState<Terminal | undefined>()
const [reader, setReader] = useState<WritableStream<Uint8Array> | undefined>()
2024-02-05 16:24:11 +07:00
useEffect(() => {
2024-02-07 18:25:11 +07:00
if (adb) {
console.log('adb is connected')
console.log('creating terminal')
const terminal: Terminal = new Terminal()
terminal.options.cursorBlink = true
terminal.options.theme = {
background: '#1e1e1e',
foreground: '#d4d4d4'
}
console.log('creating process')
const _reader = new WritableStream<Uint8Array>({
write(chunk) {
terminal.write(chunk)
2024-02-05 16:24:11 +07:00
}
2024-02-07 18:25:11 +07:00
})
adb.subprocess.shell('/data/data/com.termux/files/usr/bin/telnet localhost 45515').then(_process => {
_process.stdout.pipeTo(_reader)
const writer = _process.stdin.getWriter()
2024-02-05 16:24:11 +07:00
terminal.onData(data => {
const buffer = encodeUtf8(data)
const consumable = new Consumable(buffer)
writer.write(consumable)
})
2024-02-07 18:25:11 +07:00
setReader(_reader)
setProcess(_process)
setTerminal(terminal)
})
} else {
console.log('adb is not connected')
if (process) {
process?.stdout.cancel()
process?.stderr.cancel()
process?.stdin.close()
process?.kill()
2024-02-05 16:24:11 +07:00
}
2024-02-07 18:25:11 +07:00
setProcess(undefined)
setTerminal(undefined)
2024-02-05 16:24:11 +07:00
}
2024-02-07 18:25:11 +07:00
}, [adb])
const killProcess = useCallback(() => {
console.log('killing shell')
console.log(process)
if (process && terminal) {
terminal.write('exit\n')
reader?.close()
process.stderr.cancel()
process.stdin.close()
process.stdout.cancel()
process.kill()
2024-02-05 16:24:11 +07:00
}
2024-02-07 18:25:11 +07:00
}, [process])
2024-02-05 16:24:11 +07:00
return (
<Card>
<CardHeader>
<CardTitle>Shell</CardTitle>
<CardDescription>Access your device's shell using a terminal emulator</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-center justify-end py-3 w-full">
<div>
2024-02-07 18:25:11 +07:00
<Button variant={'destructive'} onClick={killProcess}>
2024-02-05 16:24:11 +07:00
Kill Shell
</Button>
</div>
</div>
2024-02-07 18:25:11 +07:00
{terminal ? (
<ShellTerminal terminal={terminal} />
) : (
<div className="w-full h-[800px] bg-slate-700 flex justify-center items-center">
<h1>No Connection ADB</h1>
</div>
)}
2024-02-05 16:24:11 +07:00
</CardContent>
</Card>
)
2024-02-07 18:25:11 +07:00
})
interface ShellTerminalProps {
terminal: Terminal
}
const ShellTerminal: React.FC<ShellTerminalProps> = ({ terminal }) => {
const shellRef = useRef<HTMLDivElement>(null)
useEffect(() => {
console.log(shellRef.current)
// check if shellRef is have child remove all
if (shellRef.current && shellRef.current.children.length > 0) {
for (const child of shellRef.current.children) {
shellRef.current.removeChild(child)
}
}
if (terminal && shellRef.current) {
const addon = new FitAddon()
terminal.loadAddon(addon)
terminal.open(shellRef.current)
addon.fit()
}
}, [terminal])
return <div className="w-full h-[800px] bg-slate-700" ref={shellRef}></div>
2024-02-05 16:24:11 +07:00
}