Refactor websocket handler
This commit is contained in:
parent
047027ddec
commit
114bf8201e
File diff suppressed because one or more lines are too long
@ -59,7 +59,7 @@ class Socket extends EventEmitter {
|
|||||||
this.send('pong');
|
this.send('pong');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit(msg.type, msg.response);
|
this.emit(msg.type, msg.data);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ class Socket extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
send(type, data) {
|
send(type, data) {
|
||||||
this.ws.send(JSON.stringify({ type, request: data }));
|
this.ws.send(JSON.stringify({ type, data }));
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeoutPing() {
|
setTimeoutPing() {
|
||||||
|
@ -43,9 +43,9 @@ func dispatchMessage(msg *irc.Message) WSResponse {
|
|||||||
return <-s.out
|
return <-s.out
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkResponse(t *testing.T, expectedType string, expectedResponse interface{}, res WSResponse) {
|
func checkResponse(t *testing.T, expectedType string, expectedData interface{}, res WSResponse) {
|
||||||
assert.Equal(t, expectedType, res.Type)
|
assert.Equal(t, expectedType, res.Type)
|
||||||
assert.Equal(t, expectedResponse, res.Response)
|
assert.Equal(t, expectedData, res.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleIRCNick(t *testing.T) {
|
func TestHandleIRCNick(t *testing.T) {
|
||||||
|
@ -7,13 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type WSRequest struct {
|
type WSRequest struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Request json.RawMessage `json:"request"`
|
Data json.RawMessage `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WSResponse struct {
|
type WSResponse struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Response interface{} `json:"response"`
|
Data interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Connect struct {
|
type Connect struct {
|
@ -59,7 +59,7 @@ func upgradeWS(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handleWS(conn)
|
newWSHandler(conn).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func reconnect() {
|
func reconnect() {
|
||||||
|
@ -11,7 +11,7 @@ type Session struct {
|
|||||||
irc map[string]*irc.Client
|
irc map[string]*irc.Client
|
||||||
ircLock sync.Mutex
|
ircLock sync.Mutex
|
||||||
|
|
||||||
ws map[string]*conn
|
ws map[string]*wsConn
|
||||||
wsLock sync.Mutex
|
wsLock sync.Mutex
|
||||||
out chan WSResponse
|
out chan WSResponse
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ type Session struct {
|
|||||||
func NewSession() *Session {
|
func NewSession() *Session {
|
||||||
return &Session{
|
return &Session{
|
||||||
irc: make(map[string]*irc.Client),
|
irc: make(map[string]*irc.Client),
|
||||||
ws: make(map[string]*conn),
|
ws: make(map[string]*wsConn),
|
||||||
out: make(chan WSResponse, 32),
|
out: make(chan WSResponse, 32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ func (s *Session) numIRC() int {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) setWS(addr string, w *conn) {
|
func (s *Session) setWS(addr string, w *wsConn) {
|
||||||
s.wsLock.Lock()
|
s.wsLock.Lock()
|
||||||
s.ws[addr] = w
|
s.ws[addr] = w
|
||||||
s.wsLock.Unlock()
|
s.wsLock.Unlock()
|
||||||
|
@ -6,21 +6,21 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
type conn struct {
|
type wsConn struct {
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
in chan WSRequest
|
in chan WSRequest
|
||||||
out chan WSResponse
|
out chan WSResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConn(ws *websocket.Conn) *conn {
|
func newWSConn(conn *websocket.Conn) *wsConn {
|
||||||
return &conn{
|
return &wsConn{
|
||||||
conn: ws,
|
conn: conn,
|
||||||
in: make(chan WSRequest, 32),
|
in: make(chan WSRequest, 32),
|
||||||
out: make(chan WSResponse, 32),
|
out: make(chan WSResponse, 32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) send() {
|
func (c *wsConn) send() {
|
||||||
var err error
|
var err error
|
||||||
ping := time.Tick(20 * time.Second)
|
ping := time.Tick(20 * time.Second)
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ func (c *conn) send() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) recv() {
|
func (c *wsConn) recv() {
|
||||||
var req WSRequest
|
var req WSRequest
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -57,6 +57,7 @@ func (c *conn) recv() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) close() {
|
func (c *wsConn) close() {
|
||||||
close(c.out)
|
close(c.out)
|
||||||
|
c.conn.Close()
|
||||||
}
|
}
|
@ -11,213 +11,243 @@ import (
|
|||||||
"github.com/khlieng/name_pending/storage"
|
"github.com/khlieng/name_pending/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleWS(conn *websocket.Conn) {
|
type wsHandler struct {
|
||||||
defer conn.Close()
|
ws *wsConn
|
||||||
|
session *Session
|
||||||
|
|
||||||
var session *Session
|
uuid string
|
||||||
var UUID string
|
addr string
|
||||||
|
|
||||||
addr := conn.RemoteAddr().String()
|
handlers map[string]func([]byte)
|
||||||
|
}
|
||||||
|
|
||||||
ws := newConn(conn)
|
func newWSHandler(conn *websocket.Conn) *wsHandler {
|
||||||
defer ws.close()
|
h := &wsHandler{
|
||||||
go ws.send()
|
ws: newWSConn(conn),
|
||||||
go ws.recv()
|
addr: conn.RemoteAddr().String(),
|
||||||
|
}
|
||||||
|
h.initHandlers()
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
log.Println(addr, "connected")
|
func (h *wsHandler) run() {
|
||||||
|
defer h.ws.close()
|
||||||
|
go h.ws.send()
|
||||||
|
go h.ws.recv()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
req, ok := <-ws.in
|
req, ok := <-h.ws.in
|
||||||
if !ok {
|
if !ok {
|
||||||
if session != nil {
|
if h.session != nil {
|
||||||
session.deleteWS(addr)
|
h.session.deleteWS(h.addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println(addr, "disconnected")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch req.Type {
|
h.dispatchRequest(req)
|
||||||
case "uuid":
|
}
|
||||||
json.Unmarshal(req.Request, &UUID)
|
}
|
||||||
|
|
||||||
log.Println(addr, "set UUID", UUID)
|
func (h *wsHandler) dispatchRequest(req WSRequest) {
|
||||||
|
if handler, ok := h.handlers[req.Type]; ok {
|
||||||
sessionLock.Lock()
|
handler(req.Data)
|
||||||
|
}
|
||||||
if storedSession, exists := sessions[UUID]; exists {
|
}
|
||||||
sessionLock.Unlock()
|
|
||||||
session = storedSession
|
func (h *wsHandler) init(b []byte) {
|
||||||
session.setWS(addr, ws)
|
json.Unmarshal(b, &h.uuid)
|
||||||
|
|
||||||
log.Println(addr, "attached to", session.numIRC(), "existing IRC connections")
|
log.Println(h.addr, "set UUID", h.uuid)
|
||||||
|
|
||||||
channels := session.user.GetChannels()
|
sessionLock.Lock()
|
||||||
for i, channel := range channels {
|
if storedSession, exists := sessions[h.uuid]; exists {
|
||||||
channels[i].Topic = channelStore.GetTopic(channel.Server, channel.Name)
|
sessionLock.Unlock()
|
||||||
}
|
h.session = storedSession
|
||||||
|
h.session.setWS(h.addr, h.ws)
|
||||||
session.sendJSON("channels", channels)
|
|
||||||
session.sendJSON("servers", session.user.GetServers())
|
log.Println(h.addr, "attached to", h.session.numIRC(), "existing IRC connections")
|
||||||
|
|
||||||
for _, channel := range channels {
|
channels := h.session.user.GetChannels()
|
||||||
session.sendJSON("users", Userlist{
|
for i, channel := range channels {
|
||||||
Server: channel.Server,
|
channels[i].Topic = channelStore.GetTopic(channel.Server, channel.Name)
|
||||||
Channel: channel.Name,
|
}
|
||||||
Users: channelStore.GetUsers(channel.Server, channel.Name),
|
|
||||||
})
|
h.session.sendJSON("channels", channels)
|
||||||
}
|
h.session.sendJSON("servers", h.session.user.GetServers())
|
||||||
} else {
|
|
||||||
session = NewSession()
|
for _, channel := range channels {
|
||||||
session.user = storage.NewUser(UUID)
|
h.session.sendJSON("users", Userlist{
|
||||||
|
Server: channel.Server,
|
||||||
sessions[UUID] = session
|
Channel: channel.Name,
|
||||||
sessionLock.Unlock()
|
Users: channelStore.GetUsers(channel.Server, channel.Name),
|
||||||
|
})
|
||||||
session.setWS(addr, ws)
|
}
|
||||||
session.sendJSON("servers", nil)
|
} else {
|
||||||
|
h.session = NewSession()
|
||||||
go session.write()
|
h.session.user = storage.NewUser(h.uuid)
|
||||||
}
|
|
||||||
|
sessions[h.uuid] = h.session
|
||||||
case "connect":
|
sessionLock.Unlock()
|
||||||
var data Connect
|
|
||||||
|
h.session.setWS(h.addr, h.ws)
|
||||||
json.Unmarshal(req.Request, &data)
|
h.session.sendJSON("servers", nil)
|
||||||
|
|
||||||
if _, ok := session.getIRC(data.Server); !ok {
|
go h.session.write()
|
||||||
log.Println(addr, "connecting to", data.Server)
|
}
|
||||||
|
}
|
||||||
i := irc.NewClient(data.Nick, data.Username)
|
|
||||||
i.TLS = data.TLS
|
func (h *wsHandler) connect(b []byte) {
|
||||||
i.Password = data.Password
|
var data Connect
|
||||||
i.Realname = data.Realname
|
json.Unmarshal(b, &data)
|
||||||
|
|
||||||
if idx := strings.Index(data.Server, ":"); idx < 0 {
|
if _, ok := h.session.getIRC(data.Server); !ok {
|
||||||
session.setIRC(data.Server, i)
|
log.Println(h.addr, "connecting to", data.Server)
|
||||||
} else {
|
|
||||||
session.setIRC(data.Server[:idx], i)
|
i := irc.NewClient(data.Nick, data.Username)
|
||||||
}
|
i.TLS = data.TLS
|
||||||
|
i.Password = data.Password
|
||||||
i.Connect(data.Server)
|
i.Realname = data.Realname
|
||||||
go newIRCHandler(i, session).run()
|
|
||||||
|
if idx := strings.Index(data.Server, ":"); idx < 0 {
|
||||||
session.user.AddServer(storage.Server{
|
h.session.setIRC(data.Server, i)
|
||||||
Name: data.Name,
|
} else {
|
||||||
Address: i.Host,
|
h.session.setIRC(data.Server[:idx], i)
|
||||||
TLS: data.TLS,
|
}
|
||||||
Password: data.Password,
|
|
||||||
Nick: data.Nick,
|
i.Connect(data.Server)
|
||||||
Username: data.Username,
|
go newIRCHandler(i, h.session).run()
|
||||||
Realname: data.Realname,
|
|
||||||
})
|
h.session.user.AddServer(storage.Server{
|
||||||
} else {
|
Name: data.Name,
|
||||||
log.Println(addr, "already connected to", data.Server)
|
Address: i.Host,
|
||||||
}
|
TLS: data.TLS,
|
||||||
|
Password: data.Password,
|
||||||
case "join":
|
Nick: data.Nick,
|
||||||
var data Join
|
Username: data.Username,
|
||||||
|
Realname: data.Realname,
|
||||||
json.Unmarshal(req.Request, &data)
|
})
|
||||||
|
} else {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
log.Println(h.addr, "already connected to", data.Server)
|
||||||
i.Join(data.Channels...)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "part":
|
func (h *wsHandler) join(b []byte) {
|
||||||
var data Part
|
var data Join
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
json.Unmarshal(req.Request, &data)
|
|
||||||
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
i.Join(data.Channels...)
|
||||||
i.Part(data.Channels...)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "quit":
|
func (h *wsHandler) part(b []byte) {
|
||||||
var data Quit
|
var data Part
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
json.Unmarshal(req.Request, &data)
|
|
||||||
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
i.Part(data.Channels...)
|
||||||
i.Quit()
|
}
|
||||||
session.deleteIRC(data.Server)
|
}
|
||||||
channelStore.RemoveUserAll(i.GetNick(), data.Server)
|
|
||||||
session.user.RemoveServer(data.Server)
|
func (h *wsHandler) quit(b []byte) {
|
||||||
}
|
var data Quit
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
case "chat":
|
|
||||||
var data Chat
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
|
i.Quit()
|
||||||
json.Unmarshal(req.Request, &data)
|
h.session.deleteIRC(data.Server)
|
||||||
|
channelStore.RemoveUserAll(i.GetNick(), data.Server)
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
h.session.user.RemoveServer(data.Server)
|
||||||
i.Privmsg(data.To, data.Message)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "nick":
|
func (h *wsHandler) chat(b []byte) {
|
||||||
var data Nick
|
var data Chat
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
json.Unmarshal(req.Request, &data)
|
|
||||||
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
i.Privmsg(data.To, data.Message)
|
||||||
i.Nick(data.New)
|
}
|
||||||
session.user.SetNick(data.New, data.Server)
|
}
|
||||||
}
|
|
||||||
|
func (h *wsHandler) nick(b []byte) {
|
||||||
case "invite":
|
var data Nick
|
||||||
var data Invite
|
json.Unmarshal(b, &data)
|
||||||
|
|
||||||
json.Unmarshal(req.Request, &data)
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
|
i.Nick(data.New)
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
h.session.user.SetNick(data.New, data.Server)
|
||||||
i.Invite(data.User, data.Channel)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "kick":
|
func (h *wsHandler) invite(b []byte) {
|
||||||
var data Invite
|
var data Invite
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
json.Unmarshal(req.Request, &data)
|
|
||||||
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
i.Invite(data.User, data.Channel)
|
||||||
i.Kick(data.Channel, data.User)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "whois":
|
func (h *wsHandler) kick(b []byte) {
|
||||||
var data Whois
|
var data Invite
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
json.Unmarshal(req.Request, &data)
|
|
||||||
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
i.Kick(data.Channel, data.User)
|
||||||
i.Whois(data.User)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "away":
|
func (h *wsHandler) whois(b []byte) {
|
||||||
var data Away
|
var data Whois
|
||||||
|
json.Unmarshal(b, &data)
|
||||||
json.Unmarshal(req.Request, &data)
|
|
||||||
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
if i, ok := session.getIRC(data.Server); ok {
|
i.Whois(data.User)
|
||||||
i.Away(data.Message)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "search":
|
func (h *wsHandler) away(b []byte) {
|
||||||
go func() {
|
var data Away
|
||||||
var data SearchRequest
|
json.Unmarshal(b, &data)
|
||||||
|
|
||||||
json.Unmarshal(req.Request, &data)
|
if i, ok := h.session.getIRC(data.Server); ok {
|
||||||
|
i.Away(data.Message)
|
||||||
results, err := session.user.SearchMessages(data.Server, data.Channel, data.Phrase)
|
}
|
||||||
if err != nil {
|
}
|
||||||
log.Println(err)
|
|
||||||
return
|
func (h *wsHandler) search(b []byte) {
|
||||||
}
|
go func() {
|
||||||
|
var data SearchRequest
|
||||||
session.sendJSON("search", SearchResult{
|
json.Unmarshal(b, &data)
|
||||||
Server: data.Server,
|
|
||||||
Channel: data.Channel,
|
results, err := h.session.user.SearchMessages(data.Server, data.Channel, data.Phrase)
|
||||||
Results: results,
|
if err != nil {
|
||||||
})
|
log.Println(err)
|
||||||
}()
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.session.sendJSON("search", SearchResult{
|
||||||
|
Server: data.Server,
|
||||||
|
Channel: data.Channel,
|
||||||
|
Results: results,
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *wsHandler) initHandlers() {
|
||||||
|
h.handlers = map[string]func([]byte){
|
||||||
|
"uuid": h.init,
|
||||||
|
"connect": h.connect,
|
||||||
|
"join": h.join,
|
||||||
|
"part": h.part,
|
||||||
|
"quit": h.quit,
|
||||||
|
"chat": h.chat,
|
||||||
|
"nick": h.nick,
|
||||||
|
"invite": h.invite,
|
||||||
|
"kick": h.kick,
|
||||||
|
"whois": h.whois,
|
||||||
|
"away": h.away,
|
||||||
|
"search": h.search,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user