commit 0b1065e99314d9fbb86df1b272dc644495ffca52 Author: Łukasz Moskała Date: Sun Dec 22 20:19:23 2024 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d409c81 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +mqtt2exec \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..356ac94 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +all: mqtt2exec +.PHONY: mqtt2exec + +mqtt2exec: + GOOS=linux GOARCH=arm go build -o mqtt2exec + arm-linux-gnueabihf-strip mqtt2exec \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f222dea --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Setup + +Root android with magisk + +Install busybox + +Create init script at `/data/adb/service.d/mqtt2exec.sh` + +```shell +#!/system/bin/sh +/system/xbin/start-stop-daemon -S -b /system/xbin/mqtt2exec -- tcp://ENDPOINT:1883 CLIENT_ID USERNAME PASSWORD +exit 0 +``` + +Set it as executable: `chmod +x /data/adb/service.d/mqtt2exec.sh` + +Install binary: + +```shell +adb push mqtt2exec /storage/emulated/0/mqtt2exec +adb shell +su +mv /storage/emulated/0/mqtt2exec /system/xbin/mqtt2exec +chmod +x /system/xbin/mqtt2exec +``` + +Reboot :) \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d44883f --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module mqtt2exec + +go 1.23 + +require ( + github.com/eclipse/paho.mqtt.golang v1.5.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sync v0.7.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..b555dd0 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= +github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= diff --git a/main.go b/main.go new file mode 100644 index 0000000..b5eca01 --- /dev/null +++ b/main.go @@ -0,0 +1,76 @@ +package main + +import ( + "encoding/json" + mqtt "github.com/eclipse/paho.mqtt.golang" + "log" + "os" + "os/exec" + "time" +) + +type Result struct { + Command string + Output string + Error string +} + +func main() { + + var msgchan = make(chan mqtt.Message, 4) + + if len(os.Args) < 5 { + log.Fatalf("Usage: %s ", os.Args[0]) + } + opts := mqtt.NewClientOptions() + opts.AddBroker(os.Args[1]) + opts.SetClientID(os.Args[2]) + opts.SetUsername(os.Args[3]) + opts.SetPassword(os.Args[4]) + opts.SetDefaultPublishHandler(func(client mqtt.Client, msg mqtt.Message) { + msgchan <- msg + }) + opts.OnConnect = connectHandler + opts.SetKeepAlive(20 * time.Second) + opts.SetAutoReconnect(true) + opts.SetWill("mqtt2exec/"+os.Args[2]+"/state", "offline", 1, false) + client := mqtt.NewClient(opts) + sleep := 1 * time.Second + for { + if token := client.Connect(); token.Wait() && token.Error() != nil { + log.Printf("Initial connection failed: %s", token.Error()) + sleep *= 2 + time.Sleep(sleep) + } else { + log.Printf("Connected to broker: %s", os.Args[1]) + break + } + } + for { + msg := <-msgchan + if msg.Topic() == "mqtt2exec/"+os.Args[2]+"/run" { + cmd := exec.Command("/system/xbin/busybox", "ash", "-c", string(msg.Payload())) + cmd.Stdin = nil + out, err := cmd.CombinedOutput() + result := Result{ + Command: string(msg.Payload()), + Output: string(out), + } + if err != nil { + result.Error = err.Error() + } + resultJSON, _ := json.Marshal(result) + client.Publish("mqtt2exec/"+os.Args[2]+"/result", 0, false, resultJSON) + } + } + +} + +func connectHandler(c mqtt.Client) { + token := c.Subscribe("mqtt2exec/"+os.Args[2]+"/run", 2, nil) + token.Wait() + if token.Error() != nil { + log.Printf("mqtt2exec: Error subscribing to topic: %s", token.Error()) + } + c.Publish("mqtt2exec/"+os.Args[2]+"/state", 1, false, "online") +}