Files
httprunner/hrp/pkg/gadb/device.go
2022-10-23 22:04:42 +08:00

300 lines
6.8 KiB
Go

package gadb
import (
"errors"
"fmt"
"io"
"os"
"strings"
"time"
)
type DeviceFileInfo struct {
Name string
Mode os.FileMode
Size uint32
LastModified time.Time
}
func (info DeviceFileInfo) IsDir() bool {
return (info.Mode & (1 << 14)) == (1 << 14)
}
const DefaultFileMode = os.FileMode(0664)
type DeviceState string
const (
StateUnknown DeviceState = "UNKNOWN"
StateOnline DeviceState = "online"
StateOffline DeviceState = "offline"
StateDisconnected DeviceState = "disconnected"
)
var deviceStateStrings = map[string]DeviceState{
"": StateDisconnected,
"offline": StateOffline,
"device": StateOnline,
}
func deviceStateConv(k string) (deviceState DeviceState) {
var ok bool
if deviceState, ok = deviceStateStrings[k]; !ok {
return StateUnknown
}
return
}
type DeviceForward struct {
Serial string
Local string
Remote string
// LocalProtocol string
// RemoteProtocol string
}
type Device struct {
adbClient Client
serial string
attrs map[string]string
}
func (d Device) Product() string {
return d.attrs["product"]
}
func (d Device) Model() string {
return d.attrs["model"]
}
func (d Device) Usb() string {
return d.attrs["usb"]
}
func (d Device) transportId() string {
return d.attrs["transport_id"]
}
func (d Device) DeviceInfo() map[string]string {
return d.attrs
}
func (d Device) Serial() string {
// resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-serialno", d.serial))
return d.serial
}
func (d Device) IsUsb() bool {
return d.Usb() != ""
}
func (d Device) State() (DeviceState, error) {
resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-state", d.serial))
return deviceStateConv(resp), err
}
func (d Device) DevicePath() (string, error) {
resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-devpath", d.serial))
return resp, err
}
func (d Device) Forward(localPort, remotePort int, noRebind ...bool) (err error) {
command := ""
local := fmt.Sprintf("tcp:%d", localPort)
remote := fmt.Sprintf("tcp:%d", remotePort)
if len(noRebind) != 0 && noRebind[0] {
command = fmt.Sprintf("host-serial:%s:forward:norebind:%s;%s", d.serial, local, remote)
} else {
command = fmt.Sprintf("host-serial:%s:forward:%s;%s", d.serial, local, remote)
}
_, err = d.adbClient.executeCommand(command, true)
return
}
func (d Device) ForwardList() (deviceForwardList []DeviceForward, err error) {
var forwardList []DeviceForward
if forwardList, err = d.adbClient.ForwardList(); err != nil {
return nil, err
}
deviceForwardList = make([]DeviceForward, 0, len(deviceForwardList))
for i := range forwardList {
if forwardList[i].Serial == d.serial {
deviceForwardList = append(deviceForwardList, forwardList[i])
}
}
// resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:list-forward", d.serial))
return
}
func (d Device) ForwardKill(localPort int) (err error) {
local := fmt.Sprintf("tcp:%d", localPort)
_, err = d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:killforward:%s", d.serial, local), true)
return
}
func (d Device) RunShellCommand(cmd string, args ...string) (string, error) {
raw, err := d.RunShellCommandWithBytes(cmd, args...)
return string(raw), err
}
func (d Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) {
if len(args) > 0 {
cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " "))
}
if strings.TrimSpace(cmd) == "" {
return nil, errors.New("adb shell: command cannot be empty")
}
raw, err := d.executeCommand(fmt.Sprintf("shell:%s", cmd))
return raw, err
}
func (d Device) EnableAdbOverTCP(port ...int) (err error) {
if len(port) == 0 {
port = []int{AdbDaemonPort}
}
_, err = d.executeCommand(fmt.Sprintf("tcpip:%d", port[0]), true)
return
}
func (d Device) createDeviceTransport() (tp transport, err error) {
if tp, err = newTransport(fmt.Sprintf("%s:%d", d.adbClient.host, d.adbClient.port)); err != nil {
return transport{}, err
}
if err = tp.Send(fmt.Sprintf("host:transport:%s", d.serial)); err != nil {
return transport{}, err
}
err = tp.VerifyResponse()
return
}
func (d Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw []byte, err error) {
if len(onlyVerifyResponse) == 0 {
onlyVerifyResponse = []bool{false}
}
var tp transport
if tp, err = d.createDeviceTransport(); err != nil {
return nil, err
}
defer func() { _ = tp.Close() }()
if err = tp.Send(command); err != nil {
return nil, err
}
if err = tp.VerifyResponse(); err != nil {
return nil, err
}
if onlyVerifyResponse[0] {
return
}
raw, err = tp.ReadBytesAll()
return
}
func (d Device) List(remotePath string) (devFileInfos []DeviceFileInfo, err error) {
var tp transport
if tp, err = d.createDeviceTransport(); err != nil {
return nil, err
}
defer func() { _ = tp.Close() }()
var sync syncTransport
if sync, err = tp.CreateSyncTransport(); err != nil {
return nil, err
}
defer func() { _ = sync.Close() }()
if err = sync.Send("LIST", remotePath); err != nil {
return nil, err
}
devFileInfos = make([]DeviceFileInfo, 0)
var entry DeviceFileInfo
for entry, err = sync.ReadDirectoryEntry(); err == nil; entry, err = sync.ReadDirectoryEntry() {
if entry == (DeviceFileInfo{}) {
break
}
devFileInfos = append(devFileInfos, entry)
}
return
}
func (d Device) PushFile(local *os.File, remotePath string, modification ...time.Time) (err error) {
if len(modification) == 0 {
var stat os.FileInfo
if stat, err = local.Stat(); err != nil {
return err
}
modification = []time.Time{stat.ModTime()}
}
return d.Push(local, remotePath, modification[0], DefaultFileMode)
}
func (d Device) Push(source io.Reader, remotePath string, modification time.Time, mode ...os.FileMode) (err error) {
if len(mode) == 0 {
mode = []os.FileMode{DefaultFileMode}
}
var tp transport
if tp, err = d.createDeviceTransport(); err != nil {
return err
}
defer func() { _ = tp.Close() }()
var sync syncTransport
if sync, err = tp.CreateSyncTransport(); err != nil {
return err
}
defer func() { _ = sync.Close() }()
data := fmt.Sprintf("%s,%d", remotePath, mode[0])
if err = sync.Send("SEND", data); err != nil {
return err
}
if err = sync.SendStream(source); err != nil {
return
}
if err = sync.SendStatus("DONE", uint32(modification.Unix())); err != nil {
return
}
if err = sync.VerifyStatus(); err != nil {
return
}
return
}
func (d Device) Pull(remotePath string, dest io.Writer) (err error) {
var tp transport
if tp, err = d.createDeviceTransport(); err != nil {
return err
}
defer func() { _ = tp.Close() }()
var sync syncTransport
if sync, err = tp.CreateSyncTransport(); err != nil {
return err
}
defer func() { _ = sync.Close() }()
if err = sync.Send("RECV", remotePath); err != nil {
return err
}
err = sync.WriteStream(dest)
return
}