Skip to content
This repository was archived by the owner on Jun 5, 2018. It is now read-only.

Commit 4924a04

Browse files
committed
Allow arbitrary JSON as last parameter
1 parent fb9bcd3 commit 4924a04

File tree

3 files changed

+266
-84
lines changed

3 files changed

+266
-84
lines changed

main.go

+74-84
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ package main
66
import (
77
"encoding/json"
88
"flag"
9-
"log"
9+
"fmt"
1010
"net"
1111
"os"
1212
"strings"
@@ -20,9 +20,6 @@ var (
2020
)
2121

2222
func main() {
23-
log.SetOutput(os.Stdout)
24-
log.SetFlags(0)
25-
2623
verbose := flag.Bool("v", false, "Verbose output")
2724
flag.Usage = usage
2825
flag.Parse()
@@ -33,16 +30,16 @@ func main() {
3330
os.Exit(2)
3431
}
3532

36-
log.Println("psmcli", Version)
37-
log.Println("^D to quit")
33+
fmt.Println("psmcli", Version)
34+
fmt.Println("^D to quit")
3835

3936
// Add default port 3994 if it's missing in the dst string
4037

4138
host, port, err := net.SplitHostPort(dst)
4239
if err != nil && strings.Contains(err.Error(), "missing port") {
4340
dst = net.JoinHostPort(dst, "3994")
4441
} else if err != nil {
45-
log.Println(err)
42+
fmt.Println(err)
4643
return
4744
} else if port == "" {
4845
dst = net.JoinHostPort(host, "3994")
@@ -52,18 +49,18 @@ func main() {
5249

5350
conn, err := newConnection(dst)
5451
if err != nil {
55-
log.Println(err)
52+
fmt.Println(err)
5653
return
5754
}
58-
log.Println("Connected to", conn.conn.RemoteAddr())
59-
log.Println("")
55+
fmt.Println("Connected to", conn.conn.RemoteAddr())
56+
fmt.Println("")
6057

6158
// Use system.version as dummy call to check if we can proceed without
6259
// authentication.
6360

6461
res, err := conn.run(command{Method: "system.version"})
6562
if err != nil {
66-
log.Println(err)
63+
fmt.Println(err)
6764
return
6865
}
6966

@@ -76,19 +73,19 @@ func main() {
7673

7774
oldState, err := terminal.MakeRaw(0)
7875
if err != nil {
79-
log.Println(err)
76+
fmt.Println(err)
8077
return
8178
}
8279
defer func() {
8380
terminal.Restore(0, oldState)
84-
log.Println("")
81+
fmt.Println("")
8582
}()
8683

8784
term := terminal.NewTerminal(os.NewFile(0, "terminal"), initialPrompt)
8885

8986
h, w, err := terminal.GetSize(0)
9087
if err != nil {
91-
log.Println(err)
88+
fmt.Println(err)
9289
return
9390
}
9491
term.SetSize(h, w)
@@ -98,26 +95,26 @@ func main() {
9895
term.SetPrompt("Username: ")
9996
user, err = term.ReadLine()
10097
if err != nil {
101-
log.Println(err)
98+
fmt.Println(err)
10299
return
103100
}
104101
pass, err := term.ReadPassword("Password: ")
105102
if err != nil {
106-
log.Println(err)
103+
fmt.Println(err)
107104
return
108105
}
109106
res, err = conn.run(command{Method: "system.login", Params: []interface{}{user, pass}})
110107
if err != nil {
111-
log.Println(err)
108+
fmt.Println(err)
112109
return
113110
}
114111
if res.Error.Code != 0 {
115-
log.Println(res.Error.Message)
116-
log.Println()
112+
fmt.Println(res.Error.Message)
113+
fmt.Println()
117114
} else {
118115
res, err = conn.run(command{Method: "system.version"})
119116
if err != nil {
120-
log.Println(err)
117+
fmt.Println(err)
121118
return
122119
}
123120
}
@@ -132,19 +129,19 @@ func main() {
132129

133130
res, err = conn.run(command{Method: "system.hostname"})
134131
if err != nil {
135-
log.Println(err)
132+
fmt.Println(err)
136133
return
137134
}
138135
hostname, ok := res.Result.(string)
139136
if !ok {
140137
hostname = "(unknown)"
141138
}
142139

143-
log.Println("PSM version", version, "at", hostname)
140+
fmt.Println("PSM version", version, "at", hostname)
144141

145142
res, err = conn.run(command{Method: "model.isReadOnly"})
146143
if err != nil {
147-
log.Println(err)
144+
fmt.Println(err)
148145
return
149146
}
150147

@@ -160,13 +157,14 @@ func main() {
160157
hostname = hostnameParts[0]
161158
term.SetPrompt(user + "@" + hostname + roRw)
162159

163-
log.Println()
160+
fmt.Println()
164161

165162
// Set up tab completion based on announced commands and parameters
166163

167164
smd, err := conn.smd()
168165
if err != nil {
169-
log.Fatal(err)
166+
fmt.Println(err)
167+
os.Exit(1)
170168
}
171169

172170
matchers := importSMD(smd.Result.Services)
@@ -175,6 +173,7 @@ func main() {
175173

176174
// Start the REPL
177175

176+
id := 0
178177
for {
179178
line, err := term.ReadLine()
180179
if err != nil {
@@ -187,33 +186,34 @@ func main() {
187186
}
188187

189188
if line == "help" || line == "?" {
190-
completer.PrintHelp(term.Escape)
189+
printHelp(term.Escape)
191190
continue
192191
}
193-
194-
fields := strings.Fields(line)
195-
if len(fields) < 2 {
196-
log.Println("incomplete command")
192+
if line == "commands" {
193+
completer.PrintHelp(term.Escape)
197194
continue
198195
}
199196

200-
cmd, err := parseCommand(fields)
197+
cmd, err := parseCommand(line)
201198
if err != nil {
202-
log.Println(err)
199+
fmt.Println(err)
203200
continue
204201
}
205202

203+
cmd.ID = id
204+
id++
205+
206206
if *verbose {
207207
// Print the command locally
208208
bs, _ := json.Marshal(cmd)
209-
log.Printf("> %s", bs)
209+
fmt.Printf("> %s", bs)
210210
}
211211

212212
// Execute command on PSM
213213

214214
res, err := conn.run(cmd)
215215
if err != nil {
216-
log.Println(err)
216+
fmt.Println(err)
217217
return
218218
}
219219

@@ -222,75 +222,65 @@ func main() {
222222
}
223223

224224
func usage() {
225-
log.Println("psmcli", Version)
226-
log.Println()
227-
log.Println("Usage:")
228-
log.Println(" psmcli [-v] <host:port>")
229-
}
230-
231-
var nextID int
232-
233-
func parseCommand(fields []string) (command, error) {
234-
// The command is the first two parts joined with a dot.
235-
236-
cmd := command{
237-
ID: nextID,
238-
Method: fields[0] + "." + fields[1],
239-
}
240-
nextID++
241-
242-
// Look for key=val,key=val sequences among params and make them objects.
243-
// Not stuff that starts with "(" though, because that might be an LDAP
244-
// query expression.
245-
246-
for _, param := range fields[2:] {
247-
if strings.HasPrefix(param, "{") {
248-
var obj map[string]interface{}
249-
err := json.Unmarshal([]byte(param), &obj)
250-
if err != nil {
251-
return command{}, err
252-
}
253-
cmd.Params = append(cmd.Params, obj)
254-
} else if strings.Contains(param, "=") && !strings.HasPrefix(param, "(") {
255-
parts := strings.Split(param, ",")
256-
obj := map[string]string{}
257-
for _, part := range parts {
258-
kv := strings.SplitN(part, "=", 2)
259-
obj[kv[0]] = kv[1]
260-
}
261-
cmd.Params = append(cmd.Params, obj)
262-
} else {
263-
cmd.Params = append(cmd.Params, param)
264-
}
265-
}
266-
267-
return cmd, nil
225+
fmt.Println("psmcli", Version)
226+
fmt.Println()
227+
fmt.Println("Usage:")
228+
fmt.Println(" psmcli [-v] <host:port>")
268229
}
269230

270231
func printResponse(res response) {
271232
if res.Error.Code != 0 {
272-
log.Printf("Error %d: %s", res.Error.Code, res.Error.Message)
233+
fmt.Printf("Error %d: %s", res.Error.Code, res.Error.Message)
273234
} else if res.Result != nil {
274235
switch result := res.Result.(type) {
275236
case []interface{}:
276237
for _, res := range result {
277238
switch res := res.(type) {
278239
case string, int, json.Number:
279-
log.Println(res)
240+
fmt.Println(res)
280241
default:
281242
bs, _ := json.MarshalIndent(res, "", " ")
282-
log.Printf("%s\n\n", bs)
243+
fmt.Printf("%s\n\n", bs)
283244
}
284245
}
285246

286247
case map[string]interface{}:
287248
bs, _ := json.MarshalIndent(result, "", " ")
288-
log.Printf("%s\n\n", bs)
249+
fmt.Printf("%s\n\n", bs)
289250

290251
default:
291-
log.Println(result)
252+
fmt.Println(result)
292253
}
293-
} else {
294-
log.Println("OK")
295254
}
296255
}
256+
257+
func printHelp(esc *terminal.EscapeCodes) {
258+
fmt.Println(`Usage:
259+
260+
help, ?:
261+
Print this help
262+
263+
commands:
264+
Print available PSM commands. Commands have tab completion available.
265+
266+
Examples:
267+
268+
Simple command without parameter:
269+
$ system hostname
270+
271+
Command with parameters:
272+
$ object deleteByAid subscriber 1234
273+
274+
Command with object parameters:
275+
$ object updateByAid subscriber 1234 attr=value
276+
$ object updateByAid subscriber 1234 attr1=value1,attr2=value2
277+
278+
(No spaces in the object parameter!)
279+
280+
Command with arbitrary JSON object parameter:
281+
$ object updateByAid subscriber 1234
282+
{"attr1": "value1 with space", "attr2": "value2"}
283+
284+
(Line break for display purposes only)
285+
`)
286+
}

0 commit comments

Comments
 (0)