mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-15 04:19:28 +08:00
300 lines
6.8 KiB
Go
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
|
|
}
|