commit 57f1c0f3030b6472ddfb1eb98fe055129d7753b6
parent 9bc41991a84d7e5c9a0c3421504fad1db5cfdc32
Author: sin <sin@2f30.org>
Date: Thu, 2 May 2013 13:07:16 +0100
add better irc parsing
Diffstat:
5 files changed, 133 insertions(+), 113 deletions(-)
diff --git a/src/games/games.go b/src/games/games.go
@@ -47,11 +47,11 @@ func (s *hangmanState) String() string {
//to the state channel.
func hangmanInit(cs *hangmanState) {
for msg := range *cs.gchan {
- if msg.Cmd == "SETNICK" {
- cs.botname = msg.Params[0]
+ if msg.Command == "SETNICK" {
+ cs.botname = msg.Args[0]
}
- if msg.Cmd == "SETCHAN" {
- cs.channame = msg.Params[0]
+ if msg.Command == "SETCHAN" {
+ cs.channame = msg.Args[0]
}
if cs.botname != "" && cs.channame != "" {
break
@@ -65,11 +65,11 @@ func hangmanInit(cs *hangmanState) {
func hangmanWaitGoal(cs *hangmanState) {
cs.ictx.Privmsg(cs.channame, "Hangman is waiting for goal. When ready use hangman <letter|possibleword>")
for msg := range *cs.gchan {
- msg.Params[1] = strings.TrimSpace(msg.Params[1])
- if msg.Params[0] == cs.botname {
- if strings.HasPrefix(msg.Params[1], ":setgoal ") {
- cs.goal = msg.Params[1][9:]
- who := msg.Prefix[:strings.Index(msg.Prefix, "!")]
+ msg.Args[1] = strings.TrimSpace(msg.Args[1])
+ if msg.Args[0] == cs.botname {
+ if strings.HasPrefix(msg.Args[1], "setgoal ") {
+ cs.goal = msg.Args[1][8:]
+ who := msg.Nick
cs.ictx.Privmsg(who, "Goal is now set to: "+cs.goal)
runes := make([]rune, len(cs.goal))
for i := 0; i < len(runes); i++ {
@@ -78,12 +78,12 @@ func hangmanWaitGoal(cs *hangmanState) {
cs.foundnow = string(runes)
break
} else {
- who := msg.Prefix[:strings.Index(msg.Prefix, "!")]
+ who := msg.Nick
cs.ictx.Privmsg(who, "Now we are playing hangman. Use setgoal <WORD>")
}
} else {
- if strings.HasPrefix(msg.Params[1], ":hangman ") {
- cs.ictx.Privmsg(msg.Params[0], "Still waiting for goal...")
+ if strings.HasPrefix(msg.Args[1], "hangman ") {
+ cs.ictx.Privmsg(msg.Args[0], "Still waiting for goal...")
}
}
}
@@ -99,37 +99,37 @@ func hangmanWaitGoal(cs *hangmanState) {
func hangmanMainLoop(cs *hangmanState) {
cs.ictx.Privmsg(cs.channame, cs.String())
for msg := range *cs.gchan {
- msg.Params[1] = strings.TrimSpace(msg.Params[1])
- if msg.Params[0] != cs.botname {
+ msg.Args[1] = strings.TrimSpace(msg.Args[1])
+ if msg.Args[0] != cs.botname {
if cs.lives < 1 {
- cs.ictx.Privmsg(msg.Params[0], "You are hanged! Goal was ->"+cs.goal)
+ cs.ictx.Privmsg(msg.Args[0], "You are hanged! Goal was ->"+cs.goal)
*cs.statchan <- hangmanEnd
}
- if strings.HasPrefix(msg.Params[1], ":hangman ") {
- in := msg.Params[1][9:]
+ if strings.HasPrefix(msg.Args[1], "hangman ") {
+ in := msg.Args[1][8:]
if len(in) > 1 {
if in == cs.goal {
- cs.ictx.Privmsg(msg.Params[0], "You won!")
+ cs.ictx.Privmsg(msg.Args[0], "You won!")
*cs.statchan <- hangmanEnd
} else {
- cs.ictx.Privmsg(msg.Params[0], "You lost a life punk...")
+ cs.ictx.Privmsg(msg.Args[0], "You lost a life punk...")
cs.lives -= 1
- cs.ictx.Privmsg(msg.Params[0], cs.String())
+ cs.ictx.Privmsg(msg.Args[0], cs.String())
continue
}
} else {
if strings.Index(cs.tried, string(in[0])) != -1 {
- cs.ictx.Privmsg(msg.Params[0], "I heard you the first time")
+ cs.ictx.Privmsg(msg.Args[0], "I heard you the first time")
continue
}
hm := cs.checkLetter([]rune(in)[0])
- cs.ictx.Privmsg(msg.Params[0], fmt.Sprintf("You got %d letters", hm))
+ cs.ictx.Privmsg(msg.Args[0], fmt.Sprintf("You got %d letters", hm))
if hm == 0 {
cs.lives -= 1
}
- cs.ictx.Privmsg(msg.Params[0], cs.String())
+ cs.ictx.Privmsg(msg.Args[0], cs.String())
if cs.foundnow == cs.goal {
- cs.ictx.Privmsg(msg.Params[0], "You won!")
+ cs.ictx.Privmsg(msg.Args[0], "You won!")
*cs.statchan <- hangmanEnd
}
}
diff --git a/src/irc/events.go b/src/irc/events.go
@@ -5,8 +5,8 @@ const (
)
type IrcEvent struct {
- Cmd string
- Fn func(IrcMessage)
+ Command string
+ Fn func(IrcMessage)
}
func (i *IrcContext) AddEventHandler(ev IrcEvent) int {
diff --git a/src/irc/irc.go b/src/irc/irc.go
@@ -155,8 +155,6 @@ func (i *IrcContext) read(buf []byte) (int, error) {
// This is the actual raw read loop. Here we parse the incoming bytes
// and form messages.
func (i *IrcContext) rxLoop() error {
- var msg IrcMessage
- var cmdpos, lastddot int
for {
var buf [512]byte
@@ -167,8 +165,6 @@ func (i *IrcContext) rxLoop() error {
fmt.Println(string(buf[0 : n-1]))
s := string(buf[0:n])
- // Handle this here, no need to create
- // a message for it
if strings.HasPrefix(s, "PING :") {
r := strings.Replace(s, "PING :", "PONG :", 6)
r = r + "\r\n"
@@ -179,19 +175,10 @@ func (i *IrcContext) rxLoop() error {
continue
}
- // At the moment - handle only PRIVMSG
- cmdpos = strings.Index(s, "PRIVMSG ") // the space is needed for discarding init msgs.
- if cmdpos != -1 {
- //XXX this is too fragile but soon le parser will save us.
- msg.Prefix = s[1 : cmdpos-1] //discard the first :
- lastddot = strings.Index(s[1:], ":")
- msg.Cmd = "PRIVMSG"
- msg.Params = []string{s[cmdpos+8 : lastddot],
- s[lastddot+1:]}
- i.incomingMsg <- msg
- for _, v := range i.intercepts {
- *v <- msg
- }
+ msg := i.ParseRawMessage(s)
+ i.incomingMsg <- msg
+ for _, v := range i.intercepts {
+ *v <- msg
}
}
return nil
diff --git a/src/irc/message.go b/src/irc/message.go
@@ -1,17 +1,22 @@
package irc
+import "strings"
+
type IrcMessage struct {
- Prefix string // prefix part of the message
- Cmd string // the actual command
- Params []string // the tokenized parameters
+ Command string
+ Raw string
+ Nick string
+ Host string
+ Source string
+ User string
+ Args []string
}
// Send the nickname
func (i *IrcContext) Nick() {
msg := IrcMessage{
- Prefix: "",
- Cmd: "NICK",
- Params: []string{i.network.nick},
+ Command: "NICK",
+ Args: []string{i.network.nick},
}
i.outgoingMsg <- msg
}
@@ -19,9 +24,8 @@ func (i *IrcContext) Nick() {
// Send the username
func (i *IrcContext) User() {
msg := IrcMessage{
- Prefix: "",
- Cmd: "USER",
- Params: []string{
+ Command: "USER",
+ Args: []string{
i.network.user,
"* 8",
":" + i.network.nick,
@@ -33,9 +37,8 @@ func (i *IrcContext) User() {
// Join a channel
func (i *IrcContext) Join(channel string) {
msg := IrcMessage{
- Prefix: "",
- Cmd: "JOIN",
- Params: []string{channel},
+ Command: "JOIN",
+ Args: []string{channel},
}
i.outgoingMsg <- msg
}
@@ -43,9 +46,8 @@ func (i *IrcContext) Join(channel string) {
// Send a PRIVMSG
func (i *IrcContext) Privmsg(channel string, text string) {
msg := IrcMessage{
- Prefix: "",
- Cmd: "PRIVMSG",
- Params: []string{
+ Command: "PRIVMSG",
+ Args: []string{
channel,
":" + text,
},
@@ -53,11 +55,47 @@ func (i *IrcContext) Privmsg(channel string, text string) {
i.outgoingMsg <- msg
}
+func (i *IrcContext) ParseRawMessage(raw string) IrcMessage {
+ var msg IrcMessage
+ msg.Raw = raw
+ if raw[0] == ':' {
+ if i := strings.Index(raw, " "); i != -1 {
+ msg.Source = raw[1:i]
+ raw = raw[1:]
+ }
+ if i := strings.Index(raw, "!"); i != -1 {
+ msg.Nick = raw[:i]
+ raw = raw[i+1:]
+ }
+ if i := strings.Index(raw, "@"); i != -1 {
+ msg.User = raw[:i]
+ raw = raw[i+1:]
+ }
+ if i := strings.Index(raw, " "); i != -1 {
+ msg.Host = raw[:i]
+ raw = raw[i+1:]
+ }
+ }
+ if i := strings.Index(raw, " "); i != -1 {
+ msg.Command = raw[:i]
+ raw = raw[i+1:]
+ }
+ if raw[0] == ':' {
+ msg.Args = []string{raw[1:]}
+ } else {
+ args := strings.SplitN(raw, " :", 2)
+ if len(args) == 2 {
+ msg.Args = []string{args[0], args[1]}
+ }
+ }
+ return msg
+}
+
// Unpack a message into a byte array
func (i *IrcContext) UnpackMessage(msg IrcMessage) ([]byte, error) {
// No Prefix crap for TX paths
- rawMsg := msg.Cmd + " "
- for _, v := range msg.Params {
+ rawMsg := msg.Command + " "
+ for _, v := range msg.Args {
rawMsg += v + " "
}
rawMsg = rawMsg[:len(rawMsg)-1] + "\r\n"
@@ -83,7 +121,7 @@ func (i *IrcContext) incomingMsgLoop() error {
// Check if the user has registered
// a callback for this message
for _, v := range i.ev {
- if v.Cmd == msg.Cmd {
+ if v.Command == msg.Command {
v.Fn(msg)
break
}
diff --git a/src/kunt/kunt.go b/src/kunt/kunt.go
@@ -51,7 +51,7 @@ func cmdKunt(msg irc.IrcMessage) {
"no fucking way",
}
idx := rand.Intn(len(actions))
- kunt.ircCtx.Privmsg(msg.Params[0], string(actions[idx]))
+ kunt.ircCtx.Privmsg(msg.Args[0], string(actions[idx]))
}
func cmdWisdom(msg irc.IrcMessage) {
@@ -64,7 +64,7 @@ func cmdWisdom(msg irc.IrcMessage) {
if i == "" {
continue
}
- kunt.ircCtx.Privmsg(msg.Params[0], i)
+ kunt.ircCtx.Privmsg(msg.Args[0], i)
time.Sleep(512 * time.Millisecond)
}
}
@@ -86,19 +86,19 @@ func cmdHelp(msg irc.IrcMessage) {
"!version -> Show version",
}
for _, i := range help {
- kunt.ircCtx.Privmsg(msg.Params[0], i)
+ kunt.ircCtx.Privmsg(msg.Args[0], i)
time.Sleep(512 * time.Millisecond)
}
}
func cmdVersion(msg irc.IrcMessage) {
ver := "v0.2.8"
- kunt.ircCtx.Privmsg(msg.Params[0], ver)
+ kunt.ircCtx.Privmsg(msg.Args[0], ver)
}
func cmdRandQuote(msg irc.IrcMessage) {
if quoteDb.Empty() {
- kunt.ircCtx.Privmsg(msg.Params[0], "Empty quote database")
+ kunt.ircCtx.Privmsg(msg.Args[0], "Empty quote database")
return
}
quote, idx := quoteDb.Rand()
@@ -106,28 +106,27 @@ func cmdRandQuote(msg irc.IrcMessage) {
// Print idx in red
text := fmt.Sprintf("%s%02d[%d]%s %s",
"\003", '5', idx, "\003", string(quote))
- kunt.ircCtx.Privmsg(msg.Params[0], text)
+ kunt.ircCtx.Privmsg(msg.Args[0], text)
}
func cmdAddQuote(msg irc.IrcMessage) {
- s := msg.Params[1]
- hm := strings.Fields(s)
- if len(hm) < 2 {
- kunt.ircCtx.Privmsg(msg.Params[0], "Missing parameter for !addquote")
+ text := msg.Args[1]
+ if len(strings.Fields(text)) < 2 {
+ kunt.ircCtx.Privmsg(msg.Args[0], "Missing parameter for !addquote")
return
}
- s = s[11:]
- s = strings.TrimSpace(s)
- s += "\n"
- buf := []byte(s)
+ text = text[10:]
+ text = strings.TrimSpace(text)
+ text += "\n"
+ buf := []byte(text)
if quoteDb.CountMatches(buf) > 0 {
- kunt.ircCtx.Privmsg(msg.Params[0],
+ kunt.ircCtx.Privmsg(msg.Args[0],
fmt.Errorf("Duplicate entry: %s", buf).Error())
return
}
_, err := quoteDb.Append(buf)
if err != nil {
- kunt.ircCtx.Privmsg(msg.Params[0], err.Error())
+ kunt.ircCtx.Privmsg(msg.Args[0], err.Error())
return
}
err = quoteDb.Sync()
@@ -138,12 +137,12 @@ func cmdAddQuote(msg irc.IrcMessage) {
func cmdCountQuotes(msg irc.IrcMessage) {
text := fmt.Sprintf("The quote DB has %d quotes", quoteDb.Size())
- kunt.ircCtx.Privmsg(msg.Params[0], text)
+ kunt.ircCtx.Privmsg(msg.Args[0], text)
}
func cmdRandUrl(msg irc.IrcMessage) {
if urlDb.Empty() {
- kunt.ircCtx.Privmsg(msg.Params[0], "Empty url database")
+ kunt.ircCtx.Privmsg(msg.Args[0], "Empty url database")
return
}
url, idx := urlDb.Rand()
@@ -151,33 +150,32 @@ func cmdRandUrl(msg irc.IrcMessage) {
// Print idx in red
r := fmt.Sprintf("%s%02d[%d]%s %s",
"\003", '5', idx, "\003", string(url))
- kunt.ircCtx.Privmsg(msg.Params[0], r)
+ kunt.ircCtx.Privmsg(msg.Args[0], r)
title, ok := resolveYoutubeTitle(string(url))
if ok {
r = fmt.Sprintf("[YouTube] %s", title)
- kunt.ircCtx.Privmsg(msg.Params[0], r)
+ kunt.ircCtx.Privmsg(msg.Args[0], r)
}
}
func cmdAddUrl(msg irc.IrcMessage) {
- s := msg.Params[1]
- as := strings.Fields(s)
- if len(as) < 2 {
- kunt.ircCtx.Privmsg(msg.Params[0], "Missing parameter for !addurl")
+ text := msg.Args[1]
+ if len(strings.Fields(text)) < 2 {
+ kunt.ircCtx.Privmsg(msg.Args[0], "Missing parameter for !addurl")
return
}
- s = s[9:]
- s = strings.TrimSpace(s)
- s += "\n"
- buf := []byte(s)
+ text = text[8:]
+ text = strings.TrimSpace(text)
+ text += "\n"
+ buf := []byte(text)
if urlDb.CountMatches(buf) > 0 {
- kunt.ircCtx.Privmsg(msg.Params[0],
+ kunt.ircCtx.Privmsg(msg.Args[0],
fmt.Errorf("Duplicate entry: %s", buf).Error())
return
}
_, err := urlDb.Append(buf)
if err != nil {
- kunt.ircCtx.Privmsg(msg.Params[0], err.Error())
+ kunt.ircCtx.Privmsg(msg.Args[0], err.Error())
return
}
err = urlDb.Sync()
@@ -188,38 +186,38 @@ func cmdAddUrl(msg irc.IrcMessage) {
func cmdCountUrls(msg irc.IrcMessage) {
r := fmt.Sprintf("The url DB has %d urls", urlDb.Size())
- kunt.ircCtx.Privmsg(msg.Params[0], r)
+ kunt.ircCtx.Privmsg(msg.Args[0], r)
}
func cmdRadio(msg irc.IrcMessage) {
np, e := http.Get("http://radio.2f30.org:8000/npsong.xsl")
if e != nil {
- kunt.ircCtx.Privmsg(msg.Params[0], "Is radio broken?")
+ kunt.ircCtx.Privmsg(msg.Args[0], "Is radio broken?")
} else {
defer np.Body.Close()
song, _ := ioutil.ReadAll(np.Body)
r := fmt.Sprintf("[Radio] %s", song)
- kunt.ircCtx.Privmsg(msg.Params[0], r)
+ kunt.ircCtx.Privmsg(msg.Args[0], r)
r = "[Radio] http://radio.2f30.org:8000/live.ogg"
- kunt.ircCtx.Privmsg(msg.Params[0], r)
+ kunt.ircCtx.Privmsg(msg.Args[0], r)
}
}
func cmdUptime(msg irc.IrcMessage) {
etime := time.Now()
r := fmt.Sprintf("%v", etime.Sub(kunt.stime))
- kunt.ircCtx.Privmsg(msg.Params[0], r)
+ kunt.ircCtx.Privmsg(msg.Args[0], r)
}
func cmdSrc(msg irc.IrcMessage) {
src := "http://amnezia.2f30.org/tmp/kunt-latest.tgz"
- kunt.ircCtx.Privmsg(msg.Params[0], src)
+ kunt.ircCtx.Privmsg(msg.Args[0], src)
}
func cmdTodo(msg irc.IrcMessage) {
todo, err := ioutil.ReadFile("TODO")
if err != nil {
- kunt.ircCtx.Privmsg(msg.Params[0], "No TODO list available")
+ kunt.ircCtx.Privmsg(msg.Args[0], "No TODO list available")
return
}
sf := strings.FieldsFunc(string(todo), func(r rune) bool {
@@ -230,32 +228,31 @@ func cmdTodo(msg irc.IrcMessage) {
return false
})
for _, v := range sf {
- kunt.ircCtx.Privmsg(msg.Params[0], v)
+ kunt.ircCtx.Privmsg(msg.Args[0], v)
time.Sleep(512 * time.Millisecond)
}
}
func cmdGame(msg irc.IrcMessage) {
- s := msg.Params[1]
- as := strings.Fields(s)
- if len(as) < 2 {
- kunt.ircCtx.Privmsg(msg.Params[0], "Missing parameter for !game")
+ text := msg.Args[1]
+ if len(strings.Fields(text)) < 2 {
+ kunt.ircCtx.Privmsg(msg.Args[0], "Missing parameter for !game")
return
}
- s = s[6:]
- s = strings.TrimSpace(s)
- switch s {
+ text = text[5:]
+ text = strings.TrimSpace(text)
+ switch text {
case "list":
for _, str := range geng.List() {
- kunt.ircCtx.Privmsg(msg.Params[0], "[game] "+str)
+ kunt.ircCtx.Privmsg(msg.Args[0], "[game] "+str)
}
return
}
gchan := make(chan irc.IrcMessage)
- geng.New(s, kunt.ircCtx, &gchan)
+ geng.New(text, kunt.ircCtx, &gchan)
time.Sleep(512 * time.Millisecond)
- gchan <- irc.IrcMessage{Prefix: "", Cmd: "SETNICK", Params: []string{botname}} //Let the game engine know.
- gchan <- irc.IrcMessage{Prefix: "", Cmd: "SETCHAN", Params: []string{msg.Params[0]}}
+ gchan <- irc.IrcMessage{Command: "SETNICK", Args: []string{botname}} //Let the game engine know.
+ gchan <- irc.IrcMessage{Command: "SETCHAN", Args: []string{msg.Args[0]}}
}
var sslon = flag.Bool("s", false, "SSL support")
@@ -349,9 +346,7 @@ func main() {
kunt.ircCtx = irc.NewIrcContext(cfg)
kunt.ircCtx.AddEventHandler(irc.IrcEvent{"PRIVMSG", func(msg irc.IrcMessage) {
- cmd := msg.Params[1]
- // Strip the leading ':'
- cmd = cmd[1:]
+ cmd := msg.Args[1]
for i, v := range dispatch {
if strings.HasPrefix(cmd, i) {
go v(msg)