Decoupled clients from each other.
This commit is contained in:
parent
31c075d150
commit
0817d29438
16
client_config.go
Normal file
16
client_config.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package goadb
|
||||
|
||||
var (
|
||||
defaultDialer Dialer = NewDialer("", 0)
|
||||
)
|
||||
|
||||
type ClientConfig struct {
|
||||
Dialer Dialer
|
||||
}
|
||||
|
||||
func (c ClientConfig) sanitized() ClientConfig {
|
||||
if c.Dialer == nil {
|
||||
c.Dialer = defaultDialer
|
||||
}
|
||||
return c
|
||||
}
|
|
@ -15,13 +15,10 @@ var port = flag.Int("p", adb.AdbPort, "")
|
|||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
client, err := adb.NewHostClientPort(*port)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
client := adb.NewHostClient(adb.ClientConfig{})
|
||||
|
||||
fmt.Println("Starting server…")
|
||||
client.StartServer()
|
||||
adb.StartServer()
|
||||
|
||||
serverVersion, err := client.GetServerVersion()
|
||||
if err != nil {
|
||||
|
@ -38,23 +35,24 @@ func main() {
|
|||
fmt.Printf("\t%+v\n", *device)
|
||||
}
|
||||
|
||||
PrintDeviceInfoAndError(client.GetAnyDevice())
|
||||
PrintDeviceInfoAndError(client.GetLocalDevice())
|
||||
PrintDeviceInfoAndError(client.GetUsbDevice())
|
||||
PrintDeviceInfoAndError(adb.AnyDevice())
|
||||
PrintDeviceInfoAndError(adb.AnyLocalDevice())
|
||||
PrintDeviceInfoAndError(adb.AnyUsbDevice())
|
||||
|
||||
serials, err := client.ListDeviceSerials()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, serial := range serials {
|
||||
PrintDeviceInfoAndError(client.GetDeviceWithSerial(serial))
|
||||
PrintDeviceInfoAndError(adb.DeviceWithSerial(serial))
|
||||
}
|
||||
|
||||
//fmt.Println("Killing server…")
|
||||
//client.KillServer()
|
||||
}
|
||||
|
||||
func PrintDeviceInfoAndError(device *adb.DeviceClient) {
|
||||
func PrintDeviceInfoAndError(descriptor adb.DeviceDescriptor) {
|
||||
device := adb.NewDeviceClient(adb.ClientConfig{}, descriptor)
|
||||
if err := PrintDeviceInfo(device); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ func readLine() string {
|
|||
}
|
||||
|
||||
func doCommand(cmd string) error {
|
||||
conn, err := wire.NewDialer("", *port).Dial()
|
||||
conn, err := goadb.NewDialer("", *port).Dial()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -10,8 +10,15 @@ import (
|
|||
|
||||
// DeviceClient communicates with a specific Android device.
|
||||
type DeviceClient struct {
|
||||
dialer wire.Dialer
|
||||
descriptor *DeviceDescriptor
|
||||
config ClientConfig
|
||||
descriptor DeviceDescriptor
|
||||
}
|
||||
|
||||
func NewDeviceClient(config ClientConfig, descriptor DeviceDescriptor) *DeviceClient {
|
||||
return &DeviceClient{
|
||||
config: config.sanitized(),
|
||||
descriptor: descriptor,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DeviceClient) String() string {
|
||||
|
@ -134,7 +141,7 @@ func (c *DeviceClient) OpenRead(path string) (io.ReadCloser, error) {
|
|||
// getAttribute returns the first message returned by the server by running
|
||||
// <host-prefix>:<attr>, where host-prefix is determined from the DeviceDescriptor.
|
||||
func (c *DeviceClient) getAttribute(attr string) (string, error) {
|
||||
resp, err := wire.RoundTripSingleResponse(c.dialer,
|
||||
resp, err := roundTripSingleResponse(c.config.Dialer,
|
||||
fmt.Sprintf("%s:%s", c.descriptor.getHostPrefix(), attr))
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -145,9 +152,9 @@ func (c *DeviceClient) getAttribute(attr string) (string, error) {
|
|||
// dialDevice switches the connection to communicate directly with the device
|
||||
// by requesting the transport defined by the DeviceDescriptor.
|
||||
func (c *DeviceClient) dialDevice() (*wire.Conn, error) {
|
||||
conn, err := c.dialer.Dial()
|
||||
conn, err := c.config.Dialer.Dial()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error dialing adb server (%s): %+v", c.dialer, err)
|
||||
return nil, fmt.Errorf("error dialing adb server (%s): %+v", c.config.Dialer, err)
|
||||
}
|
||||
|
||||
req := fmt.Sprintf("host:%s", c.descriptor.getTransportDescriptor())
|
||||
|
@ -197,7 +204,7 @@ func prepareCommandLine(cmd string, args ...string) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Prepend the comand to the args array.
|
||||
// Prepend the command to the args array.
|
||||
if len(args) > 0 {
|
||||
cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " "))
|
||||
}
|
||||
|
|
|
@ -12,7 +12,12 @@ func TestGetAttribute(t *testing.T) {
|
|||
Status: wire.StatusSuccess,
|
||||
Messages: []string{"value"},
|
||||
}
|
||||
client := &DeviceClient{s, deviceWithSerial("serial")}
|
||||
client := NewDeviceClient(
|
||||
ClientConfig{
|
||||
Dialer: s,
|
||||
},
|
||||
DeviceWithSerial("serial"),
|
||||
)
|
||||
|
||||
v, err := client.getAttribute("attr")
|
||||
assert.Equal(t, "host-serial:serial:attr", s.Requests[0])
|
||||
|
@ -25,7 +30,12 @@ func TestRunCommandNoArgs(t *testing.T) {
|
|||
Status: wire.StatusSuccess,
|
||||
Messages: []string{"output"},
|
||||
}
|
||||
client := &DeviceClient{s, anyDevice()}
|
||||
client := NewDeviceClient(
|
||||
ClientConfig{
|
||||
Dialer: s,
|
||||
},
|
||||
AnyDevice(),
|
||||
)
|
||||
|
||||
v, err := client.RunCommand("cmd")
|
||||
assert.Equal(t, "host:transport-any", s.Requests[0])
|
||||
|
|
|
@ -23,33 +23,33 @@ type DeviceDescriptor struct {
|
|||
serial string
|
||||
}
|
||||
|
||||
func anyDevice() *DeviceDescriptor {
|
||||
return &DeviceDescriptor{descriptorType: DeviceAny}
|
||||
func AnyDevice() DeviceDescriptor {
|
||||
return DeviceDescriptor{descriptorType: DeviceAny}
|
||||
}
|
||||
|
||||
func anyUsbDevice() *DeviceDescriptor {
|
||||
return &DeviceDescriptor{descriptorType: DeviceUsb}
|
||||
func AnyUsbDevice() DeviceDescriptor {
|
||||
return DeviceDescriptor{descriptorType: DeviceUsb}
|
||||
}
|
||||
|
||||
func anyLocalDevice() *DeviceDescriptor {
|
||||
return &DeviceDescriptor{descriptorType: DeviceLocal}
|
||||
func AnyLocalDevice() DeviceDescriptor {
|
||||
return DeviceDescriptor{descriptorType: DeviceLocal}
|
||||
}
|
||||
|
||||
func deviceWithSerial(serial string) *DeviceDescriptor {
|
||||
return &DeviceDescriptor{
|
||||
func DeviceWithSerial(serial string) DeviceDescriptor {
|
||||
return DeviceDescriptor{
|
||||
descriptorType: DeviceSerial,
|
||||
serial: serial,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DeviceDescriptor) String() string {
|
||||
func (d DeviceDescriptor) String() string {
|
||||
if d.descriptorType == DeviceSerial {
|
||||
return fmt.Sprintf("%s[%s]", d.descriptorType, d.serial)
|
||||
}
|
||||
return d.descriptorType.String()
|
||||
}
|
||||
|
||||
func (d *DeviceDescriptor) getHostPrefix() string {
|
||||
func (d DeviceDescriptor) getHostPrefix() string {
|
||||
switch d.descriptorType {
|
||||
case DeviceAny:
|
||||
return "host"
|
||||
|
@ -64,7 +64,7 @@ func (d *DeviceDescriptor) getHostPrefix() string {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *DeviceDescriptor) getTransportDescriptor() string {
|
||||
func (d DeviceDescriptor) getTransportDescriptor() string {
|
||||
switch d.descriptorType {
|
||||
case DeviceAny:
|
||||
return "transport-any"
|
||||
|
|
|
@ -1,17 +1,38 @@
|
|||
package wire
|
||||
package goadb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"runtime"
|
||||
|
||||
"github.com/zach-klippenstein/goadb/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default port the adb server listens on.
|
||||
AdbPort = 5037
|
||||
)
|
||||
|
||||
/*
|
||||
Dialer knows how to create connections to an adb server.
|
||||
*/
|
||||
type Dialer interface {
|
||||
Dial() (*Conn, error)
|
||||
Dial() (*wire.Conn, error)
|
||||
}
|
||||
|
||||
/*
|
||||
NewDialer creates a new Dialer.
|
||||
|
||||
If host is "" or port is 0, "localhost:5037" is used.
|
||||
*/
|
||||
func NewDialer(host string, port int) Dialer {
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
if port == 0 {
|
||||
port = AdbPort
|
||||
}
|
||||
return &netDialer{host, port}
|
||||
}
|
||||
|
||||
type netDialer struct {
|
||||
|
@ -19,35 +40,24 @@ type netDialer struct {
|
|||
Port int
|
||||
}
|
||||
|
||||
func NewDialer(host string, port int) Dialer {
|
||||
return &netDialer{host, port}
|
||||
}
|
||||
|
||||
func (d *netDialer) String() string {
|
||||
return fmt.Sprintf("netDialer(%s:%d)", d.Host, d.Port)
|
||||
}
|
||||
|
||||
// Dial connects to the adb server on the host and port set on the netDialer.
|
||||
// The zero-value will connect to the default, localhost:5037.
|
||||
func (d *netDialer) Dial() (*Conn, error) {
|
||||
func (d *netDialer) Dial() (*wire.Conn, error) {
|
||||
host := d.Host
|
||||
if host == "" {
|
||||
return nil, errors.New("Must specify adb hostname (cannot be empty).")
|
||||
}
|
||||
|
||||
port := d.Port
|
||||
if port == 0 {
|
||||
return nil, errors.New("Must specify port (cannot be 0).")
|
||||
}
|
||||
|
||||
netConn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn := &Conn{
|
||||
Scanner: NewScanner(netConn),
|
||||
Sender: NewSender(netConn),
|
||||
conn := &wire.Conn{
|
||||
Scanner: wire.NewScanner(netConn),
|
||||
Sender: wire.NewSender(netConn),
|
||||
}
|
||||
|
||||
// Prevent leaking the network connection, not sure if TCPConn does this itself.
|
||||
|
@ -58,7 +68,8 @@ func (d *netDialer) Dial() (*Conn, error) {
|
|||
return conn, nil
|
||||
}
|
||||
|
||||
func RoundTripSingleResponse(d Dialer, req string) ([]byte, error) {
|
||||
// TODO(zach): Make this unexported.
|
||||
func roundTripSingleResponse(d Dialer, req string) ([]byte, error) {
|
||||
conn, err := d.Dial()
|
||||
if err != nil {
|
||||
return nil, err
|
|
@ -2,18 +2,11 @@
|
|||
package goadb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/zach-klippenstein/goadb/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default port the adb server listens on.
|
||||
AdbPort = 5037
|
||||
)
|
||||
|
||||
/*
|
||||
HostClient communicates with host services on the adb server.
|
||||
|
||||
|
@ -27,27 +20,31 @@ See list of services at https://android.googlesource.com/platform/system/core/+/
|
|||
*/
|
||||
// TODO(z): Finish implementing host services.
|
||||
type HostClient struct {
|
||||
dialer wire.Dialer
|
||||
config ClientConfig
|
||||
}
|
||||
|
||||
func NewHostClient() (*HostClient, error) {
|
||||
return NewHostClientPort(AdbPort)
|
||||
}
|
||||
// func NewHostClient() (*HostClient, error) {
|
||||
// return NewHostClientPort(AdbPort)
|
||||
// }
|
||||
|
||||
func NewHostClientPort(port int) (*HostClient, error) {
|
||||
return NewHostClientDialer(wire.NewDialer("localhost", port))
|
||||
}
|
||||
// func NewHostClientPort(port int) (*HostClient, error) {
|
||||
// return NewHostClientDialer(wire.NewDialer("localhost", port))
|
||||
// }
|
||||
|
||||
func NewHostClientDialer(d wire.Dialer) (*HostClient, error) {
|
||||
if d == nil {
|
||||
return nil, errors.New("dialer cannot be nil.")
|
||||
}
|
||||
return &HostClient{d}, nil
|
||||
// func NewHostClientDialer(d wire.Dialer) (*HostClient, error) {
|
||||
// if d == nil {
|
||||
// return nil, errors.New("dialer cannot be nil.")
|
||||
// }
|
||||
// return &HostClient{d}, nil
|
||||
// }
|
||||
|
||||
func NewHostClient(config ClientConfig) *HostClient {
|
||||
return &HostClient{config.sanitized()}
|
||||
}
|
||||
|
||||
// GetServerVersion asks the ADB server for its internal version number.
|
||||
func (c *HostClient) GetServerVersion() (int, error) {
|
||||
resp, err := wire.RoundTripSingleResponse(c.dialer, "host:version")
|
||||
resp, err := roundTripSingleResponse(c.config.Dialer, "host:version")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -63,7 +60,7 @@ Corresponds to the command:
|
|||
adb kill-server
|
||||
*/
|
||||
func (c *HostClient) KillServer() error {
|
||||
conn, err := c.dialer.Dial()
|
||||
conn, err := c.config.Dialer.Dial()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,17 +73,6 @@ func (c *HostClient) KillServer() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
StartServer ensures there is a server running.
|
||||
|
||||
Currently implemented by just running
|
||||
adb start-server
|
||||
*/
|
||||
func (c *HostClient) StartServer() error {
|
||||
cmd := exec.Command("adb", "start-server")
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
/*
|
||||
ListDeviceSerials returns the serial numbers of all attached devices.
|
||||
|
||||
|
@ -94,7 +80,7 @@ Corresponds to the command:
|
|||
adb devices
|
||||
*/
|
||||
func (c *HostClient) ListDeviceSerials() ([]string, error) {
|
||||
resp, err := wire.RoundTripSingleResponse(c.dialer, "host:devices")
|
||||
resp, err := roundTripSingleResponse(c.config.Dialer, "host:devices")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -118,41 +104,10 @@ Corresponds to the command:
|
|||
adb devices -l
|
||||
*/
|
||||
func (c *HostClient) ListDevices() ([]*DeviceInfo, error) {
|
||||
resp, err := wire.RoundTripSingleResponse(c.dialer, "host:devices-l")
|
||||
resp, err := roundTripSingleResponse(c.config.Dialer, "host:devices-l")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseDeviceList(string(resp), parseDeviceLong)
|
||||
}
|
||||
|
||||
func (c *HostClient) GetDevice(d *DeviceInfo) *DeviceClient {
|
||||
return c.GetDeviceWithSerial(d.Serial)
|
||||
}
|
||||
|
||||
// GetDeviceWithSerial returns a client for the device with the specified serial number.
|
||||
// Will return a client even if there is no matching device connected.
|
||||
func (c *HostClient) GetDeviceWithSerial(serial string) *DeviceClient {
|
||||
return c.getDevice(deviceWithSerial(serial))
|
||||
}
|
||||
|
||||
// GetAnyDevice returns a client for any one connected device.
|
||||
func (c *HostClient) GetAnyDevice() *DeviceClient {
|
||||
return c.getDevice(anyDevice())
|
||||
}
|
||||
|
||||
// GetUsbDevice returns a client for the USB device.
|
||||
// Will return a client even if there is no device connected.
|
||||
func (c *HostClient) GetUsbDevice() *DeviceClient {
|
||||
return c.getDevice(anyUsbDevice())
|
||||
}
|
||||
|
||||
// GetLocalDevice returns a client for the local device.
|
||||
// Will return a client even if there is no device connected.
|
||||
func (c *HostClient) GetLocalDevice() *DeviceClient {
|
||||
return c.getDevice(anyLocalDevice())
|
||||
}
|
||||
|
||||
func (c *HostClient) getDevice(descriptor *DeviceDescriptor) *DeviceClient {
|
||||
return &DeviceClient{c.dialer, descriptor}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,9 @@ func TestGetServerVersion(t *testing.T) {
|
|||
Status: wire.StatusSuccess,
|
||||
Messages: []string{"000a"},
|
||||
}
|
||||
client, err := NewHostClientDialer(s)
|
||||
assert.NoError(t, err)
|
||||
client := NewHostClient(ClientConfig{
|
||||
Dialer: s,
|
||||
})
|
||||
|
||||
v, err := client.GetServerVersion()
|
||||
assert.Equal(t, "host:version", s.Requests[0])
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package goadb
|
||||
|
||||
import "github.com/zach-klippenstein/goadb/wire"
|
||||
|
||||
type nilSafeDialer struct {
|
||||
wire.Dialer
|
||||
}
|
||||
|
||||
func (d nilSafeDialer) Dial() (*wire.Conn, error) {
|
||||
if d.Dialer == nil {
|
||||
d.Dialer = wire.NewDialer("", AdbPort)
|
||||
}
|
||||
|
||||
return d.Dialer.Dial()
|
||||
}
|
14
server_controller.go
Normal file
14
server_controller.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package goadb
|
||||
|
||||
import "os/exec"
|
||||
|
||||
/*
|
||||
StartServer ensures there is a server running.
|
||||
|
||||
Currently implemented by just running
|
||||
adb start-server
|
||||
*/
|
||||
func StartServer() error {
|
||||
cmd := exec.Command("adb", "start-server")
|
||||
return cmd.Run()
|
||||
}
|
|
@ -4,14 +4,14 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
type AdbError struct {
|
||||
type AdbServerError struct {
|
||||
Request string
|
||||
ServerMsg string
|
||||
}
|
||||
|
||||
var _ error = &AdbError{}
|
||||
var _ error = &AdbServerError{}
|
||||
|
||||
func (e *AdbError) Error() string {
|
||||
func (e *AdbServerError) Error() string {
|
||||
if e.Request == "" {
|
||||
return fmt.Sprintf("server error: %s", e.ServerMsg)
|
||||
} else {
|
|
@ -20,7 +20,7 @@ func ReadStatusFailureAsError(s Scanner, req string) error {
|
|||
return fmt.Errorf("server returned error for %s, but couldn't read the error message: %+v", err)
|
||||
}
|
||||
|
||||
return &AdbError{
|
||||
return &AdbServerError{
|
||||
Request: req,
|
||||
ServerMsg: string(msg),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue