Initial commit
This commit is contained in:
commit
0b1065e993
6 changed files with 128 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
mqtt2exec
|
6
Makefile
Normal file
6
Makefile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
all: mqtt2exec
|
||||||
|
.PHONY: mqtt2exec
|
||||||
|
|
||||||
|
mqtt2exec:
|
||||||
|
GOOS=linux GOARCH=arm go build -o mqtt2exec
|
||||||
|
arm-linux-gnueabihf-strip mqtt2exec
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -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 :)
|
10
go.mod
Normal file
10
go.mod
Normal file
|
@ -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
|
||||||
|
)
|
8
go.sum
Normal file
8
go.sum
Normal file
|
@ -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=
|
76
main.go
Normal file
76
main.go
Normal file
|
@ -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 <broker> <client_id> <username> <password>", 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")
|
||||||
|
}
|
Loading…
Reference in a new issue