Commit 418bcf0e authored by Audrius Butkevicius's avatar Audrius Butkevicius

Refactor commands

parent bec5cbb0
......@@ -7,52 +7,58 @@ import (
"strings"
)
var errorCommand = cli.Command{
Name: "errors",
HideHelp: true,
Usage: "Error command group",
Subcommands: []cli.Command{
{
Name: "show",
Usage: "Show pending errors",
Requires: &cli.Requires{},
Action: func(c *cli.Context) {
response := httpGet(c, "errors")
var data []map[string]interface{}
json.Unmarshal(responseToBArray(response), &data)
writer := newTableWriter()
for _, item := range data {
time := item["Time"].(string)[:19]
time = strings.Replace(time, "T", " ", 1)
err := item["Error"].(string)
err = strings.TrimSpace(err)
fmt.Fprintln(writer, time+":\t"+err)
}
writer.Flush()
func init() {
cliCommands = append(cliCommands, cli.Command{
Name: "errors",
HideHelp: true,
Usage: "Error command group",
Subcommands: []cli.Command{
{
Name: "show",
Usage: "Show pending errors",
Requires: &cli.Requires{},
Action: errorsShow,
},
},
{
Name: "push",
Usage: "Push an error to active clients",
Requires: &cli.Requires{"error message..."},
Action: func(c *cli.Context) {
err := strings.Join(c.Args(), " ")
response := httpPost(c, "error", strings.TrimSpace(err))
if response.StatusCode != 200 {
err = fmt.Sprint("Failed to push error\nStatus code: ", response.StatusCode)
body := string(responseToBArray(response))
if body != "" {
err += "\nBody: " + body
}
die(err)
}
{
Name: "push",
Usage: "Push an error to active clients",
Requires: &cli.Requires{"error message..."},
Action: errorsPush,
},
{
Name: "clear",
Usage: "Clear pending errors",
Requires: &cli.Requires{},
Action: wrappedHttpPost("error/clear"),
},
},
{
Name: "clear",
Usage: "Clear pending errors",
Requires: &cli.Requires{},
Action: wrappedHttpPost("error/clear"),
},
},
})
}
func errorsShow(c *cli.Context) {
response := httpGet(c, "errors")
var data []map[string]interface{}
json.Unmarshal(responseToBArray(response), &data)
writer := newTableWriter()
for _, item := range data {
time := item["Time"].(string)[:19]
time = strings.Replace(time, "T", " ", 1)
err := item["Error"].(string)
err = strings.TrimSpace(err)
fmt.Fprintln(writer, time+":\t"+err)
}
writer.Flush()
}
func errorsPush(c *cli.Context) {
err := strings.Join(c.Args(), " ")
response := httpPost(c, "error", strings.TrimSpace(err))
if response.StatusCode != 200 {
err = fmt.Sprint("Failed to push error\nStatus code: ", response.StatusCode)
body := string(responseToBArray(response))
if body != "" {
err += "\nBody: " + body
}
die(err)
}
}
......@@ -6,61 +6,69 @@ import (
"github.com/AudriusButkevicius/cli"
)
var generalCommands = []cli.Command{
{
Name: "id",
Usage: "Get ID of the Syncthing client",
Requires: &cli.Requires{},
Action: func(c *cli.Context) {
fmt.Println(getMyID(c))
func init() {
cliCommands = append(cliCommands, []cli.Command{
{
Name: "id",
Usage: "Get ID of the Syncthing client",
Requires: &cli.Requires{},
Action: generalID,
},
},
{
Name: "status",
Usage: "Configuration status, whether or not a restart is required for changes to take effect",
Requires: &cli.Requires{},
Action: func(c *cli.Context) {
response := httpGet(c, "config/sync")
status := make(map[string]interface{})
json.Unmarshal(responseToBArray(response), &status)
if status["configInSync"] != true {
die("Config out of sync")
}
fmt.Println("Config in sync")
{
Name: "status",
Usage: "Configuration status, whether or not a restart is required for changes to take effect",
Requires: &cli.Requires{},
Action: generalStatus,
},
},
{
Name: "restart",
Usage: "Restart syncthing",
Requires: &cli.Requires{},
Action: wrappedHttpPost("restart"),
},
{
Name: "shutdown",
Usage: "Shutdown syncthing",
Requires: &cli.Requires{},
Action: wrappedHttpPost("shutdown"),
},
{
Name: "reset",
Usage: "Reset syncthing deleting all repositories and nodes",
Requires: &cli.Requires{},
Action: wrappedHttpPost("reset"),
},
{
Name: "upgrade",
Usage: "Upgrade syncthing (if a newer version is available)",
Requires: &cli.Requires{},
Action: wrappedHttpPost("upgrade"),
},
{
Name: "version",
Usage: "Syncthing client version",
Requires: &cli.Requires{},
Action: func(c *cli.Context) {
response := httpGet(c, "version")
output := string(responseToBArray(response))
fmt.Println(output)
{
Name: "restart",
Usage: "Restart syncthing",
Requires: &cli.Requires{},
Action: wrappedHttpPost("restart"),
},
},
{
Name: "shutdown",
Usage: "Shutdown syncthing",
Requires: &cli.Requires{},
Action: wrappedHttpPost("shutdown"),
},
{
Name: "reset",
Usage: "Reset syncthing deleting all repositories and nodes",
Requires: &cli.Requires{},
Action: wrappedHttpPost("reset"),
},
{
Name: "upgrade",
Usage: "Upgrade syncthing (if a newer version is available)",
Requires: &cli.Requires{},
Action: wrappedHttpPost("upgrade"),
},
{
Name: "version",
Usage: "Syncthing client version",
Requires: &cli.Requires{},
Action: generalVersion,
},
}...)
}
func generalID(c *cli.Context) {
fmt.Println(getMyID(c))
}
func generalStatus(c *cli.Context) {
response := httpGet(c, "config/sync")
status := make(map[string]interface{})
json.Unmarshal(responseToBArray(response), &status)
if status["configInSync"] != true {
die("Config out of sync")
}
fmt.Println("Config in sync")
}
func generalVersion(c *cli.Context) {
response := httpGet(c, "version")
output := string(responseToBArray(response))
fmt.Println(output)
}
......@@ -6,109 +6,119 @@ import (
"strings"
)
var guiCommand = cli.Command{
Name: "gui",
HideHelp: true,
Usage: "GUI command group",
Subcommands: []cli.Command{
{
Name: "dump",
Usage: "Show all GUI configuration settings",
Requires: &cli.Requires{},
Action: func(c *cli.Context) {
cfg := getConfig(c).GUI
writer := newTableWriter()
fmt.Fprintln(writer, "Enabled:\t", cfg.Enabled, "\t(enabled)")
fmt.Fprintln(writer, "Use HTTPS:\t", cfg.UseTLS, "\t(tls)")
fmt.Fprintln(writer, "Listen Addresses:\t", cfg.Address, "\t(address)")
if cfg.User != "" {
fmt.Fprintln(writer, "Authentication User:\t", cfg.User, "\t(username)")
fmt.Fprintln(writer, "Authentication Password:\t", cfg.Password, "\t(password)")
}
if cfg.APIKey != "" {
fmt.Fprintln(writer, "API Key:\t", cfg.APIKey, "\t(apikey)")
}
writer.Flush()
func init() {
cliCommands = append(cliCommands, cli.Command{
Name: "gui",
HideHelp: true,
Usage: "GUI command group",
Subcommands: []cli.Command{
{
Name: "dump",
Usage: "Show all GUI configuration settings",
Requires: &cli.Requires{},
Action: guiDump,
},
},
{
Name: "get",
Usage: "Get a GUI configuration setting",
Requires: &cli.Requires{"setting"},
Action: func(c *cli.Context) {
cfg := getConfig(c).GUI
arg := c.Args()[0]
switch strings.ToLower(arg) {
case "enabled":
fmt.Println(cfg.Enabled)
case "tls":
fmt.Println(cfg.UseTLS)
case "address":
fmt.Println(cfg.Address)
case "user":
if cfg.User != "" {
fmt.Println(cfg.User)
}
case "password":
if cfg.User != "" {
fmt.Println(cfg.Password)
}
case "apikey":
if cfg.APIKey != "" {
fmt.Println(cfg.APIKey)
}
default:
die("Invalid setting: " + arg + "\nAvailable settings: enabled, tls, address, user, password, apikey")
}
{
Name: "get",
Usage: "Get a GUI configuration setting",
Requires: &cli.Requires{"setting"},
Action: guiGet,
},
},
{
Name: "set",
Usage: "Set a GUI configuration setting",
Requires: &cli.Requires{"setting", "value"},
Action: func(c *cli.Context) {
cfg := getConfig(c)
arg := c.Args()[0]
val := c.Args()[1]
switch strings.ToLower(arg) {
case "enabled":
cfg.GUI.Enabled = parseBool(val)
case "tls":
cfg.GUI.UseTLS = parseBool(val)
case "address":
validAddress(val)
cfg.GUI.Address = val
case "user":
cfg.GUI.User = val
case "password":
cfg.GUI.Password = val
case "apikey":
cfg.GUI.APIKey = val
default:
die("Invalid setting: " + arg + "\nAvailable settings: enabled, tls, address, user, password, apikey")
}
setConfig(c, cfg)
{
Name: "set",
Usage: "Set a GUI configuration setting",
Requires: &cli.Requires{"setting", "value"},
Action: guiSet,
},
},
{
Name: "unset",
Usage: "Unset a GUI configuration setting",
Requires: &cli.Requires{"setting"},
Action: func(c *cli.Context) {
cfg := getConfig(c)
arg := c.Args()[0]
switch strings.ToLower(arg) {
case "user":
cfg.GUI.User = ""
case "password":
cfg.GUI.Password = ""
case "apikey":
cfg.GUI.APIKey = ""
default:
die("Invalid setting: " + arg + "\nAvailable settings: user, password, apikey")
}
setConfig(c, cfg)
{
Name: "unset",
Usage: "Unset a GUI configuration setting",
Requires: &cli.Requires{"setting"},
Action: guiUnset,
},
},
},
})
}
func guiDump(c *cli.Context) {
cfg := getConfig(c).GUI
writer := newTableWriter()
fmt.Fprintln(writer, "Enabled:\t", cfg.Enabled, "\t(enabled)")
fmt.Fprintln(writer, "Use HTTPS:\t", cfg.UseTLS, "\t(tls)")
fmt.Fprintln(writer, "Listen Addresses:\t", cfg.Address, "\t(address)")
if cfg.User != "" {
fmt.Fprintln(writer, "Authentication User:\t", cfg.User, "\t(username)")
fmt.Fprintln(writer, "Authentication Password:\t", cfg.Password, "\t(password)")
}
if cfg.APIKey != "" {
fmt.Fprintln(writer, "API Key:\t", cfg.APIKey, "\t(apikey)")
}
writer.Flush()
}
func guiGet(c *cli.Context) {
cfg := getConfig(c).GUI
arg := c.Args()[0]
switch strings.ToLower(arg) {
case "enabled":
fmt.Println(cfg.Enabled)
case "tls":
fmt.Println(cfg.UseTLS)
case "address":
fmt.Println(cfg.Address)
case "user":
if cfg.User != "" {
fmt.Println(cfg.User)
}
case "password":
if cfg.User != "" {
fmt.Println(cfg.Password)
}
case "apikey":
if cfg.APIKey != "" {
fmt.Println(cfg.APIKey)
}
default:
die("Invalid setting: " + arg + "\nAvailable settings: enabled, tls, address, user, password, apikey")
}
}
func guiSet(c *cli.Context) {
cfg := getConfig(c)
arg := c.Args()[0]
val := c.Args()[1]
switch strings.ToLower(arg) {
case "enabled":
cfg.GUI.Enabled = parseBool(val)
case "tls":
cfg.GUI.UseTLS = parseBool(val)
case "address":
validAddress(val)
cfg.GUI.Address = val
case "user":
cfg.GUI.User = val
case "password":
cfg.GUI.Password = val
case "apikey":
cfg.GUI.APIKey = val
default:
die("Invalid setting: " + arg + "\nAvailable settings: enabled, tls, address, user, password, apikey")
}
setConfig(c, cfg)
}
func guiUnset(c *cli.Context) {
cfg := getConfig(c)
arg := c.Args()[0]
switch strings.ToLower(arg) {
case "user":
cfg.GUI.User = ""
case "password":
cfg.GUI.Password = ""
case "apikey":
cfg.GUI.APIKey = ""
default:
die("Invalid setting: " + arg + "\nAvailable settings: user, password, apikey")
}
setConfig(c, cfg)
}
......@@ -7,151 +7,163 @@ import (
"strings"
)
var nodeCommand = cli.Command{
Name: "nodes",
HideHelp: true,
Usage: "Node command group",
Subcommands: []cli.Command{
{
Name: "list",
Usage: "List registered nodes",
Requires: &cli.Requires{},
Action: func(c *cli.Context) {
cfg := getConfig(c)
first := true
writer := newTableWriter()
for _, node := range cfg.Nodes {
if !first {
fmt.Fprintln(writer)
}
fmt.Fprintln(writer, "ID:\t", node.NodeID, "\t")
fmt.Fprintln(writer, "Name:\t", node.Name, "\t(name)")
fmt.Fprintln(writer, "Address:\t", strings.Join(node.Addresses, " "), "\t(address)")
first = false
}
writer.Flush()
func init() {
cliCommands = append(cliCommands, cli.Command{
Name: "nodes",
HideHelp: true,
Usage: "Node command group",
Subcommands: []cli.Command{
{
Name: "list",
Usage: "List registered nodes",
Requires: &cli.Requires{},
Action: nodesList,
},
{
Name: "add",
Usage: "Add a new node",
Requires: &cli.Requires{"node id", "node name?"},
Action: nodesAdd,
},
{
Name: "remove",
Usage: "Remove an existing node",
Requires: &cli.Requires{"node id"},
Action: nodesRemove,
},
{
Name: "get",
Usage: "Get a property of a node",
Requires: &cli.Requires{"node id", "property"},
Action: nodesGet,
},
{
Name: "set",
Usage: "Set a property of a node",
Requires: &cli.Requires{"node id", "property", "value..."},
Action: nodesSet,
},
},
{
Name: "add",
Usage: "Add a new node",
Requires: &cli.Requires{"node id", "node name?"},
Action: func(c *cli.Context) {
nid := c.Args()[0]
id := parseNodeID(nid)
})
}
newNode := config.NodeConfiguration{
NodeID: id,
Name: nid,
Addresses: []string{"dynamic"},
}
func nodesList(c *cli.Context) {
cfg := getConfig(c)
first := true
writer := newTableWriter()
for _, node := range cfg.Nodes {
if !first {
fmt.Fprintln(writer)
}
fmt.Fprintln(writer, "ID:\t", node.NodeID, "\t")
fmt.Fprintln(writer, "Name:\t", node.Name, "\t(name)")
fmt.Fprintln(writer, "Address:\t", strings.Join(node.Addresses, " "), "\t(address)")
first = false
}
writer.Flush()
}
if len(c.Args()) > 1 {
newNode.Name = c.Args()[1]
}
func nodesAdd(c *cli.Context) {
nid := c.Args()[0]
id := parseNodeID(nid)
if len(c.Args()) > 2 {
addresses := c.Args()[2:]
for _, item := range addresses {
if item == "dynamic" {
continue
}
validAddress(item)
}
newNode.Addresses = addresses
}
newNode := config.NodeConfiguration{
NodeID: id,
Name: nid,
Addresses: []string{"dynamic"},
}
cfg := getConfig(c)
for _, node := range cfg.Nodes {
if node.NodeID == id {
die("Node " + nid + " already exists")
}
}
cfg.Nodes = append(cfg.Nodes, newNode)
setConfig(c, cfg)
},
},
{
Name: "remove",
Usage: "Remove an existing node",
Requires: &cli.Requires{"node id"},
Action: func(c *cli.Context) {
nid := c.Args()[0]
id := parseNodeID(nid)
if nid == getMyID(c) {
die("Cannot remove yourself")
}
cfg := getConfig(c)
for i, node := range cfg.Nodes {
if node.NodeID == id {
last := len(cfg.Nodes) - 1
cfg.Nodes[i] = cfg.Nodes[last]
cfg.Nodes = cfg.Nodes[:last]
setConfig(c, cfg)
return
}
}
die("Node " + nid + " not found")
},
},
{
Name: "get",
Usage: "Get a property of a node",
Requires: &cli.Requires{"node id", "property"},
Action: func(c *cli.Context) {
nid := c.Args()[0]
id := parseNodeID(nid)
arg := c.Args()[1]
cfg := getConfig(c)
for _, node := range cfg.Nodes {
if node.NodeID != id {
continue
}
switch strings.ToLower(arg) {
case "name":
fmt.Println(node.Name)
case "address":
fmt.Println(strings.Join(node.Addresses, "\n"))
default:
die("Invalid property: " + arg + "\nAvailable properties: name, address")
}
return
}
die("Node " + nid + " not found")
},
},
{
Name: "set",
Usage: "Set a property of a node",
Requires: &cli.Requires{"node id", "property", "value..."},
Action: func(c *cli.Context) {
nid := c.Args()[0]
id := parseNodeID(nid)
arg := c.Args()[1]
config := getConfig(c)
for i, node := range config.Nodes {
if node.NodeID != id {
continue
}
switch strings.ToLower(arg) {
case "name":
config.Nodes[i].Name = strings.Join(c.Args