Pull IRC client out
This commit is contained in:
parent
78b6a0859b
commit
adcf12e1fa
11 changed files with 567 additions and 538 deletions
62
server/conn.go
Normal file
62
server/conn.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
conn *websocket.Conn
|
||||
in chan WSRequest
|
||||
out chan []byte
|
||||
}
|
||||
|
||||
func newConn(ws *websocket.Conn) *conn {
|
||||
return &conn{
|
||||
conn: ws,
|
||||
in: make(chan WSRequest, 32),
|
||||
out: make(chan []byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) send() {
|
||||
var err error
|
||||
ping := time.Tick(20 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case msg, ok := <-c.out:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.conn.WriteMessage(websocket.TextMessage, msg)
|
||||
|
||||
case <-ping:
|
||||
err = c.conn.WriteJSON(WSResponse{Type: "ping"})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) recv() {
|
||||
var req WSRequest
|
||||
|
||||
for {
|
||||
err := c.conn.ReadJSON(&req)
|
||||
if err != nil {
|
||||
close(c.in)
|
||||
return
|
||||
}
|
||||
|
||||
c.in <- req
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) close() {
|
||||
close(c.out)
|
||||
}
|
379
server/irc.go
379
server/irc.go
|
@ -1,379 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
PING = "PING"
|
||||
NICK = "NICK"
|
||||
JOIN = "JOIN"
|
||||
PART = "PART"
|
||||
MODE = "MODE"
|
||||
PRIVMSG = "PRIVMSG"
|
||||
NOTICE = "NOTICE"
|
||||
TOPIC = "TOPIC"
|
||||
QUIT = "QUIT"
|
||||
|
||||
RPL_WELCOME = "001"
|
||||
RPL_YOURHOST = "002"
|
||||
RPL_CREATED = "003"
|
||||
RPL_LUSERCLIENT = "251"
|
||||
RPL_LUSEROP = "252"
|
||||
RPL_LUSERUNKNOWN = "253"
|
||||
RPL_LUSERCHANNELS = "254"
|
||||
RPL_LUSERME = "255"
|
||||
|
||||
RPL_AWAY = "301"
|
||||
|
||||
RPL_WHOISUSER = "311"
|
||||
RPL_WHOISSERVER = "312"
|
||||
RPL_WHOISOPERATOR = "313"
|
||||
RPL_WHOISIDLE = "317"
|
||||
RPL_ENDOFWHOIS = "318"
|
||||
RPL_WHOISCHANNELS = "319"
|
||||
|
||||
RPL_TOPIC = "332"
|
||||
|
||||
RPL_NAMREPLY = "353"
|
||||
RPL_ENDOFNAMES = "366"
|
||||
|
||||
RPL_MOTD = "372"
|
||||
RPL_MOTDSTART = "375"
|
||||
RPL_ENDOFMOTD = "376"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Prefix string
|
||||
Nick string
|
||||
Command string
|
||||
Params []string
|
||||
Trailing string
|
||||
}
|
||||
|
||||
type IRC struct {
|
||||
conn net.Conn
|
||||
connected bool
|
||||
dialer *net.Dialer
|
||||
reader *bufio.Reader
|
||||
out chan string
|
||||
|
||||
quit chan struct{}
|
||||
reconnect chan struct{}
|
||||
ready sync.WaitGroup
|
||||
once sync.Once
|
||||
lock sync.Mutex
|
||||
|
||||
nick string
|
||||
|
||||
Messages chan *Message
|
||||
Server string
|
||||
Host string
|
||||
TLS bool
|
||||
TLSConfig *tls.Config
|
||||
Password string
|
||||
Username string
|
||||
Realname string
|
||||
}
|
||||
|
||||
func NewIRC(nick, username string) *IRC {
|
||||
return &IRC{
|
||||
nick: nick,
|
||||
Username: username,
|
||||
Realname: nick,
|
||||
Messages: make(chan *Message, 32),
|
||||
out: make(chan string, 32),
|
||||
quit: make(chan struct{}),
|
||||
reconnect: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IRC) Connect(address string) {
|
||||
if idx := strings.Index(address, ":"); idx < 0 {
|
||||
i.Host = address
|
||||
|
||||
if i.TLS {
|
||||
address += ":6697"
|
||||
} else {
|
||||
address += ":6667"
|
||||
}
|
||||
} else {
|
||||
i.Host = address[:idx]
|
||||
}
|
||||
i.Server = address
|
||||
i.dialer = &net.Dialer{Timeout: 10 * time.Second}
|
||||
|
||||
go i.run()
|
||||
}
|
||||
|
||||
func (i *IRC) Connected() bool {
|
||||
i.lock.Lock()
|
||||
defer i.lock.Unlock()
|
||||
|
||||
return i.connected
|
||||
}
|
||||
|
||||
func (i *IRC) Pass(password string) {
|
||||
i.write("PASS " + password)
|
||||
}
|
||||
|
||||
func (i *IRC) Nick(nick string) {
|
||||
i.Write("NICK " + nick)
|
||||
|
||||
i.lock.Lock()
|
||||
i.nick = nick
|
||||
i.lock.Unlock()
|
||||
}
|
||||
|
||||
func (i *IRC) User(username, realname string) {
|
||||
i.writef("USER %s 0 * :%s", username, realname)
|
||||
}
|
||||
|
||||
func (i *IRC) Oper(name, password string) {
|
||||
i.Write("OPER " + name + " " + password)
|
||||
}
|
||||
|
||||
func (i *IRC) Mode(target, modes, params string) {
|
||||
i.Write(strings.TrimRight("MODE "+target+" "+modes+" "+params, " "))
|
||||
}
|
||||
|
||||
func (i *IRC) Quit() {
|
||||
go func() {
|
||||
if i.Connected() {
|
||||
i.write("QUIT")
|
||||
}
|
||||
close(i.quit)
|
||||
}()
|
||||
}
|
||||
|
||||
func (i *IRC) Join(channels ...string) {
|
||||
i.Write("JOIN " + strings.Join(channels, ","))
|
||||
}
|
||||
|
||||
func (i *IRC) Part(channels ...string) {
|
||||
i.Write("PART " + strings.Join(channels, ","))
|
||||
}
|
||||
|
||||
func (i *IRC) Topic(channel string) {
|
||||
i.Write("TOPIC " + channel)
|
||||
}
|
||||
|
||||
func (i *IRC) Invite(nick, channel string) {
|
||||
i.Write("INVITE " + nick + " " + channel)
|
||||
}
|
||||
|
||||
func (i *IRC) Kick(channel string, users ...string) {
|
||||
i.Write("KICK " + channel + " " + strings.Join(users, ","))
|
||||
}
|
||||
|
||||
func (i *IRC) Privmsg(target, msg string) {
|
||||
i.Writef("PRIVMSG %s :%s", target, msg)
|
||||
}
|
||||
|
||||
func (i *IRC) Notice(target, msg string) {
|
||||
i.Writef("NOTICE %s :%s", target, msg)
|
||||
}
|
||||
|
||||
func (i *IRC) Whois(nick string) {
|
||||
i.Write("WHOIS " + nick)
|
||||
}
|
||||
|
||||
func (i *IRC) Away(message string) {
|
||||
i.Write("AWAY :" + message)
|
||||
}
|
||||
|
||||
func (i *IRC) GetNick() string {
|
||||
i.lock.Lock()
|
||||
defer i.lock.Unlock()
|
||||
|
||||
return i.nick
|
||||
}
|
||||
|
||||
func (i *IRC) Write(data string) {
|
||||
i.out <- data + "\r\n"
|
||||
}
|
||||
|
||||
func (i *IRC) Writef(format string, a ...interface{}) {
|
||||
i.out <- fmt.Sprintf(format+"\r\n", a...)
|
||||
}
|
||||
|
||||
func (i *IRC) write(data string) {
|
||||
i.conn.Write([]byte(data + "\r\n"))
|
||||
}
|
||||
|
||||
func (i *IRC) writef(format string, a ...interface{}) {
|
||||
fmt.Fprintf(i.conn, format+"\r\n", a...)
|
||||
}
|
||||
|
||||
func (i *IRC) run() {
|
||||
i.tryConnect()
|
||||
for {
|
||||
select {
|
||||
case <-i.quit:
|
||||
i.close()
|
||||
i.lock.Lock()
|
||||
i.connected = false
|
||||
i.lock.Unlock()
|
||||
return
|
||||
|
||||
case <-i.reconnect:
|
||||
i.reconnect = make(chan struct{})
|
||||
i.once = sync.Once{}
|
||||
i.tryConnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IRC) tryConnect() {
|
||||
// TODO: backoff
|
||||
for {
|
||||
select {
|
||||
case <-i.quit:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
err := i.connect()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IRC) connect() error {
|
||||
if i.TLS {
|
||||
if i.TLSConfig == nil {
|
||||
i.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
}
|
||||
|
||||
if conn, err := tls.DialWithDialer(i.dialer, "tcp", i.Server, i.TLSConfig); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i.conn = conn
|
||||
}
|
||||
} else {
|
||||
if conn, err := i.dialer.Dial("tcp", i.Server); err != nil {
|
||||
return err
|
||||
} else {
|
||||
i.conn = conn
|
||||
}
|
||||
}
|
||||
|
||||
i.lock.Lock()
|
||||
i.connected = true
|
||||
i.lock.Unlock()
|
||||
|
||||
i.reader = bufio.NewReader(i.conn)
|
||||
|
||||
if i.Password != "" {
|
||||
i.Pass(i.Password)
|
||||
}
|
||||
i.write("NICK " + i.nick)
|
||||
i.User(i.Username, i.Realname)
|
||||
|
||||
i.ready.Add(1)
|
||||
go i.send()
|
||||
go i.recv()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IRC) send() {
|
||||
i.ready.Wait()
|
||||
for {
|
||||
select {
|
||||
case <-i.quit:
|
||||
return
|
||||
|
||||
case <-i.reconnect:
|
||||
return
|
||||
|
||||
case msg := <-i.out:
|
||||
_, err := i.conn.Write([]byte(msg))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IRC) recv() {
|
||||
defer i.conn.Close()
|
||||
for {
|
||||
line, err := i.reader.ReadString('\n')
|
||||
if err != nil {
|
||||
i.lock.Lock()
|
||||
i.connected = false
|
||||
i.lock.Unlock()
|
||||
i.once.Do(i.ready.Done)
|
||||
close(i.reconnect)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-i.quit:
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
msg := parseMessage(line)
|
||||
i.Messages <- msg
|
||||
|
||||
switch msg.Command {
|
||||
case PING:
|
||||
go i.write("PONG :" + msg.Trailing)
|
||||
|
||||
case RPL_WELCOME:
|
||||
i.once.Do(i.ready.Done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *IRC) close() {
|
||||
if i.Connected() {
|
||||
i.once.Do(i.ready.Done)
|
||||
}
|
||||
close(i.out)
|
||||
close(i.Messages)
|
||||
}
|
||||
|
||||
func parseMessage(line string) *Message {
|
||||
line = strings.Trim(line, "\r\n")
|
||||
msg := Message{}
|
||||
cmdStart := 0
|
||||
cmdEnd := len(line)
|
||||
|
||||
if strings.HasPrefix(line, ":") {
|
||||
cmdStart = strings.Index(line, " ") + 1
|
||||
msg.Prefix = line[1 : cmdStart-1]
|
||||
|
||||
if i := strings.Index(msg.Prefix, "!"); i > 0 {
|
||||
msg.Nick = msg.Prefix[:i]
|
||||
} else {
|
||||
msg.Nick = msg.Prefix
|
||||
}
|
||||
}
|
||||
|
||||
if i := strings.Index(line, " :"); i > 0 {
|
||||
cmdEnd = i
|
||||
msg.Trailing = line[i+2:]
|
||||
}
|
||||
|
||||
cmd := strings.Split(line[cmdStart:cmdEnd], " ")
|
||||
msg.Command = cmd[0]
|
||||
if len(cmd) > 1 {
|
||||
msg.Params = cmd[1:]
|
||||
}
|
||||
|
||||
if msg.Trailing != "" {
|
||||
msg.Params = append(msg.Params, msg.Trailing)
|
||||
}
|
||||
|
||||
return &msg
|
||||
}
|
|
@ -4,86 +4,87 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/khlieng/name_pending/irc"
|
||||
"github.com/khlieng/name_pending/storage"
|
||||
)
|
||||
|
||||
func handleMessages(irc *IRC, session *Session) {
|
||||
func handleIRC(client *irc.Client, session *Session) {
|
||||
var whois WhoisReply
|
||||
userBuffers := make(map[string][]string)
|
||||
var motd MOTD
|
||||
|
||||
for {
|
||||
msg, ok := <-irc.Messages
|
||||
msg, ok := <-client.Messages
|
||||
if !ok {
|
||||
session.deleteIRC(irc.Host)
|
||||
session.deleteIRC(client.Host)
|
||||
return
|
||||
}
|
||||
|
||||
switch msg.Command {
|
||||
case NICK:
|
||||
case irc.Nick:
|
||||
session.sendJSON("nick", Nick{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
Old: msg.Nick,
|
||||
New: msg.Trailing,
|
||||
})
|
||||
|
||||
channelStore.RenameUser(msg.Nick, msg.Trailing, irc.Host)
|
||||
channelStore.RenameUser(msg.Nick, msg.Trailing, client.Host)
|
||||
|
||||
case JOIN:
|
||||
case irc.Join:
|
||||
session.sendJSON("join", Join{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
User: msg.Nick,
|
||||
Channels: msg.Params,
|
||||
})
|
||||
|
||||
channelStore.AddUser(msg.Nick, irc.Host, msg.Params[0])
|
||||
channelStore.AddUser(msg.Nick, client.Host, msg.Params[0])
|
||||
|
||||
if msg.Nick == irc.GetNick() {
|
||||
if msg.Nick == client.GetNick() {
|
||||
session.user.AddChannel(storage.Channel{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
Name: msg.Params[0],
|
||||
})
|
||||
}
|
||||
|
||||
case PART:
|
||||
case irc.Part:
|
||||
session.sendJSON("part", Part{
|
||||
Join: Join{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
User: msg.Nick,
|
||||
Channels: msg.Params,
|
||||
},
|
||||
Reason: msg.Trailing,
|
||||
})
|
||||
|
||||
channelStore.RemoveUser(msg.Nick, irc.Host, msg.Params[0])
|
||||
channelStore.RemoveUser(msg.Nick, client.Host, msg.Params[0])
|
||||
|
||||
if msg.Nick == irc.GetNick() {
|
||||
session.user.RemoveChannel(irc.Host, msg.Params[0])
|
||||
if msg.Nick == client.GetNick() {
|
||||
session.user.RemoveChannel(client.Host, msg.Params[0])
|
||||
}
|
||||
|
||||
case MODE:
|
||||
case irc.Mode:
|
||||
target := msg.Params[0]
|
||||
if len(msg.Params) > 2 && isChannel(target) {
|
||||
mode := parseMode(msg.Params[1])
|
||||
mode.Server = irc.Host
|
||||
mode.Server = client.Host
|
||||
mode.Channel = target
|
||||
mode.User = msg.Params[2]
|
||||
|
||||
session.sendJSON("mode", mode)
|
||||
|
||||
channelStore.SetMode(irc.Host, target, msg.Params[2], mode.Add, mode.Remove)
|
||||
channelStore.SetMode(client.Host, target, msg.Params[2], mode.Add, mode.Remove)
|
||||
}
|
||||
|
||||
case PRIVMSG, NOTICE:
|
||||
if msg.Params[0] == irc.GetNick() {
|
||||
case irc.Privmsg, irc.Notice:
|
||||
if msg.Params[0] == client.GetNick() {
|
||||
session.sendJSON("pm", Chat{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
From: msg.Nick,
|
||||
Message: msg.Trailing,
|
||||
})
|
||||
} else {
|
||||
session.sendJSON("message", Chat{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
From: msg.Nick,
|
||||
To: msg.Params[0],
|
||||
Message: msg.Trailing,
|
||||
|
@ -91,90 +92,90 @@ func handleMessages(irc *IRC, session *Session) {
|
|||
}
|
||||
|
||||
if msg.Params[0] != "*" {
|
||||
session.user.LogMessage(irc.Host, msg.Nick, msg.Params[0], msg.Trailing)
|
||||
session.user.LogMessage(client.Host, msg.Nick, msg.Params[0], msg.Trailing)
|
||||
}
|
||||
|
||||
case QUIT:
|
||||
case irc.Quit:
|
||||
session.sendJSON("quit", Quit{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
User: msg.Nick,
|
||||
Reason: msg.Trailing,
|
||||
})
|
||||
|
||||
channelStore.RemoveUserAll(msg.Nick, irc.Host)
|
||||
channelStore.RemoveUserAll(msg.Nick, client.Host)
|
||||
|
||||
case RPL_WELCOME,
|
||||
RPL_YOURHOST,
|
||||
RPL_CREATED,
|
||||
RPL_LUSERCLIENT,
|
||||
RPL_LUSEROP,
|
||||
RPL_LUSERUNKNOWN,
|
||||
RPL_LUSERCHANNELS,
|
||||
RPL_LUSERME:
|
||||
case irc.ReplyWelcome,
|
||||
irc.ReplyYourHost,
|
||||
irc.ReplyCreated,
|
||||
irc.ReplyLUserClient,
|
||||
irc.ReplyLUserOp,
|
||||
irc.ReplyLUserUnknown,
|
||||
irc.ReplyLUserChannels,
|
||||
irc.ReplyLUserMe:
|
||||
session.sendJSON("pm", Chat{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
From: msg.Nick,
|
||||
Message: strings.Join(msg.Params[1:], " "),
|
||||
})
|
||||
|
||||
case RPL_WHOISUSER:
|
||||
case irc.ReplyWhoisUser:
|
||||
whois.Nick = msg.Params[1]
|
||||
whois.Username = msg.Params[2]
|
||||
whois.Host = msg.Params[3]
|
||||
whois.Realname = msg.Params[5]
|
||||
|
||||
case RPL_WHOISSERVER:
|
||||
case irc.ReplyWhoisServer:
|
||||
whois.Server = msg.Params[2]
|
||||
|
||||
case RPL_WHOISCHANNELS:
|
||||
case irc.ReplyWhoisChannels:
|
||||
whois.Channels = append(whois.Channels, strings.Split(strings.TrimRight(msg.Trailing, " "), " ")...)
|
||||
|
||||
case RPL_ENDOFWHOIS:
|
||||
case irc.ReplyEndOfWhois:
|
||||
session.sendJSON("whois", whois)
|
||||
|
||||
whois = WhoisReply{}
|
||||
|
||||
case RPL_TOPIC:
|
||||
case irc.ReplyTopic:
|
||||
session.sendJSON("topic", Topic{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
Channel: msg.Params[1],
|
||||
Topic: msg.Trailing,
|
||||
})
|
||||
|
||||
channelStore.SetTopic(msg.Trailing, irc.Host, msg.Params[1])
|
||||
channelStore.SetTopic(msg.Trailing, client.Host, msg.Params[1])
|
||||
|
||||
case RPL_NAMREPLY:
|
||||
case irc.ReplyNamReply:
|
||||
users := strings.Split(msg.Trailing, " ")
|
||||
userBuffer := userBuffers[msg.Params[2]]
|
||||
userBuffers[msg.Params[2]] = append(userBuffer, users...)
|
||||
|
||||
case RPL_ENDOFNAMES:
|
||||
case irc.ReplyEndOfNames:
|
||||
channel := msg.Params[1]
|
||||
users := userBuffers[channel]
|
||||
|
||||
session.sendJSON("users", Userlist{
|
||||
Server: irc.Host,
|
||||
Server: client.Host,
|
||||
Channel: channel,
|
||||
Users: users,
|
||||
})
|
||||
|
||||
channelStore.SetUsers(users, irc.Host, channel)
|
||||
channelStore.SetUsers(users, client.Host, channel)
|
||||
delete(userBuffers, channel)
|
||||
|
||||
case RPL_MOTDSTART:
|
||||
motd.Server = irc.Host
|
||||
case irc.ReplyMotdStart:
|
||||
motd.Server = client.Host
|
||||
motd.Title = msg.Trailing
|
||||
|
||||
case RPL_MOTD:
|
||||
case irc.ReplyMotd:
|
||||
motd.Content = append(motd.Content, msg.Trailing)
|
||||
|
||||
case RPL_ENDOFMOTD:
|
||||
case irc.ReplyEndOfMotd:
|
||||
session.sendJSON("motd", motd)
|
||||
|
||||
motd = MOTD{}
|
||||
|
||||
default:
|
||||
printMessage(msg, irc)
|
||||
printMessage(msg, client)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,6 +203,6 @@ func isChannel(s string) bool {
|
|||
return strings.IndexAny(s, "&#+!") == 0
|
||||
}
|
||||
|
||||
func printMessage(msg *Message, irc *IRC) {
|
||||
log.Println(irc.GetNick()+":", msg.Prefix, msg.Command, msg.Params, msg.Trailing)
|
||||
func printMessage(msg *irc.Message, i *irc.Client) {
|
||||
log.Println(i.GetNick()+":", msg.Prefix, msg.Command, msg.Params, msg.Trailing)
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
"github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
|
||||
|
||||
"github.com/khlieng/name_pending/irc"
|
||||
"github.com/khlieng/name_pending/storage"
|
||||
)
|
||||
|
||||
|
@ -63,16 +64,16 @@ func reconnect() {
|
|||
channels := user.GetChannels()
|
||||
|
||||
for _, server := range user.GetServers() {
|
||||
irc := NewIRC(server.Nick, server.Username)
|
||||
irc.TLS = server.TLS
|
||||
irc.Password = server.Password
|
||||
irc.Realname = server.Realname
|
||||
i := irc.NewClient(server.Nick, server.Username)
|
||||
i.TLS = server.TLS
|
||||
i.Password = server.Password
|
||||
i.Realname = server.Realname
|
||||
|
||||
go func(server storage.Server) {
|
||||
irc.Connect(server.Address)
|
||||
session.setIRC(irc.Host, irc)
|
||||
i.Connect(server.Address)
|
||||
session.setIRC(i.Host, i)
|
||||
|
||||
go handleMessages(irc, session)
|
||||
go handleIRC(i, session)
|
||||
|
||||
var joining []string
|
||||
for _, channel := range channels {
|
||||
|
@ -80,7 +81,7 @@ func reconnect() {
|
|||
joining = append(joining, channel.Name)
|
||||
}
|
||||
}
|
||||
irc.Join(joining...)
|
||||
i.Join(joining...)
|
||||
}(server)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,15 @@ import (
|
|||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/khlieng/name_pending/irc"
|
||||
"github.com/khlieng/name_pending/storage"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
irc map[string]*IRC
|
||||
irc map[string]*irc.Client
|
||||
ircLock sync.Mutex
|
||||
|
||||
ws map[string]*WebSocket
|
||||
ws map[string]*conn
|
||||
wsLock sync.Mutex
|
||||
out chan []byte
|
||||
|
||||
|
@ -20,23 +21,23 @@ type Session struct {
|
|||
|
||||
func NewSession() *Session {
|
||||
return &Session{
|
||||
irc: make(map[string]*IRC),
|
||||
ws: make(map[string]*WebSocket),
|
||||
irc: make(map[string]*irc.Client),
|
||||
ws: make(map[string]*conn),
|
||||
out: make(chan []byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) getIRC(server string) (*IRC, bool) {
|
||||
func (s *Session) getIRC(server string) (*irc.Client, bool) {
|
||||
s.ircLock.Lock()
|
||||
irc, ok := s.irc[server]
|
||||
i, ok := s.irc[server]
|
||||
s.ircLock.Unlock()
|
||||
|
||||
return irc, ok
|
||||
return i, ok
|
||||
}
|
||||
|
||||
func (s *Session) setIRC(server string, irc *IRC) {
|
||||
func (s *Session) setIRC(server string, i *irc.Client) {
|
||||
s.ircLock.Lock()
|
||||
s.irc[server] = irc
|
||||
s.irc[server] = i
|
||||
s.ircLock.Unlock()
|
||||
}
|
||||
|
||||
|
@ -54,7 +55,7 @@ func (s *Session) numIRC() int {
|
|||
return n
|
||||
}
|
||||
|
||||
func (s *Session) setWS(addr string, w *WebSocket) {
|
||||
func (s *Session) setWS(addr string, w *conn) {
|
||||
s.wsLock.Lock()
|
||||
s.ws[addr] = w
|
||||
s.wsLock.Unlock()
|
||||
|
@ -85,7 +86,7 @@ func (s *Session) write() {
|
|||
for res := range s.out {
|
||||
s.wsLock.Lock()
|
||||
for _, ws := range s.ws {
|
||||
ws.Out <- res
|
||||
ws.out <- res
|
||||
}
|
||||
s.wsLock.Unlock()
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type WebSocket struct {
|
||||
conn *websocket.Conn
|
||||
|
||||
Out chan []byte
|
||||
}
|
||||
|
||||
func NewWebSocket(ws *websocket.Conn) *WebSocket {
|
||||
return &WebSocket{
|
||||
conn: ws,
|
||||
Out: make(chan []byte, 32),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebSocket) write() {
|
||||
var err error
|
||||
ping := time.Tick(20 * time.Second)
|
||||
|
||||
for {
|
||||
select {
|
||||
case msg, ok := <-w.Out:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err = w.conn.WriteMessage(websocket.TextMessage, msg)
|
||||
|
||||
case <-ping:
|
||||
err = w.conn.WriteJSON(WSResponse{Type: "ping"})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebSocket) close() {
|
||||
close(w.Out)
|
||||
}
|
|
@ -7,31 +7,32 @@ import (
|
|||
|
||||
"github.com/khlieng/name_pending/Godeps/_workspace/src/github.com/gorilla/websocket"
|
||||
|
||||
"github.com/khlieng/name_pending/irc"
|
||||
"github.com/khlieng/name_pending/storage"
|
||||
)
|
||||
|
||||
func handleWS(ws *websocket.Conn) {
|
||||
defer ws.Close()
|
||||
func handleWS(conn *websocket.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
var session *Session
|
||||
var UUID string
|
||||
var req WSRequest
|
||||
|
||||
addr := ws.RemoteAddr().String()
|
||||
w := NewWebSocket(ws)
|
||||
go w.write()
|
||||
addr := conn.RemoteAddr().String()
|
||||
|
||||
ws := newConn(conn)
|
||||
defer ws.close()
|
||||
go ws.send()
|
||||
go ws.recv()
|
||||
|
||||
log.Println(addr, "connected")
|
||||
|
||||
for {
|
||||
err := ws.ReadJSON(&req)
|
||||
if err != nil {
|
||||
req, ok := <-ws.in
|
||||
if !ok {
|
||||
if session != nil {
|
||||
session.deleteWS(addr)
|
||||
}
|
||||
|
||||
w.close()
|
||||
|
||||
log.Println(addr, "disconnected")
|
||||
return
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ func handleWS(ws *websocket.Conn) {
|
|||
go session.write()
|
||||
}
|
||||
|
||||
session.setWS(addr, w)
|
||||
session.setWS(addr, ws)
|
||||
|
||||
case "connect":
|
||||
var data Connect
|
||||
|
@ -87,24 +88,24 @@ func handleWS(ws *websocket.Conn) {
|
|||
if _, ok := session.getIRC(data.Server); !ok {
|
||||
log.Println(addr, "connecting to", data.Server)
|
||||
|
||||
irc := NewIRC(data.Nick, data.Username)
|
||||
irc.TLS = data.TLS
|
||||
irc.Password = data.Password
|
||||
irc.Realname = data.Realname
|
||||
i := irc.NewClient(data.Nick, data.Username)
|
||||
i.TLS = data.TLS
|
||||
i.Password = data.Password
|
||||
i.Realname = data.Realname
|
||||
|
||||
if idx := strings.Index(data.Server, ":"); idx < 0 {
|
||||
session.setIRC(data.Server, irc)
|
||||
session.setIRC(data.Server, i)
|
||||
} else {
|
||||
session.setIRC(data.Server[:idx], irc)
|
||||
session.setIRC(data.Server[:idx], i)
|
||||
}
|
||||
|
||||
go func() {
|
||||
irc.Connect(data.Server)
|
||||
go handleMessages(irc, session)
|
||||
i.Connect(data.Server)
|
||||
go handleIRC(i, session)
|
||||
|
||||
session.user.AddServer(storage.Server{
|
||||
Name: data.Name,
|
||||
Address: irc.Host,
|
||||
Address: i.Host,
|
||||
TLS: data.TLS,
|
||||
Password: data.Password,
|
||||
Nick: data.Nick,
|
||||
|
@ -121,8 +122,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Join(data.Channels...)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Join(data.Channels...)
|
||||
}
|
||||
|
||||
case "part":
|
||||
|
@ -130,8 +131,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Part(data.Channels...)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Part(data.Channels...)
|
||||
}
|
||||
|
||||
case "quit":
|
||||
|
@ -139,10 +140,10 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Quit()
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Quit()
|
||||
session.deleteIRC(data.Server)
|
||||
channelStore.RemoveUserAll(irc.GetNick(), data.Server)
|
||||
channelStore.RemoveUserAll(i.GetNick(), data.Server)
|
||||
session.user.RemoveServer(data.Server)
|
||||
}
|
||||
|
||||
|
@ -151,8 +152,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Privmsg(data.To, data.Message)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Privmsg(data.To, data.Message)
|
||||
}
|
||||
|
||||
case "nick":
|
||||
|
@ -160,8 +161,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Nick(data.New)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Nick(data.New)
|
||||
session.user.SetNick(data.New, data.Server)
|
||||
}
|
||||
|
||||
|
@ -170,8 +171,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Invite(data.User, data.Channel)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Invite(data.User, data.Channel)
|
||||
}
|
||||
|
||||
case "kick":
|
||||
|
@ -179,8 +180,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Kick(data.Channel, data.User)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Kick(data.Channel, data.User)
|
||||
}
|
||||
|
||||
case "whois":
|
||||
|
@ -188,8 +189,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Whois(data.User)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Whois(data.User)
|
||||
}
|
||||
|
||||
case "away":
|
||||
|
@ -197,8 +198,8 @@ func handleWS(ws *websocket.Conn) {
|
|||
|
||||
json.Unmarshal(req.Request, &data)
|
||||
|
||||
if irc, ok := session.getIRC(data.Server); ok {
|
||||
irc.Away(data.Message)
|
||||
if i, ok := session.getIRC(data.Server); ok {
|
||||
i.Away(data.Message)
|
||||
}
|
||||
|
||||
case "search":
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue