From 3e03dc7a868c16bf3b2e6e69cc5fe4ad74edbe42 Mon Sep 17 00:00:00 2001 From: shengxiang Date: Thu, 19 Oct 2017 11:05:12 +0800 Subject: [PATCH] support upload file --- main.go | 34 ++++++++++++++++++++++++++++++++-- tunnelproxy.go | 7 ++++--- uiautomator.go | 34 ++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index fc55083..a2f8866 100644 --- a/main.go +++ b/main.go @@ -406,7 +406,20 @@ func ServeHTTP(port int) error { go httpServer.Shutdown(nil) }) + m.HandleFunc("/uiautomator", func(w http.ResponseWriter, r *http.Request) { + err := safeRunUiautomator() + if err == nil { + io.WriteString(w, "Success") + } else { + io.WriteString(w, err.Error()) + } + }).Methods("POST") + m.HandleFunc("/screenshot", func(w http.ResponseWriter, r *http.Request) { + if strings.ToLower(getProperty("ro.product.manufacturer")) == "meizu" { + http.Redirect(w, r, "/screenshot/0", 302) + return + } imagePath := "/data/local/tmp/minicap-screenshot.jpg" if err := Screenshot(imagePath); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -420,6 +433,12 @@ func ServeHTTP(port int) error { if runtime.GOOS != "windows" { filepath = "/" + filepath } + var fileMode os.FileMode + if _, err := fmt.Sscanf(r.FormValue("mode"), "%o", &fileMode); err != nil { + log.Printf("invalid file mode: %s", r.FormValue("mode")) + fileMode = 0644 + } // %o base 8 + file, header, err := r.FormFile("file") if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -443,7 +462,18 @@ func ServeHTTP(port int) error { http.Error(w, err.Error(), http.StatusInternalServerError) return } - fmt.Fprintf(w, "copied %d bytes into %s", written, filepath) + if fileMode != 0 { + os.Chmod(filepath, fileMode) + } + if fileInfo, err := os.Stat(filepath); err == nil { + fileMode = fileInfo.Mode() + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + json.NewEncoder(w).Encode(map[string]interface{}{ + "target": filepath, + "size": written, + "mode": fmt.Sprintf("0%o", fileMode), + }) }) m.HandleFunc("/install", func(w http.ResponseWriter, r *http.Request) { @@ -531,7 +561,7 @@ func ServeHTTP(port int) error { http.Handle("/jsonrpc/0", uiautomatorProxy) http.Handle("/ping", uiautomatorProxy) http.HandleFunc("/screenshot/0", func(w http.ResponseWriter, r *http.Request) { - if r.FormValue("minicap") == "false" { + if r.FormValue("minicap") == "false" || strings.ToLower(getProperty("ro.product.manufacturer")) == "meizu" { uiautomatorProxy.ServeHTTP(w, r) return } diff --git a/tunnelproxy.go b/tunnelproxy.go index 4501e00..4dd5b3b 100644 --- a/tunnelproxy.go +++ b/tunnelproxy.go @@ -36,9 +36,10 @@ func unsafeRunTunnelProxy(serverAddr string) error { props, _ := androidutils.Properties() devInfo := &proto.DeviceInfo{ - Serial: props["ro.serialno"], - Brand: props["ro.product.brand"], - Model: props["ro.product.model"], + Serial: props["ro.serialno"], + Brand: props["ro.product.brand"], + Model: props["ro.product.model"], + AgentVersion: version, } devInfo.HWAddr, _ = androidutils.HWAddrWLAN() c.WriteJSON(proto.CommonMessage{ diff --git a/uiautomator.go b/uiautomator.go index 03d2acd..4483a9e 100644 --- a/uiautomator.go +++ b/uiautomator.go @@ -1,6 +1,7 @@ package main import ( + "errors" "log" "os" "os/exec" @@ -8,15 +9,33 @@ import ( "time" ) -func safeRunUiautomator() { +type uiautomatorLauncher struct { + running bool +} + +func (u *uiautomatorLauncher) Start() error { + if u.running { + return errors.New("uiautomator already started") + } if runtime.GOOS == "windows" { - return + u.running = true + return nil } + go u.safeRun() + return nil +} + +func (u *uiautomatorLauncher) IsRunning() bool { + return u.running +} + +func (u *uiautomatorLauncher) safeRun() { + u.running = true retry := 5 for retry > 0 { retry-- start := time.Now() - if err := runUiautomator(); err != nil { + if err := u.runUiautomator(); err != nil { log.Printf("uiautomator quit: %v", err) } if time.Since(start) > 1*time.Minute { @@ -25,9 +44,10 @@ func safeRunUiautomator() { time.Sleep(2 * time.Second) } log.Println("uiautomator can not started") + u.running = false } -func runUiautomator() error { +func (u *uiautomatorLauncher) runUiautomator() error { c := exec.Command("am", "instrument", "-w", "-r", "-e", "debug", "false", "-e", "class", "com.github.uiautomator.stub.Stub", @@ -36,3 +56,9 @@ func runUiautomator() error { c.Stderr = os.Stderr return c.Run() } + +var uiautomator uiautomatorLauncher + +func safeRunUiautomator() error { + return uiautomator.Start() +}