add shell

This commit is contained in:
Kenta420 2024-02-05 16:24:11 +07:00
parent aaa60216b2
commit be417729ea
10 changed files with 768 additions and 380 deletions

View file

@ -0,0 +1,100 @@
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import useAdb from '@/hooks/useAdb'
import { encodeUtf8, type AdbSubprocessProtocol } from '@yume-chan/adb'
import { Consumable, WritableStream } from '@yume-chan/stream-extra'
import { useEffect, useRef, useState } from 'react'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
export const ShellTab: React.FC = () => {
const adb = useAdb(state => state.adb)
const shellRef = useRef<HTMLDivElement>(null)
const [process, setProcess] = useState<AdbSubprocessProtocol | undefined>()
useEffect(() => {
const startTerminal = async () => {
if (shellRef.current && adb) {
if (shellRef.current.children.length > 0) {
// remove all children from the shellRef
while (shellRef.current.firstChild) {
shellRef.current.removeChild(shellRef.current.firstChild)
}
}
const terminal: Terminal = new Terminal()
const fitAddon = new FitAddon()
terminal.loadAddon(fitAddon)
const process: AdbSubprocessProtocol = await adb.subprocess.shell(
'/data/data/com.termux/files/usr/bin/telnet localhost 45515'
)
process.stdout.pipeTo(
new WritableStream<Uint8Array>({
write(chunk) {
terminal.write(chunk)
}
})
)
const writer = process.stdin.getWriter()
terminal.onData(data => {
const buffer = encodeUtf8(data)
const consumable = new Consumable(buffer)
writer.write(consumable)
})
terminal.options.cursorBlink = true
terminal.options.theme = {
background: '#1e1e1e',
foreground: '#d4d4d4'
}
terminal.open(shellRef.current)
fitAddon.fit()
setProcess(process)
}
}
startTerminal()
return () => {
console.log('cleaning up shell')
shellRef.current && shellRef.current.firstChild && shellRef.current.removeChild(shellRef.current.firstChild)
process?.stderr.cancel()
process?.stdin.close()
process?.stdout.cancel()
process?.kill()
}
}, [shellRef, adb])
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>
<Button
variant={'destructive'}
onClick={() => {
process?.stderr.cancel()
process?.stdin.close()
process?.stdout.cancel()
process?.kill()
}}
>
Kill Shell
</Button>
</div>
</div>
<div className="w-full h-[800px] bg-slate-700" ref={shellRef}></div>
</CardContent>
</Card>
)
}