source: code/trunk/service.go@ 155

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

Add a "network status" command

File size: 4.8 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
[150]15type serviceCommandSet map[string]*serviceCommand
16
[117]17type serviceCommand struct {
[150]18 usage string
19 desc string
20 handle func(dc *downstreamConn, params []string) error
21 children serviceCommandSet
[117]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
[150]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))
[117]42 return
43 }
44
45 if err := cmd.handle(dc, params); err != nil {
46 sendServicePRIVMSG(dc, fmt.Sprintf("error: %v", err))
47 }
48}
49
[150]50func (cmds serviceCommandSet) Get(params []string) (*serviceCommand, []string, error) {
51 if len(params) == 0 {
52 return nil, nil, fmt.Errorf("no command specified")
53 }
[117]54
[150]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
[117]82func init() {
[150]83 serviceCommands = serviceCommandSet{
[117]84 "help": {
85 usage: "[command]",
86 desc: "print help message",
87 handle: handleServiceHelp,
88 },
[150]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 },
[151]96 "status": {
97 desc: "show a list of saved networks and their current status",
98 handle: handleServiceNetworkStatus,
99 },
[150]100 },
[120]101 },
[117]102 }
103}
104
[150]105func appendServiceCommandSetHelp(cmds serviceCommandSet, prefix []string, l *[]string) {
106 for name, cmd := range cmds {
107 words := append(prefix, name)
108 if len(cmd.children) == 0 {
109 s := strings.Join(words, " ")
110 *l = append(*l, s)
111 } else {
112 appendServiceCommandSetHelp(cmd.children, words, l)
113 }
114 }
115}
116
[117]117func handleServiceHelp(dc *downstreamConn, params []string) error {
118 if len(params) > 0 {
[150]119 cmd, rest, err := serviceCommands.Get(params)
120 if err != nil {
121 return err
[117]122 }
[150]123 words := params[:len(params)-len(rest)]
[117]124
[150]125 if len(cmd.children) > 0 {
126 var l []string
127 appendServiceCommandSetHelp(cmd.children, words, &l)
128 sendServicePRIVMSG(dc, "available commands: "+strings.Join(l, ", "))
129 } else {
130 text := strings.Join(words, " ")
131 if cmd.usage != "" {
132 text += " " + cmd.usage
133 }
134 text += ": " + cmd.desc
135
136 sendServicePRIVMSG(dc, text)
[117]137 }
138 } else {
139 var l []string
[150]140 appendServiceCommandSetHelp(serviceCommands, nil, &l)
[117]141 sendServicePRIVMSG(dc, "available commands: "+strings.Join(l, ", "))
142 }
143 return nil
144}
[120]145
146func handleServiceCreateNetwork(dc *downstreamConn, params []string) error {
147 fs := flag.NewFlagSet("", flag.ContinueOnError)
148 fs.SetOutput(ioutil.Discard)
149 addr := fs.String("addr", "", "")
150 name := fs.String("name", "", "")
151 username := fs.String("username", "", "")
152 pass := fs.String("pass", "", "")
153 realname := fs.String("realname", "", "")
154 nick := fs.String("nick", "", "")
155
156 if err := fs.Parse(params); err != nil {
157 return err
158 }
159 if *addr == "" {
[150]160 return fmt.Errorf("flag -addr is required")
[120]161 }
162
163 if *nick == "" {
164 *nick = dc.nick
165 }
166
167 var err error
168 network, err := dc.user.createNetwork(&Network{
169 Addr: *addr,
170 Name: *name,
171 Username: *username,
172 Pass: *pass,
173 Realname: *realname,
174 Nick: *nick,
175 })
176 if err != nil {
177 return fmt.Errorf("could not create network: %v", err)
178 }
179
180 sendServicePRIVMSG(dc, fmt.Sprintf("created network %s successfully", network.GetName()))
181 return nil
182}
[151]183
184func handleServiceNetworkStatus(dc *downstreamConn, params []string) error {
185 dc.user.forEachNetwork(func(net *network) {
186 var statuses []string
187 var details string
188 if uc := net.upstream(); uc != nil {
189 statuses = append(statuses, "connected as "+uc.nick)
190 details = fmt.Sprintf("%v channels", len(uc.channels))
191 } else {
192 statuses = append(statuses, "disconnected")
193 }
194
195 if net == dc.network {
196 statuses = append(statuses, "current")
197 }
198
199 s := fmt.Sprintf("%v (%v) [%v]", net.GetName(), net.Addr, strings.Join(statuses, ", "))
200 if details != "" {
201 s += ": " + details
202 }
203 sendServicePRIVMSG(dc, s)
204 })
205 return nil
206}
Note: See TracBrowser for help on using the repository browser.