source: code/trunk/service.go@ 150

Last change on this file since 150 was 150, checked in by contact, 5 years ago

Make BouncerServ commands a tree

For instance, replace "create-network" with "network create".

File size: 4.0 KB
Line 
1package soju
2
3import (
4 "flag"
5 "fmt"
6 "io/ioutil"
7 "strings"
8
9 "github.com/google/shlex"
10 "gopkg.in/irc.v3"
11)
12
13const serviceNick = "BouncerServ"
14
15type serviceCommandSet map[string]*serviceCommand
16
17type serviceCommand struct {
18 usage string
19 desc string
20 handle func(dc *downstreamConn, params []string) error
21 children serviceCommandSet
22}
23
24func sendServicePRIVMSG(dc *downstreamConn, text string) {
25 dc.SendMessage(&irc.Message{
26 Prefix: &irc.Prefix{Name: serviceNick},
27 Command: "PRIVMSG",
28 Params: []string{dc.nick, text},
29 })
30}
31
32func handleServicePRIVMSG(dc *downstreamConn, text string) {
33 words, err := shlex.Split(text)
34 if err != nil {
35 sendServicePRIVMSG(dc, fmt.Sprintf("error: failed to parse command: %v", err))
36 return
37 }
38
39 cmd, params, err := serviceCommands.Get(words)
40 if err != nil {
41 sendServicePRIVMSG(dc, fmt.Sprintf(`error: %v (type "help" for a list of commands)`, err))
42 return
43 }
44
45 if err := cmd.handle(dc, params); err != nil {
46 sendServicePRIVMSG(dc, fmt.Sprintf("error: %v", err))
47 }
48}
49
50func (cmds serviceCommandSet) Get(params []string) (*serviceCommand, []string, error) {
51 if len(params) == 0 {
52 return nil, nil, fmt.Errorf("no command specified")
53 }
54
55 name := params[0]
56 params = params[1:]
57
58 cmd, ok := cmds[name]
59 if !ok {
60 for k := range cmds {
61 if !strings.HasPrefix(k, name) {
62 continue
63 }
64 if cmd != nil {
65 return nil, params, fmt.Errorf("command %q is ambiguous", name)
66 }
67 cmd = cmds[k]
68 }
69 }
70 if cmd == nil {
71 return nil, params, fmt.Errorf("command %q not found", name)
72 }
73
74 if len(params) == 0 || len(cmd.children) == 0 {
75 return cmd, params, nil
76 }
77 return cmd.children.Get(params)
78}
79
80var serviceCommands serviceCommandSet
81
82func init() {
83 serviceCommands = serviceCommandSet{
84 "help": {
85 usage: "[command]",
86 desc: "print help message",
87 handle: handleServiceHelp,
88 },
89 "network": {
90 children: serviceCommandSet{
91 "create": {
92 usage: "-addr <addr> [-name name] [-username username] [-pass pass] [-realname realname] [-nick nick]",
93 desc: "add a new network",
94 handle: handleServiceCreateNetwork,
95 },
96 },
97 },
98 }
99}
100
101func appendServiceCommandSetHelp(cmds serviceCommandSet, prefix []string, l *[]string) {
102 for name, cmd := range cmds {
103 words := append(prefix, name)
104 if len(cmd.children) == 0 {
105 s := strings.Join(words, " ")
106 *l = append(*l, s)
107 } else {
108 appendServiceCommandSetHelp(cmd.children, words, l)
109 }
110 }
111}
112
113func handleServiceHelp(dc *downstreamConn, params []string) error {
114 if len(params) > 0 {
115 cmd, rest, err := serviceCommands.Get(params)
116 if err != nil {
117 return err
118 }
119 words := params[:len(params)-len(rest)]
120
121 if len(cmd.children) > 0 {
122 var l []string
123 appendServiceCommandSetHelp(cmd.children, words, &l)
124 sendServicePRIVMSG(dc, "available commands: "+strings.Join(l, ", "))
125 } else {
126 text := strings.Join(words, " ")
127 if cmd.usage != "" {
128 text += " " + cmd.usage
129 }
130 text += ": " + cmd.desc
131
132 sendServicePRIVMSG(dc, text)
133 }
134 } else {
135 var l []string
136 appendServiceCommandSetHelp(serviceCommands, nil, &l)
137 sendServicePRIVMSG(dc, "available commands: "+strings.Join(l, ", "))
138 }
139 return nil
140}
141
142func handleServiceCreateNetwork(dc *downstreamConn, params []string) error {
143 fs := flag.NewFlagSet("", flag.ContinueOnError)
144 fs.SetOutput(ioutil.Discard)
145 addr := fs.String("addr", "", "")
146 name := fs.String("name", "", "")
147 username := fs.String("username", "", "")
148 pass := fs.String("pass", "", "")
149 realname := fs.String("realname", "", "")
150 nick := fs.String("nick", "", "")
151
152 if err := fs.Parse(params); err != nil {
153 return err
154 }
155 if *addr == "" {
156 return fmt.Errorf("flag -addr is required")
157 }
158
159 if *nick == "" {
160 *nick = dc.nick
161 }
162
163 var err error
164 network, err := dc.user.createNetwork(&Network{
165 Addr: *addr,
166 Name: *name,
167 Username: *username,
168 Pass: *pass,
169 Realname: *realname,
170 Nick: *nick,
171 })
172 if err != nil {
173 return fmt.Errorf("could not create network: %v", err)
174 }
175
176 sendServicePRIVMSG(dc, fmt.Sprintf("created network %s successfully", network.GetName()))
177 return nil
178}
Note: See TracBrowser for help on using the repository browser.