source: code/trunk/service.go@ 228

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

Only print addr if necessary in network status service command

File size: 5.7 KB
RevLine 
[117]1package soju
2
3import (
[120]4 "flag"
[117]5 "fmt"
[120]6 "io/ioutil"
[117]7 "strings"
8
9 "github.com/google/shlex"
10 "gopkg.in/irc.v3"
11)
12
13const serviceNick = "BouncerServ"
14
[220]15var servicePrefix = &irc.Prefix{
16 Name: serviceNick,
17 User: serviceNick,
18 Host: serviceNick,
19}
20
[150]21type serviceCommandSet map[string]*serviceCommand
22
[117]23type serviceCommand struct {
[150]24 usage string
25 desc string
26 handle func(dc *downstreamConn, params []string) error
27 children serviceCommandSet
[117]28}
29
[218]30func sendServiceNOTICE(dc *downstreamConn, text string) {
31 dc.SendMessage(&irc.Message{
[220]32 Prefix: servicePrefix,
[218]33 Command: "NOTICE",
34 Params: []string{dc.nick, text},
35 })
36}
37
[117]38func sendServicePRIVMSG(dc *downstreamConn, text string) {
39 dc.SendMessage(&irc.Message{
[220]40 Prefix: servicePrefix,
[117]41 Command: "PRIVMSG",
42 Params: []string{dc.nick, text},
43 })
44}
45
46func handleServicePRIVMSG(dc *downstreamConn, text string) {
47 words, err := shlex.Split(text)
48 if err != nil {
49 sendServicePRIVMSG(dc, fmt.Sprintf("error: failed to parse command: %v", err))
50 return
51 }
52
[150]53 cmd, params, err := serviceCommands.Get(words)
54 if err != nil {
55 sendServicePRIVMSG(dc, fmt.Sprintf(`error: %v (type "help" for a list of commands)`, err))
[117]56 return
57 }
58
59 if err := cmd.handle(dc, params); err != nil {
60 sendServicePRIVMSG(dc, fmt.Sprintf("error: %v", err))
61 }
62}
63
[150]64func (cmds serviceCommandSet) Get(params []string) (*serviceCommand, []string, error) {
65 if len(params) == 0 {
66 return nil, nil, fmt.Errorf("no command specified")
67 }
[117]68
[150]69 name := params[0]
70 params = params[1:]
71
72 cmd, ok := cmds[name]
73 if !ok {
74 for k := range cmds {
75 if !strings.HasPrefix(k, name) {
76 continue
77 }
78 if cmd != nil {
79 return nil, params, fmt.Errorf("command %q is ambiguous", name)
80 }
81 cmd = cmds[k]
82 }
83 }
84 if cmd == nil {
85 return nil, params, fmt.Errorf("command %q not found", name)
86 }
87
88 if len(params) == 0 || len(cmd.children) == 0 {
89 return cmd, params, nil
90 }
91 return cmd.children.Get(params)
92}
93
94var serviceCommands serviceCommandSet
95
[117]96func init() {
[150]97 serviceCommands = serviceCommandSet{
[117]98 "help": {
99 usage: "[command]",
100 desc: "print help message",
101 handle: handleServiceHelp,
102 },
[150]103 "network": {
104 children: serviceCommandSet{
105 "create": {
106 usage: "-addr <addr> [-name name] [-username username] [-pass pass] [-realname realname] [-nick nick]",
107 desc: "add a new network",
108 handle: handleServiceCreateNetwork,
109 },
[151]110 "status": {
111 desc: "show a list of saved networks and their current status",
112 handle: handleServiceNetworkStatus,
113 },
[202]114 "delete": {
115 usage: "<name>",
116 desc: "delete a network",
117 handle: handleServiceNetworkDelete,
118 },
[150]119 },
[120]120 },
[117]121 }
122}
123
[150]124func appendServiceCommandSetHelp(cmds serviceCommandSet, prefix []string, l *[]string) {
125 for name, cmd := range cmds {
126 words := append(prefix, name)
127 if len(cmd.children) == 0 {
128 s := strings.Join(words, " ")
129 *l = append(*l, s)
130 } else {
131 appendServiceCommandSetHelp(cmd.children, words, l)
132 }
133 }
134}
135
[117]136func handleServiceHelp(dc *downstreamConn, params []string) error {
137 if len(params) > 0 {
[150]138 cmd, rest, err := serviceCommands.Get(params)
139 if err != nil {
140 return err
[117]141 }
[150]142 words := params[:len(params)-len(rest)]
[117]143
[150]144 if len(cmd.children) > 0 {
145 var l []string
146 appendServiceCommandSetHelp(cmd.children, words, &l)
147 sendServicePRIVMSG(dc, "available commands: "+strings.Join(l, ", "))
148 } else {
149 text := strings.Join(words, " ")
150 if cmd.usage != "" {
151 text += " " + cmd.usage
152 }
153 text += ": " + cmd.desc
154
155 sendServicePRIVMSG(dc, text)
[117]156 }
157 } else {
158 var l []string
[150]159 appendServiceCommandSetHelp(serviceCommands, nil, &l)
[117]160 sendServicePRIVMSG(dc, "available commands: "+strings.Join(l, ", "))
161 }
162 return nil
163}
[120]164
[202]165func newFlagSet() *flag.FlagSet {
[120]166 fs := flag.NewFlagSet("", flag.ContinueOnError)
167 fs.SetOutput(ioutil.Discard)
[202]168 return fs
169}
170
171func handleServiceCreateNetwork(dc *downstreamConn, params []string) error {
172 fs := newFlagSet()
[120]173 addr := fs.String("addr", "", "")
174 name := fs.String("name", "", "")
175 username := fs.String("username", "", "")
176 pass := fs.String("pass", "", "")
177 realname := fs.String("realname", "", "")
178 nick := fs.String("nick", "", "")
179
180 if err := fs.Parse(params); err != nil {
181 return err
182 }
183 if *addr == "" {
[150]184 return fmt.Errorf("flag -addr is required")
[120]185 }
186
187 if *nick == "" {
188 *nick = dc.nick
189 }
190
191 var err error
192 network, err := dc.user.createNetwork(&Network{
193 Addr: *addr,
194 Name: *name,
195 Username: *username,
196 Pass: *pass,
197 Realname: *realname,
198 Nick: *nick,
199 })
200 if err != nil {
201 return fmt.Errorf("could not create network: %v", err)
202 }
203
[202]204 sendServicePRIVMSG(dc, fmt.Sprintf("created network %q", network.GetName()))
[120]205 return nil
206}
[151]207
208func handleServiceNetworkStatus(dc *downstreamConn, params []string) error {
209 dc.user.forEachNetwork(func(net *network) {
210 var statuses []string
211 var details string
212 if uc := net.upstream(); uc != nil {
213 statuses = append(statuses, "connected as "+uc.nick)
214 details = fmt.Sprintf("%v channels", len(uc.channels))
215 } else {
216 statuses = append(statuses, "disconnected")
[219]217 if net.lastError != nil {
218 details = net.lastError.Error()
219 }
[151]220 }
221
222 if net == dc.network {
223 statuses = append(statuses, "current")
224 }
225
[224]226 name := net.GetName()
227 if name != net.Addr {
228 name = fmt.Sprintf("%v (%v)", name, net.Addr)
229 }
230
231 s := fmt.Sprintf("%v [%v]", name, strings.Join(statuses, ", "))
[151]232 if details != "" {
233 s += ": " + details
234 }
235 sendServicePRIVMSG(dc, s)
236 })
237 return nil
238}
[202]239
240func handleServiceNetworkDelete(dc *downstreamConn, params []string) error {
241 if len(params) != 1 {
242 return fmt.Errorf("expected exactly one argument")
243 }
244
245 net := dc.user.getNetwork(params[0])
246 if net == nil {
247 return fmt.Errorf("unknown network %q", params[0])
248 }
249
250 if err := dc.user.deleteNetwork(net.ID); err != nil {
251 return err
252 }
253
254 sendServicePRIVMSG(dc, fmt.Sprintf("deleted network %q", net.GetName()))
255 return nil
256}
Note: See TracBrowser for help on using the repository browser.