Forward irc errors to the client, improve command validation and feedback, handle topic changes

This commit is contained in:
Ken-Håvard Lieng 2017-05-28 07:20:43 +02:00
parent 993d29242e
commit aa59e71745
17 changed files with 328 additions and 96 deletions

View file

@ -3,6 +3,7 @@ package server
import (
"log"
"strings"
"unicode"
"github.com/kjk/betterguid"
@ -52,6 +53,10 @@ func (i *ircHandler) run() {
}
func (i *ircHandler) dispatchMessage(msg *irc.Message) {
if msg.Command[0] == '4' {
i.session.printError(formatIRCError(msg))
}
if handler, ok := i.handlers[msg.Command]; ok {
handler(msg)
}
@ -78,14 +83,18 @@ func (i *ircHandler) join(msg *irc.Message) {
Channels: msg.Params,
})
channelStore.AddUser(msg.Nick, i.client.Host, msg.Params[0])
channel := msg.Params[0]
channelStore.AddUser(msg.Nick, i.client.Host, channel)
if msg.Nick == i.client.GetNick() {
i.session.sendLastMessages(i.client.Host, msg.Params[0], 50)
// Incase no topic is set and theres a cached one that needs to be cleared
i.client.Topic(channel)
i.session.sendLastMessages(i.client.Host, channel, 50)
go i.session.user.AddChannel(storage.Channel{
Server: i.client.Host,
Name: msg.Params[0],
Name: channel,
})
}
}
@ -193,13 +202,35 @@ func (i *ircHandler) whoisEnd(msg *irc.Message) {
}
func (i *ircHandler) topic(msg *irc.Message) {
var channel string
var nick string
if msg.Command == irc.Topic {
channel = msg.Params[0]
nick = msg.Nick
} else {
channel = msg.Params[1]
}
i.session.sendJSON("topic", Topic{
Server: i.client.Host,
Channel: msg.Params[1],
Channel: channel,
Topic: msg.LastParam(),
Nick: nick,
})
channelStore.SetTopic(msg.LastParam(), i.client.Host, msg.Params[1])
channelStore.SetTopic(msg.LastParam(), i.client.Host, channel)
}
func (i *ircHandler) noTopic(msg *irc.Message) {
channel := msg.Params[1]
i.session.sendJSON("topic", Topic{
Server: i.client.Host,
Channel: channel,
})
channelStore.SetTopic("", i.client.Host, channel)
}
func (i *ircHandler) names(msg *irc.Message) {
@ -245,6 +276,7 @@ func (i *ircHandler) initHandlers() {
irc.Privmsg: i.message,
irc.Notice: i.message,
irc.Quit: i.quit,
irc.Topic: i.topic,
irc.ReplyWelcome: i.info,
irc.ReplyYourHost: i.info,
irc.ReplyCreated: i.info,
@ -257,6 +289,7 @@ func (i *ircHandler) initHandlers() {
irc.ReplyWhoisServer: i.whoisServer,
irc.ReplyWhoisChannels: i.whoisChannels,
irc.ReplyEndOfWhois: i.whoisEnd,
irc.ReplyNoTopic: i.noTopic,
irc.ReplyTopic: i.topic,
irc.ReplyNamReply: i.names,
irc.ReplyEndOfNames: i.namesEnd,
@ -289,6 +322,19 @@ func isChannel(s string) bool {
return strings.IndexAny(s, "&#+!") == 0
}
func formatIRCError(msg *irc.Message) string {
errMsg := strings.TrimSuffix(msg.LastParam(), ".")
if len(msg.Params) > 2 {
for _, c := range msg.LastParam() {
if unicode.IsLower(c) {
return msg.Params[1] + " " + errMsg
}
return msg.Params[1] + ": " + errMsg
}
}
return errMsg
}
func printMessage(msg *irc.Message, i *irc.Client) {
log.Println(i.GetNick()+":", msg.Prefix, msg.Command, msg.Params, msg.LastParam())
}

View file

@ -225,6 +225,31 @@ func TestHandleIRCTopic(t *testing.T) {
Channel: "#chan",
Topic: "the topic",
}, res)
res = dispatchMessage(&irc.Message{
Command: irc.Topic,
Params: []string{"#chan", "the topic"},
Nick: "bob",
})
checkResponse(t, "topic", Topic{
Server: "host.com",
Channel: "#chan",
Topic: "the topic",
Nick: "bob",
}, res)
}
func TestHandleIRCNoTopic(t *testing.T) {
res := dispatchMessage(&irc.Message{
Command: irc.ReplyNoTopic,
Params: []string{"target", "#chan", "No topic set."},
})
checkResponse(t, "topic", Topic{
Server: "host.com",
Channel: "#chan",
}, res)
}
func TestHandleIRCNames(t *testing.T) {

View file

@ -61,11 +61,12 @@ type Quit struct {
}
type Message struct {
ID string `json:"id"`
Server string `json:"server"`
ID string `json:"id,omitempty"`
Server string `json:"server,omitempty"`
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
Content string `json:"content"`
Type string `json:"type,omitempty"`
}
type Messages struct {
@ -79,7 +80,8 @@ type Messages struct {
type Topic struct {
Server string `json:"server"`
Channel string `json:"channel"`
Topic string `json:"topic"`
Topic string `json:"topic,omitempty"`
Nick string `json:"nick,omitempty"`
}
type Userlist struct {

View file

@ -162,13 +162,19 @@ func (s *Session) sendMessages(server, channel string, count int, fromID string)
}
}
func (s *Session) print(server string, a ...interface{}) {
func (s *Session) print(a ...interface{}) {
s.sendJSON("print", Message{
Server: server,
Content: fmt.Sprintln(a...),
})
}
func (s *Session) printError(a ...interface{}) {
s.sendJSON("print", Message{
Content: fmt.Sprintln(a...),
Type: "error",
})
}
func (s *Session) resetExpirationIfEmpty() {
if s.numIRC() == 0 && s.numWS() == 0 {
s.reset <- AnonymousSessionExpiration

View file

@ -190,6 +190,15 @@ func (h *wsHandler) nick(b []byte) {
}
}
func (h *wsHandler) topic(b []byte) {
var data Topic
json.Unmarshal(b, &data)
if i, ok := h.session.getIRC(data.Server); ok {
i.Topic(data.Channel, data.Topic)
}
}
func (h *wsHandler) invite(b []byte) {
var data Invite
json.Unmarshal(b, &data)
@ -282,6 +291,7 @@ func (h *wsHandler) initHandlers() {
"quit": h.quit,
"message": h.message,
"nick": h.nick,
"topic": h.topic,
"invite": h.invite,
"kick": h.kick,
"whois": h.whois,