/
onetouch.go
107 lines (94 loc) · 2.6 KB
/
onetouch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main
import (
"github.com/dbrain/soggy"
"encoding/json"
"os"
"os/exec"
"io/ioutil"
"io"
"errors"
"fmt"
)
type CommandLine struct {
Cmd string `json:"cmd,omitempty"`
Args []string `json:"args,omitempty"`
}
type Config struct {
Name string
Description string
Host string
Port string
Password string
Commands []struct {
ShortName string `json:"shortName,omitempty"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
FailOnError bool `json:"failOnError,omitempty"`
Exec []CommandLine `json:"exec,omitempty"`
}
}
var config *Config
func passwordAuthenticate(ctx *soggy.Context) (int, string) {
if config.Password != "" {
headers := ctx.Req.Header
if (headers.Get("Authorization") != config.Password) {
return 403, "Invalid password"
}
}
ctx.Next(nil)
return -1, ""
}
func info() interface{} {
return map[string]interface{} {
"passwordRequired": config.Password != "" }
}
func listCommands() interface{} {
return map[string]interface{} { "commands": config.Commands }
}
func executeCommandLine(ctx *soggy.Context, cmdToExecute CommandLine) (err error) {
defer func() {
if recovered := recover(); recovered != nil { err = errors.New(recovered.(string)) }
}()
cmd := exec.Command(cmdToExecute.Cmd, cmdToExecute.Args...)
stdout, err := cmd.StdoutPipe()
stderr, err := cmd.StderrPipe()
err = cmd.Start()
go io.Copy(ctx.Res, stdout)
go io.Copy(ctx.Res, stderr)
err = cmd.Wait()
return err
}
func executeCommand(ctx *soggy.Context, commandName string) (err error) {
for _, command := range config.Commands {
if command.ShortName == commandName {
for _, cmdToExecute := range command.Exec {
err = executeCommandLine(ctx, cmdToExecute)
if (err != nil && command.FailOnError) {
return err
} else if (err != nil) {
ctx.Res.WriteString(fmt.Sprintln(cmdToExecute.Cmd, cmdToExecute.Args, "failed with", err))
}
}
return nil
}
}
ctx.Res.WriteHeader(404)
ctx.Res.WriteString("Command not found.")
return nil
}
func startServer() {
app, server := soggy.NewDefaultApp()
server.Get("/commands", passwordAuthenticate, listCommands)
server.Get("/commands/(.*)", passwordAuthenticate, executeCommand)
server.Get("/info", info)
server.Use(server.Router)
app.Listen(config.Host + ":" + config.Port)
}
func main() {
home := os.Getenv("HOME")
configFile, err := ioutil.ReadFile(home + "/.onetouch/config.json")
if (err != nil) { panic(err) }
config = new(Config)
json.Unmarshal(configFile, config)
startServer()
}