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