Add download file
This commit is contained in:
parent
ac0f5bbeea
commit
92fbf7eed6
5 changed files with 279 additions and 88 deletions
|
|
@ -1,75 +1,84 @@
|
|||
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 { encodeUtf8, type AdbSubprocessProtocol, type Adb } from '@yume-chan/adb'
|
||||
import { Consumable, WritableStream } from '@yume-chan/stream-extra'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { memo, useCallback, 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)
|
||||
interface ShellTabProps {
|
||||
adb: Adb | undefined
|
||||
}
|
||||
|
||||
export const ShellTab: React.FC<ShellTabProps> = memo(({ adb }) => {
|
||||
const [process, setProcess] = useState<AdbSubprocessProtocol | undefined>()
|
||||
const [terminal, setTerminal] = useState<Terminal | undefined>()
|
||||
|
||||
const [reader, setReader] = useState<WritableStream<Uint8Array> | 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
})
|
||||
)
|
||||
adb.subprocess.shell('/data/data/com.termux/files/usr/bin/telnet localhost 45515').then(_process => {
|
||||
_process.stdout.pipeTo(_reader)
|
||||
|
||||
const writer = process.stdin.getWriter()
|
||||
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)
|
||||
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()
|
||||
}
|
||||
}
|
||||
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()
|
||||
setProcess(undefined)
|
||||
setTerminal(undefined)
|
||||
}
|
||||
}, [shellRef, adb])
|
||||
}, [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()
|
||||
}
|
||||
}, [process])
|
||||
|
||||
return (
|
||||
<Card>
|
||||
|
|
@ -80,21 +89,46 @@ export const ShellTab: React.FC = () => {
|
|||
<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()
|
||||
}}
|
||||
>
|
||||
<Button variant={'destructive'} onClick={killProcess}>
|
||||
Kill Shell
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-[800px] bg-slate-700" ref={shellRef}></div>
|
||||
{terminal ? (
|
||||
<ShellTerminal terminal={terminal} />
|
||||
) : (
|
||||
<div className="w-full h-[800px] bg-slate-700 flex justify-center items-center">
|
||||
<h1>No Connection ADB</h1>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
})
|
||||
|
||||
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>
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue