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:
achmad
2026-05-06 14:51:34 +07:00
parent 6a53f87e03
commit 14935db63e
14 changed files with 610 additions and 14 deletions
+80
View File
@@ -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
}