feat: implement ADB wrapper and device management backend
Adds full ADB client, device manager, static DeviceInfo fetcher, and live DeviceLiveStats poller. Exposes ListDevices, ConnectDevice, DisconnectDevice, GetDeviceInfo, GetDeviceLiveStats as Wails-bound methods with a 1s devices:changed event loop. Bundles ADB binary infrastructure via //go:embed all:bin with runtime fallback chain.
This commit is contained in:
@@ -1 +1,81 @@
|
||||
package adb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func New(adbPath string) *Client {
|
||||
return &Client{path: adbPath}
|
||||
}
|
||||
|
||||
// run executes an adb command and returns stdout.
|
||||
func (c *Client) run(ctx context.Context, args ...string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, c.path, args...)
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
msg := strings.TrimSpace(stderr.String())
|
||||
if msg == "" {
|
||||
msg = err.Error()
|
||||
}
|
||||
return "", fmt.Errorf("adb %s: %s", strings.Join(args, " "), msg)
|
||||
}
|
||||
return strings.TrimSpace(stdout.String()), nil
|
||||
}
|
||||
|
||||
// Devices returns raw output of `adb devices -l`.
|
||||
func (c *Client) Devices(ctx context.Context) (string, error) {
|
||||
return c.run(ctx, "devices", "-l")
|
||||
}
|
||||
|
||||
// Shell runs a shell command on a specific device and returns stdout.
|
||||
func (c *Client) Shell(ctx context.Context, deviceID, cmd string) (string, error) {
|
||||
return c.run(ctx, "-s", deviceID, "shell", cmd)
|
||||
}
|
||||
|
||||
// Connect connects to a device over TCP/IP (wireless ADB).
|
||||
func (c *Client) Connect(ctx context.Context, address string) (string, error) {
|
||||
return c.run(ctx, "connect", address)
|
||||
}
|
||||
|
||||
// Disconnect disconnects a device.
|
||||
func (c *Client) Disconnect(ctx context.Context, deviceID string) (string, error) {
|
||||
return c.run(ctx, "disconnect", deviceID)
|
||||
}
|
||||
|
||||
// Pull copies a file from the device to a local path.
|
||||
func (c *Client) Pull(ctx context.Context, deviceID, remotePath, localPath string) error {
|
||||
_, err := c.run(ctx, "-s", deviceID, "pull", remotePath, localPath)
|
||||
return err
|
||||
}
|
||||
|
||||
// Push copies a local file to the device.
|
||||
func (c *Client) Push(ctx context.Context, deviceID, localPath, remotePath string) error {
|
||||
_, err := c.run(ctx, "-s", deviceID, "push", localPath, remotePath)
|
||||
return err
|
||||
}
|
||||
|
||||
// StartServer starts the ADB server if not already running.
|
||||
func (c *Client) StartServer(ctx context.Context) error {
|
||||
_, err := c.run(ctx, "start-server")
|
||||
return err
|
||||
}
|
||||
|
||||
// Path returns the resolved ADB binary path.
|
||||
func (c *Client) Path() string {
|
||||
return c.path
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user