verbose support, WHO support, global messages in blessed channel, prevent leaving blessed channel
--HG-- branch : nmdc-ircfrontend
This commit is contained in:
parent
2c84934ab8
commit
479fbf104b
15
TODO.txt
15
TODO.txt
@ -4,10 +4,10 @@ PRE-RELEASE
|
||||
|
||||
- nick list
|
||||
|
||||
- expose unprefixed system messages in chat channel
|
||||
|
||||
- part all nicks on server disconnection
|
||||
|
||||
- test the current password auth
|
||||
|
||||
|
||||
WISHLIST
|
||||
========
|
||||
@ -20,10 +20,19 @@ WISHLIST
|
||||
|
||||
- expose upstream op status
|
||||
|
||||
- support WHO, WHOIS, USERIP/KILL/KICK (if opped)
|
||||
- support WHO
|
||||
|
||||
- support WHOIS
|
||||
|
||||
- support USERIP/KILL/KICK for ops
|
||||
|
||||
- use CTCP chat to support irc-special characters in chat messages (colon, newline)
|
||||
|
||||
- respond to CAP LS 302 (hexchat) in some way that'll kick us into a modern protocol mode
|
||||
|
||||
- support SASL PLAIN authentication as well as just classic PASS
|
||||
|
||||
- threadsafe access to libnmdc hub options
|
||||
|
||||
|
||||
|
||||
|
11
main.go
11
main.go
@ -25,14 +25,12 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
ircAddress = flag.String("bind", ":6697", "The address:port to bind to and listen for clients on")
|
||||
dcAddress = flag.String("upstream", "127.0.0.1:411", "Upstream NMDC server")
|
||||
serverName = flag.String("servername", "nmdc-ircfrontend", "Server name displayed to clients")
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
ircAddress := flag.String("bind", ":6697", "The address:port to bind to and listen for clients on")
|
||||
dcAddress := flag.String("upstream", "127.0.0.1:411", "Upstream NMDC server")
|
||||
serverName := flag.String("servername", "nmdc-ircfrontend", "Server name displayed to clients")
|
||||
verbose := flag.Bool("verbose", false, "Display debugging information")
|
||||
flag.Parse()
|
||||
|
||||
log.Printf("Listening on '%s'...", *ircAddress)
|
||||
@ -52,6 +50,7 @@ func main() {
|
||||
|
||||
// Spin up a worker for the new user.
|
||||
server := NewServer(*serverName, libnmdc.HubAddress(*dcAddress), conn)
|
||||
server.verbose = *verbose
|
||||
go server.RunWorker()
|
||||
}
|
||||
}
|
||||
|
72
server.go
72
server.go
@ -40,6 +40,8 @@ type Server struct {
|
||||
upstreamCloser chan struct{}
|
||||
upstream *libnmdc.HubConnection
|
||||
|
||||
verbose bool
|
||||
|
||||
lastMessage string // FIXME racey
|
||||
}
|
||||
|
||||
@ -59,6 +61,18 @@ func NewServer(name string, upstream libnmdc.HubAddress, conn net.Conn) *Server
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) verboseln(line string) {
|
||||
if s.verbose {
|
||||
log.Println(line)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) verbosef(fmt string, args ...interface{}) {
|
||||
if s.verbose {
|
||||
log.Printf(fmt, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RunWorker() {
|
||||
|
||||
// Send the connection handshake.
|
||||
@ -72,13 +86,12 @@ func (s *Server) RunWorker() {
|
||||
|
||||
buf := make([]byte, CLIENT_READ_BUFFSIZE)
|
||||
|
||||
//s.clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))
|
||||
ln, err := s.clientConn.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break // abandon thread
|
||||
}
|
||||
//log.Println(err.Error())
|
||||
s.verboseln(err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
@ -104,7 +117,7 @@ func (s *Server) RunWorker() {
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Broken loop.")
|
||||
s.verboseln("Broken loop.")
|
||||
|
||||
// Cleanup upstream
|
||||
if s.clientRegistered {
|
||||
@ -123,7 +136,7 @@ func (s *Server) upstreamWorker() {
|
||||
select {
|
||||
case <-s.upstreamCloser:
|
||||
// Abandon the upstream connection
|
||||
log.Println("Abandoning upstream connection...")
|
||||
s.verboseln("Abandoning upstream connection...")
|
||||
s.upstream.Disconnect()
|
||||
return
|
||||
|
||||
@ -155,7 +168,7 @@ func (s *Server) upstreamWorker() {
|
||||
}
|
||||
|
||||
case libnmdc.EVENT_SYSTEM_MESSAGE_FROM_CONN, libnmdc.EVENT_SYSTEM_MESSAGE_FROM_HUB:
|
||||
s.reply(rplMsg, BLESSED_CHANNEL, BLESSED_CHANNEL, hubEvent.Message) // experimental
|
||||
s.reply(rplMsg, "", BLESSED_CHANNEL, hubEvent.Message) // experimental
|
||||
// s.sendClientGlobalMessage(hubEvent.Message)
|
||||
|
||||
}
|
||||
@ -165,6 +178,8 @@ func (s *Server) upstreamWorker() {
|
||||
|
||||
func (s *Server) handleCommand(command string, args []string) {
|
||||
|
||||
s.verbosef(" >>> '%s' %v", command, args)
|
||||
|
||||
switch command {
|
||||
case "PING":
|
||||
s.reply(rplPong)
|
||||
@ -261,7 +276,15 @@ func (s *Server) handleRegisteredCommand(command string, args []string) {
|
||||
}
|
||||
|
||||
case "PART":
|
||||
// You can check out any time you like, but you can never leave
|
||||
if len(args) < 1 {
|
||||
s.reply(errMoreArgs)
|
||||
return
|
||||
}
|
||||
|
||||
if args[0] == BLESSED_CHANNEL {
|
||||
// You can check out any time you like, but you can never leave
|
||||
s.reply(rplJoin, s.upstreamLauncher.Self.Nick, BLESSED_CHANNEL)
|
||||
}
|
||||
|
||||
case "PRIVMSG":
|
||||
if len(args) < 2 {
|
||||
@ -325,18 +348,34 @@ func (s *Server) handleRegisteredCommand(command string, args []string) {
|
||||
// Can't use this command.
|
||||
s.reply(errPassword)
|
||||
|
||||
case "KILL":
|
||||
case "KILL", "KICK":
|
||||
s.reply(errNoPriv)
|
||||
return
|
||||
|
||||
case "KICK":
|
||||
if s.clientRegistered == false {
|
||||
s.reply(errNotReg)
|
||||
case "WHO":
|
||||
if len(args) < 1 {
|
||||
s.reply(errMoreArgs)
|
||||
return
|
||||
}
|
||||
|
||||
s.reply(errNoPriv)
|
||||
return
|
||||
if args[0] == BLESSED_CHANNEL {
|
||||
// always include ourselves
|
||||
s.reply(rplWho, s.upstreamLauncher.Self.Nick)
|
||||
|
||||
for nick, _ := range s.upstream.Users {
|
||||
if nick != s.upstreamLauncher.Self.Nick { // but don't repeat ourselves
|
||||
s.reply(rplWho, nick)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// argument is a filter
|
||||
for nick, _ := range s.upstream.Users {
|
||||
if strings.Contains(nick, args[0]) {
|
||||
s.reply(rplWho, nick)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.reply(rplEndOfWho)
|
||||
|
||||
case "MODE":
|
||||
if len(args) < 1 {
|
||||
@ -409,10 +448,17 @@ func (s *Server) reply(code replyCode, args ...string) {
|
||||
s.writeClient(fmt.Sprintf(":%s 332 %s %s :%s", s.name, s.upstreamLauncher.Self.Nick, args[0], args[1]))
|
||||
case rplNoTopic:
|
||||
s.writeClient(fmt.Sprintf(":%s 331 %s %s :No topic is set", s.name, s.upstreamLauncher.Self.Nick, args[0]))
|
||||
|
||||
case rplNames:
|
||||
s.writeClient(fmt.Sprintf(":%s 353 %s = %s :%s", s.name, s.upstreamLauncher.Self.Nick, args[0], args[1]))
|
||||
case rplEndOfNames:
|
||||
s.writeClient(fmt.Sprintf(":%s 366 %s %s :End of NAMES list", s.name, s.upstreamLauncher.Self.Nick, args[0]))
|
||||
|
||||
case rplWho:
|
||||
s.writeClient(fmt.Sprintf(":%s 352 %s %s %s %s %s %s H :0 %s", s.name, s.upstreamLauncher.Self.Nick, BLESSED_CHANNEL, args[0], args[0], s.name, args[0], args[0]))
|
||||
case rplEndOfWho:
|
||||
s.writeClient(fmt.Sprintf(":%s 315 :End of WHO list", s.name))
|
||||
|
||||
case rplNickChange:
|
||||
s.writeClient(fmt.Sprintf(":%s NICK %s", args[0], args[1]))
|
||||
case rplKill:
|
||||
@ -473,6 +519,8 @@ func (s *Server) writeClient(output string) {
|
||||
return
|
||||
}
|
||||
|
||||
s.verbosef(" <<< %s", output)
|
||||
|
||||
s.clientConn.SetWriteDeadline(time.Now().Add(time.Second * 30))
|
||||
if _, err := fmt.Fprintf(s.clientConn, "%s\r\n", output); err != nil {
|
||||
s.DisconnectClient()
|
||||
|
@ -39,6 +39,8 @@ const (
|
||||
rplNoTopic
|
||||
rplNames
|
||||
rplEndOfNames
|
||||
rplWho
|
||||
rplEndOfWho
|
||||
rplNickChange
|
||||
rplKill
|
||||
rplMsg
|
||||
|
Loading…
Reference in New Issue
Block a user