2015-05-01 20:59:46 +00:00
|
|
|
package server
|
2015-01-17 01:37:21 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
2016-01-19 21:02:12 +00:00
|
|
|
"time"
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2017-04-06 21:26:58 +00:00
|
|
|
"fmt"
|
|
|
|
|
2015-12-11 03:35:48 +00:00
|
|
|
"github.com/khlieng/dispatch/irc"
|
|
|
|
"github.com/khlieng/dispatch/storage"
|
2015-01-17 01:37:21 +00:00
|
|
|
)
|
|
|
|
|
2016-01-19 21:02:12 +00:00
|
|
|
const (
|
|
|
|
AnonymousSessionExpiration = 24 * time.Hour
|
|
|
|
)
|
|
|
|
|
2015-01-17 01:37:21 +00:00
|
|
|
type Session struct {
|
2016-01-13 17:53:54 +00:00
|
|
|
irc map[string]*irc.Client
|
|
|
|
connectionState map[string]bool
|
|
|
|
ircLock sync.Mutex
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2016-01-25 05:01:40 +00:00
|
|
|
ws map[string]*wsConn
|
|
|
|
wsLock sync.Mutex
|
|
|
|
broadcast chan WSResponse
|
2015-01-17 01:37:21 +00:00
|
|
|
|
2016-01-19 21:02:12 +00:00
|
|
|
user *storage.User
|
|
|
|
expiration *time.Timer
|
|
|
|
reset chan time.Duration
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
func NewSession(user *storage.User) *Session {
|
2015-01-17 01:37:21 +00:00
|
|
|
return &Session{
|
2016-01-13 17:53:54 +00:00
|
|
|
irc: make(map[string]*irc.Client),
|
|
|
|
connectionState: make(map[string]bool),
|
|
|
|
ws: make(map[string]*wsConn),
|
2016-01-25 05:01:40 +00:00
|
|
|
broadcast: make(chan WSResponse, 32),
|
2016-01-15 01:27:30 +00:00
|
|
|
user: user,
|
2016-01-19 21:02:12 +00:00
|
|
|
expiration: time.NewTimer(AnonymousSessionExpiration),
|
|
|
|
reset: make(chan time.Duration, 1),
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-05 22:34:13 +00:00
|
|
|
func (s *Session) getIRC(server string) (*irc.Client, bool) {
|
2015-01-17 01:37:21 +00:00
|
|
|
s.ircLock.Lock()
|
2015-06-05 22:34:13 +00:00
|
|
|
i, ok := s.irc[server]
|
2015-02-09 00:00:30 +00:00
|
|
|
s.ircLock.Unlock()
|
|
|
|
|
2015-06-05 22:34:13 +00:00
|
|
|
return i, ok
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
|
2015-06-05 22:34:13 +00:00
|
|
|
func (s *Session) setIRC(server string, i *irc.Client) {
|
2015-01-17 01:37:21 +00:00
|
|
|
s.ircLock.Lock()
|
2015-06-05 22:34:13 +00:00
|
|
|
s.irc[server] = i
|
2016-01-13 17:53:54 +00:00
|
|
|
s.connectionState[server] = false
|
2015-01-17 01:37:21 +00:00
|
|
|
s.ircLock.Unlock()
|
2016-01-19 21:02:12 +00:00
|
|
|
|
|
|
|
s.reset <- 0
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
|
2015-02-09 00:00:30 +00:00
|
|
|
func (s *Session) deleteIRC(server string) {
|
|
|
|
s.ircLock.Lock()
|
|
|
|
delete(s.irc, server)
|
2016-01-13 17:53:54 +00:00
|
|
|
delete(s.connectionState, server)
|
2015-02-09 00:00:30 +00:00
|
|
|
s.ircLock.Unlock()
|
2016-01-19 21:02:12 +00:00
|
|
|
|
|
|
|
s.resetExpirationIfEmpty()
|
2015-02-09 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) numIRC() int {
|
|
|
|
s.ircLock.Lock()
|
|
|
|
n := len(s.irc)
|
|
|
|
s.ircLock.Unlock()
|
|
|
|
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
2016-01-13 17:53:54 +00:00
|
|
|
func (s *Session) getConnectionStates() map[string]bool {
|
|
|
|
s.ircLock.Lock()
|
|
|
|
state := make(map[string]bool, len(s.connectionState))
|
|
|
|
|
|
|
|
for k, v := range s.connectionState {
|
|
|
|
state[k] = v
|
|
|
|
}
|
|
|
|
s.ircLock.Unlock()
|
|
|
|
|
|
|
|
return state
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) setConnectionState(server string, connected bool) {
|
|
|
|
s.ircLock.Lock()
|
|
|
|
s.connectionState[server] = connected
|
|
|
|
s.ircLock.Unlock()
|
|
|
|
}
|
|
|
|
|
2015-06-16 22:46:58 +00:00
|
|
|
func (s *Session) setWS(addr string, w *wsConn) {
|
2015-01-17 01:37:21 +00:00
|
|
|
s.wsLock.Lock()
|
2015-06-04 00:06:17 +00:00
|
|
|
s.ws[addr] = w
|
2015-01-17 01:37:21 +00:00
|
|
|
s.wsLock.Unlock()
|
2016-01-19 21:02:12 +00:00
|
|
|
|
|
|
|
s.reset <- 0
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) deleteWS(addr string) {
|
|
|
|
s.wsLock.Lock()
|
|
|
|
delete(s.ws, addr)
|
|
|
|
s.wsLock.Unlock()
|
2016-01-19 21:02:12 +00:00
|
|
|
|
|
|
|
s.resetExpirationIfEmpty()
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 01:27:30 +00:00
|
|
|
func (s *Session) numWS() int {
|
|
|
|
s.ircLock.Lock()
|
|
|
|
n := len(s.ws)
|
|
|
|
s.ircLock.Unlock()
|
|
|
|
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
2015-01-17 01:37:21 +00:00
|
|
|
func (s *Session) sendJSON(t string, v interface{}) {
|
2016-01-25 05:01:40 +00:00
|
|
|
s.broadcast <- WSResponse{t, v}
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 23:38:51 +00:00
|
|
|
func (s *Session) sendError(err error, server string) {
|
|
|
|
s.sendJSON("error", Error{
|
|
|
|
Server: server,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-05-20 21:22:56 +00:00
|
|
|
func (s *Session) sendLastMessages(server, channel string, count int) {
|
|
|
|
messages, hasMore, err := s.user.GetLastMessages(server, channel, count)
|
|
|
|
if err == nil && len(messages) > 0 {
|
|
|
|
res := Messages{
|
|
|
|
Server: server,
|
|
|
|
To: channel,
|
|
|
|
Messages: messages,
|
|
|
|
}
|
|
|
|
|
|
|
|
if hasMore {
|
|
|
|
res.Next = messages[0].ID
|
|
|
|
}
|
|
|
|
|
|
|
|
s.sendJSON("messages", res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) sendMessages(server, channel string, count int, fromID string) {
|
|
|
|
messages, hasMore, err := s.user.GetMessages(server, channel, count, fromID)
|
|
|
|
if err == nil && len(messages) > 0 {
|
|
|
|
res := Messages{
|
|
|
|
Server: server,
|
|
|
|
To: channel,
|
|
|
|
Messages: messages,
|
|
|
|
Prepend: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
if hasMore {
|
|
|
|
res.Next = messages[0].ID
|
|
|
|
}
|
|
|
|
|
|
|
|
s.sendJSON("messages", res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-28 05:20:43 +00:00
|
|
|
func (s *Session) print(a ...interface{}) {
|
|
|
|
s.sendJSON("print", Message{
|
|
|
|
Content: fmt.Sprintln(a...),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) printError(a ...interface{}) {
|
2017-04-17 20:36:37 +00:00
|
|
|
s.sendJSON("print", Message{
|
|
|
|
Content: fmt.Sprintln(a...),
|
2017-05-28 05:20:43 +00:00
|
|
|
Type: "error",
|
2017-04-06 21:26:58 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-01-19 21:02:12 +00:00
|
|
|
func (s *Session) resetExpirationIfEmpty() {
|
|
|
|
if s.numIRC() == 0 && s.numWS() == 0 {
|
|
|
|
s.reset <- AnonymousSessionExpiration
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Session) run() {
|
|
|
|
for {
|
|
|
|
select {
|
2016-01-25 05:01:40 +00:00
|
|
|
case res := <-s.broadcast:
|
2016-01-19 21:02:12 +00:00
|
|
|
s.wsLock.Lock()
|
|
|
|
for _, ws := range s.ws {
|
|
|
|
ws.out <- res
|
|
|
|
}
|
|
|
|
s.wsLock.Unlock()
|
|
|
|
|
|
|
|
case <-s.expiration.C:
|
2016-01-25 05:01:40 +00:00
|
|
|
sessions.delete(s.user.ID)
|
2016-01-19 21:02:12 +00:00
|
|
|
s.user.Remove()
|
|
|
|
return
|
|
|
|
|
|
|
|
case duration := <-s.reset:
|
|
|
|
if duration == 0 {
|
|
|
|
s.expiration.Stop()
|
|
|
|
} else {
|
|
|
|
s.expiration.Reset(duration)
|
|
|
|
}
|
2015-01-17 01:37:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-01-25 05:01:40 +00:00
|
|
|
|
|
|
|
type sessionStore struct {
|
|
|
|
sessions map[uint64]*Session
|
|
|
|
lock sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func newSessionStore() *sessionStore {
|
|
|
|
return &sessionStore{
|
|
|
|
sessions: make(map[uint64]*Session),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *sessionStore) get(userid uint64) *Session {
|
|
|
|
s.lock.Lock()
|
|
|
|
session := s.sessions[userid]
|
|
|
|
s.lock.Unlock()
|
|
|
|
return session
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *sessionStore) set(userid uint64, session *Session) {
|
|
|
|
s.lock.Lock()
|
|
|
|
s.sessions[userid] = session
|
|
|
|
s.lock.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *sessionStore) delete(userid uint64) {
|
|
|
|
s.lock.Lock()
|
|
|
|
delete(s.sessions, userid)
|
|
|
|
s.lock.Unlock()
|
|
|
|
}
|