Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #8 from ggmolly/feat/debug-mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Molly authored Jun 13, 2024
2 parents 66352a7 + 660487f commit 955536f
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 21 deletions.
13 changes: 6 additions & 7 deletions connection/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package connection
import (
"bytes"
"fmt"
"log"
"net"
"os"
"reflect"
Expand Down Expand Up @@ -65,21 +64,21 @@ func (server *Server) RemoveClient(client *Client) {
delete(server.Clients, client.FD)
}

func (server *Server) Run() {
func (server *Server) Run() error {
var err error
BelfastInstance = server
if server.SocketFD, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM|syscall.O_NONBLOCK, 0); err != nil {
log.Fatalf("failed to create socket : %v", err)
return fmt.Errorf("failed to create socket : %v", err)
}
defer syscall.Close(server.SocketFD)
logger.LogEvent("Server", "Listen", fmt.Sprintf("Listening on %s:%d", server.BindAddress, server.Port), logger.LOG_LEVEL_AUTO)

if err = syscall.SetsockoptInt(server.SocketFD, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
log.Fatalf("setsockopt error: %v", err)
return fmt.Errorf("setsockopt error: %v", err)
}

if err = syscall.SetNonblock(server.SocketFD, true); err != nil {
log.Fatalf("setnonblock error: %v", err)
return fmt.Errorf("setnonblock error: %v", err)
}

var ip [4]byte
Expand All @@ -90,11 +89,11 @@ func (server *Server) Run() {
}

if err = syscall.Bind(server.SocketFD, &addr); err != nil {
log.Fatalf("bind error: %v", err)
return fmt.Errorf("bind error: %v", err)
}

if err = syscall.Listen(server.SocketFD, syscall.SOMAXCONN); err != nil {
log.Fatalf("listen error: %v", err)
return fmt.Errorf("listen error: %v", err)
}

if server.EpollFD, err = syscall.EpollCreate1(0); err != nil {
Expand Down
243 changes: 243 additions & 0 deletions debug/adb_watcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package debug

import (
"bufio"
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"time"

"github.com/ggmolly/belfast/logger"
"github.com/mattn/go-tty"
)

var handlers = map[string]func(){
"?": help,
"c": clear,
"l": listDevices,
"s": toggleLogcat,
"f": flushLogcat,
"d": dumpLogcat,
"+": increaseSleep,
"-": decreaseSleep,
"=": printDelay,
}

// a list of needles to search for in the process list
// to find Azur Lane's PID -- these should be lowercase
// to make the search case-insensitive
const grepRegex = "'(azurlane|blhx|manjuu|yostar)'"

// Filter to remove Azur Lane's uninteresting logs (FacebookSDK, ...) -- regex for -e parameter
// see https://developer.android.com/studio/command-line/logcat#filteringOutput
const defaultLogcatFilter = "(System|Unity)"

var logcatProcess *exec.Cmd
var azurLanePID int
var psDelay time.Duration = 3 * time.Second

func help() {
fmt.Println("belfast -- adb watcher help")
fmt.Println("?: print this help")
fmt.Println("l: list connected devices")
fmt.Println("c: clear terminal")
fmt.Println("s: start/stop logcat parsing")
fmt.Println("f: flush logcat")
fmt.Println("d: dump logcat buffer to a file")
fmt.Println("+: increase delay between ps commands (default: 3s)")
fmt.Println("-: decrease delay between ps commands (default: 3s)")
fmt.Println("=: print current delay between ps commands")
fmt.Println("x: exit adb watcher")
}

// stupid way to clear the terminal, calls 'clear' on non-windows and 'cls' on windows
func clear() {
if runtime.GOOS == "windows" {
cmd := exec.Command("cmd", "/c", "cls")
cmd.Stdout = os.Stdout
cmd.Run()
} else {
cmd := exec.Command("clear")
cmd.Stdout = os.Stdout
cmd.Run()
}
}

// runs 'adb devices' and prints the output
func listDevices() {
cmd := exec.Command("adb", "devices")
out, err := cmd.Output()
if err != nil {
logger.LogEvent("ADB", "ListDevices", "Failed to list devices", logger.LOG_LEVEL_ERROR)
return
}
fmt.Print(string(out))
}

// runs 'adb logcat -c' to flush logcat's buffer
func flushLogcat() {
cmd := exec.Command("adb", "logcat", "-c")
if err := cmd.Run(); err != nil {
logger.LogEvent("ADB", "Flush", "Failed to flush logcat", logger.LOG_LEVEL_ERROR)
return
}
logger.LogEvent("ADB", "FlushLogcat", "Logcat flushed", logger.LOG_LEVEL_INFO)
}

// wrapper function to print logcat lines
func echoLog(line *string) {
fmt.Println(*line)
}

func stopLogcat() {
if logcatProcess == nil {
return
}
pid := logcatProcess.Process.Pid
logcatProcess.Process.Kill()
logcatProcess = nil
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Logcat stopped (PID: %d)", pid), logger.LOG_LEVEL_INFO)
}

// starts/stops logcat parsing
func toggleLogcat() {
if logcatProcess != nil {
stopLogcat()
return
}
go func() {
args := []string{"logcat"}
if azurLanePID != 0 {
args = append(args, "--pid", fmt.Sprintf("%d", azurLanePID), "-e", defaultLogcatFilter)
} else {
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Azur Lane PID not found, waiting %v to retry", psDelay), logger.LOG_LEVEL_INFO)
return
}
logcatProcess = exec.Command("adb", args...)
processStdout, err := logcatProcess.StdoutPipe()
if err != nil {
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Failed to get logcat stdout: %v", err), logger.LOG_LEVEL_ERROR)
return
}

if err := logcatProcess.Start(); err != nil {
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Failed to start logcat: %v", err), logger.LOG_LEVEL_ERROR)
return
}
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Logcat started (PID: %d)", logcatProcess.Process.Pid), logger.LOG_LEVEL_INFO)

// Parse logcat output in background
go func() {
scanner := bufio.NewScanner(processStdout)
for scanner.Scan() {
line := scanner.Text()
echoLog(&line)
}
if err := scanner.Err(); err != nil {
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Error reading logcat stdout: %v", err), logger.LOG_LEVEL_INFO)
}
}()
logcatProcess.Wait()
exitCode := logcatProcess.ProcessState.ExitCode()
if exitCode != 0 {
logger.LogEvent("ADB", "Logcat", fmt.Sprintf("Logcat process (PID: %d) exited with code %d", logcatProcess.Process.Pid, exitCode), logger.LOG_LEVEL_ERROR)
}
}()
}

// increases by 1s the delay between ps commands
func increaseSleep() {
psDelay += 1 * time.Second
logger.LogEvent("Watcher", "Delay", fmt.Sprintf("Delay increased to %v", psDelay), logger.LOG_LEVEL_INFO)
}

// decreases by 1s the delay between ps commands
func decreaseSleep() {
if psDelay > 1*time.Second {
psDelay -= 1 * time.Second
logger.LogEvent("Watcher", "Delay", fmt.Sprintf("Delay decreased to %v", psDelay), logger.LOG_LEVEL_INFO)
} else {
logger.LogEvent("Watcher", "Delay", "Delay cannot be decreased further, minimum is 1s", logger.LOG_LEVEL_INFO)
}
}

// prints the current delay between ps commands
func printDelay() {
logger.LogEvent("ADB", "PrintDelay", fmt.Sprintf("Current delay: %v", psDelay), logger.LOG_LEVEL_INFO)
}

// dump logcat buffer to a file
func dumpLogcat() {
cmd := exec.Command("adb", "logcat", "-d")
filename := time.Now().Format("2006-01-02_15-04-05") + "_belfast_logcat.log"
file, err := os.Create(filename)
if err != nil {
logger.LogEvent("ADB", "DumpLogcat", "Failed to create file", logger.LOG_LEVEL_ERROR)
return
}
cmd.Stdout = file
cmd.Stderr = file
if err := cmd.Run(); err != nil {
logger.LogEvent("ADB", "DumpLogcat", "Failed to dump logcat", logger.LOG_LEVEL_ERROR)
return
}
defer file.Close()
logger.LogEvent("ADB", "DumpLogcat", fmt.Sprintf("Logcat dumped to %s", filename), logger.LOG_LEVEL_INFO)
}

// main routine for ADB watcher, listens for key presses and executes commands
func ADBRoutine(tty *tty.TTY, flush bool) {
if tty == nil {
return // silently return, main function will handle the error
}
// Checking if adb is installed / in PATH
_, err := exec.LookPath("adb")
if err != nil {
logger.LogEvent("ADB", "Init", "ADB not found in PATH", logger.LOG_LEVEL_ERROR)
return
}
logger.LogEvent("ADB", "Init", "ADB watcher started", logger.LOG_LEVEL_INFO)
if flush {
flushLogcat()
}
help()

// Goroutine to find Azur Lane's PID
go func() {
for {
cmd := exec.Command("adb", "shell", "ps", "-A", "-o", "PID,NAME", "|", "grep", "-iE", grepRegex)
if out, err := cmd.Output(); err == nil {
for _, line := range strings.Split(string(out), "\n") {
newPid := 0
fmt.Sscanf(line, "%d", &newPid)
if newPid != 0 && newPid != azurLanePID {
azurLanePID = newPid
logger.LogEvent("ADB", "Shell", fmt.Sprintf("Azur Lane PID: %d", azurLanePID), logger.LOG_LEVEL_INFO)
stopLogcat() // force stop logcat to restart with new PID
toggleLogcat() // restart logcat with new PID
}
}
}
time.Sleep(psDelay)
}
}()

for {
// Read key from stdin
// If key is '?' print hello world
r, err := tty.ReadRune()
if err != nil {
logger.LogEvent("ADB", "ReadRune", fmt.Sprintf("Failed to read rune: %v", err), logger.LOG_LEVEL_ERROR)
break
}
if r == 'x' {
logger.LogEvent("ADB", "Exit", "ADB watcher exited", logger.LOG_LEVEL_INFO)
break
}
if handler, ok := handlers[string(r)]; ok {
handler()
}
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mattn/go-tty v0.0.5 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.52.0 // indirect
Expand Down
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,21 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-tty v0.0.5 h1:s09uXI7yDbXzzTTfw3zonKFzwGkyYlgU3OMjqA0ddz4=
github.com/mattn/go-tty v0.0.5/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
Expand All @@ -76,6 +82,9 @@ golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
Expand Down
Loading

0 comments on commit 955536f

Please sign in to comment.