mirror of
https://github.com/ergochat/ergo.git
synced 2025-02-17 14:10:39 +01:00
parent
72959eb1cf
commit
28f79f57b2
@ -15,6 +15,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
ident "github.com/ergochat/go-ident"
|
ident "github.com/ergochat/go-ident"
|
||||||
"github.com/ergochat/irc-go/ircfmt"
|
"github.com/ergochat/irc-go/ircfmt"
|
||||||
@ -104,7 +105,7 @@ type Client struct {
|
|||||||
registrationTimer *time.Timer
|
registrationTimer *time.Timer
|
||||||
server *Server
|
server *Server
|
||||||
skeleton string
|
skeleton string
|
||||||
sessions []*Session
|
sessions unsafe.Pointer
|
||||||
stateMutex sync.RWMutex // tier 1
|
stateMutex sync.RWMutex // tier 1
|
||||||
alwaysOn bool
|
alwaysOn bool
|
||||||
username string
|
username string
|
||||||
@ -360,7 +361,7 @@ func (server *Server) RunClient(conn IRCConn) {
|
|||||||
isTor: wConn.Config.Tor,
|
isTor: wConn.Config.Tor,
|
||||||
hideSTS: wConn.Config.Tor || wConn.Config.HideSTS,
|
hideSTS: wConn.Config.Tor || wConn.Config.HideSTS,
|
||||||
}
|
}
|
||||||
client.sessions = []*Session{session}
|
client.setSessions([]*Session{session})
|
||||||
|
|
||||||
session.resetFakelag()
|
session.resetFakelag()
|
||||||
|
|
||||||
@ -1018,9 +1019,7 @@ func (client *Client) FriendsMonitors(capabs ...caps.Capability) (result map[*Se
|
|||||||
|
|
||||||
// helper for Friends
|
// helper for Friends
|
||||||
func addFriendsToSet(set map[*Session]empty, client *Client, capabs ...caps.Capability) {
|
func addFriendsToSet(set map[*Session]empty, client *Client, capabs ...caps.Capability) {
|
||||||
client.stateMutex.RLock()
|
for _, session := range client.Sessions() {
|
||||||
defer client.stateMutex.RUnlock()
|
|
||||||
for _, session := range client.sessions {
|
|
||||||
if session.capabilities.HasAll(capabs...) {
|
if session.capabilities.HasAll(capabs...) {
|
||||||
set[session] = empty{}
|
set[session] = empty{}
|
||||||
}
|
}
|
||||||
@ -1174,7 +1173,7 @@ func (client *Client) Quit(message string, session *Session) {
|
|||||||
if session != nil {
|
if session != nil {
|
||||||
sessions = []*Session{session}
|
sessions = []*Session{session}
|
||||||
} else {
|
} else {
|
||||||
sessions = client.sessions
|
sessions = client.Sessions()
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, session := range sessions {
|
for _, session := range sessions {
|
||||||
@ -1213,8 +1212,8 @@ func (client *Client) destroy(session *Session) {
|
|||||||
|
|
||||||
var remainingSessions int
|
var remainingSessions int
|
||||||
if session == nil {
|
if session == nil {
|
||||||
sessionsToDestroy = client.sessions
|
sessionsToDestroy = client.Sessions()
|
||||||
client.sessions = nil
|
client.setSessions(nil)
|
||||||
remainingSessions = 0
|
remainingSessions = 0
|
||||||
} else {
|
} else {
|
||||||
sessionRemoved, remainingSessions = client.removeSession(session)
|
sessionRemoved, remainingSessions = client.removeSession(session)
|
||||||
@ -1241,7 +1240,7 @@ func (client *Client) destroy(session *Session) {
|
|||||||
shouldDestroy := !client.destroyed && remainingSessions == 0 && !alwaysOn
|
shouldDestroy := !client.destroyed && remainingSessions == 0 && !alwaysOn
|
||||||
// decrement stats on a true destroy, or for the removal of the last connected session
|
// decrement stats on a true destroy, or for the removal of the last connected session
|
||||||
// of an always-on client
|
// of an always-on client
|
||||||
shouldDecrement := shouldDestroy || (alwaysOn && len(sessionsToDestroy) != 0 && len(client.sessions) == 0)
|
shouldDecrement := shouldDestroy || (alwaysOn && len(sessionsToDestroy) != 0 && len(client.Sessions()) == 0)
|
||||||
if shouldDestroy {
|
if shouldDestroy {
|
||||||
// if it's our job to destroy it, don't let anyone else try
|
// if it's our job to destroy it, don't let anyone else try
|
||||||
client.destroyed = true
|
client.destroyed = true
|
||||||
|
@ -48,10 +48,11 @@ func (server *Server) SetDefcon(defcon uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Sessions() (sessions []*Session) {
|
func (client *Client) Sessions() (sessions []*Session) {
|
||||||
client.stateMutex.RLock()
|
ptr := atomic.LoadPointer(&client.sessions)
|
||||||
sessions = client.sessions
|
if ptr == nil {
|
||||||
client.stateMutex.RUnlock()
|
return nil
|
||||||
return
|
}
|
||||||
|
return *((*[]*Session)(ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionData struct {
|
type SessionData struct {
|
||||||
@ -67,12 +68,14 @@ type SessionData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) AllSessionData(currentSession *Session, hasPrivs bool) (data []SessionData, currentIndex int) {
|
func (client *Client) AllSessionData(currentSession *Session, hasPrivs bool) (data []SessionData, currentIndex int) {
|
||||||
currentIndex = -1
|
|
||||||
client.stateMutex.RLock()
|
client.stateMutex.RLock()
|
||||||
defer client.stateMutex.RUnlock()
|
defer client.stateMutex.RUnlock()
|
||||||
|
|
||||||
data = make([]SessionData, len(client.sessions))
|
currentIndex = -1
|
||||||
for i, session := range client.sessions {
|
sessions := client.Sessions()
|
||||||
|
|
||||||
|
data = make([]SessionData, len(sessions))
|
||||||
|
for i, session := range sessions {
|
||||||
if session == currentSession {
|
if session == currentSession {
|
||||||
currentIndex = i
|
currentIndex = i
|
||||||
}
|
}
|
||||||
@ -107,40 +110,49 @@ func (client *Client) AddSession(session *Session) (success bool, numSessions in
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// success, attach the new session to the client
|
// success, attach the new session to the client
|
||||||
|
sessions := client.Sessions()
|
||||||
session.client = client
|
session.client = client
|
||||||
session.sessionID = client.nextSessionID
|
session.sessionID = client.nextSessionID
|
||||||
client.nextSessionID++
|
client.nextSessionID++
|
||||||
newSessions := make([]*Session, len(client.sessions)+1)
|
newSessions := make([]*Session, len(sessions)+1)
|
||||||
copy(newSessions, client.sessions)
|
copy(newSessions, sessions)
|
||||||
newSessions[len(newSessions)-1] = session
|
newSessions[len(newSessions)-1] = session
|
||||||
if client.accountSettings.AutoreplayMissed || session.deviceID != "" {
|
if client.accountSettings.AutoreplayMissed || session.deviceID != "" {
|
||||||
lastSeen = client.lastSeen[session.deviceID]
|
lastSeen = client.lastSeen[session.deviceID]
|
||||||
client.setLastSeen(time.Now().UTC(), session.deviceID)
|
client.setLastSeen(time.Now().UTC(), session.deviceID)
|
||||||
}
|
}
|
||||||
client.sessions = newSessions
|
client.setSessions(newSessions)
|
||||||
// TODO(#1551) there should be a cap to opt out of this behavior on a session
|
// TODO(#1551) there should be a cap to opt out of this behavior on a session
|
||||||
if persistenceEnabled(config.Accounts.Multiclient.AutoAway, client.accountSettings.AutoAway) {
|
if persistenceEnabled(config.Accounts.Multiclient.AutoAway, client.accountSettings.AutoAway) {
|
||||||
client.awayMessage = ""
|
client.awayMessage = ""
|
||||||
if len(client.sessions) == 1 {
|
if len(newSessions) == 1 {
|
||||||
back = true
|
back = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true, len(client.sessions), lastSeen, back
|
return true, len(newSessions), lastSeen, back
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) setSessions(sessions []*Session) {
|
||||||
|
// must be called while holding stateMutex.Lock()
|
||||||
|
sessionsPtr := new([]*Session)
|
||||||
|
(*sessionsPtr) = sessions
|
||||||
|
atomic.StorePointer(&client.sessions, unsafe.Pointer(sessionsPtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) removeSession(session *Session) (success bool, length int) {
|
func (client *Client) removeSession(session *Session) (success bool, length int) {
|
||||||
if len(client.sessions) == 0 {
|
oldSessions := client.Sessions()
|
||||||
|
if len(oldSessions) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sessions := make([]*Session, 0, len(client.sessions)-1)
|
sessions := make([]*Session, 0, len(oldSessions)-1)
|
||||||
for _, currentSession := range client.sessions {
|
for _, currentSession := range oldSessions {
|
||||||
if session == currentSession {
|
if session == currentSession {
|
||||||
success = true
|
success = true
|
||||||
} else {
|
} else {
|
||||||
sessions = append(sessions, currentSession)
|
sessions = append(sessions, currentSession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.sessions = sessions
|
client.setSessions(sessions)
|
||||||
length = len(sessions)
|
length = len(sessions)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -150,7 +162,7 @@ func (client *Client) getWhoisActually() (ip net.IP, hostname string) {
|
|||||||
client.stateMutex.RLock()
|
client.stateMutex.RLock()
|
||||||
defer client.stateMutex.RUnlock()
|
defer client.stateMutex.RUnlock()
|
||||||
|
|
||||||
for _, session := range client.sessions {
|
for _, session := range client.Sessions() {
|
||||||
return session.IP(), session.rawHostname
|
return session.IP(), session.rawHostname
|
||||||
}
|
}
|
||||||
return utils.IPv4LoopbackAddress, client.server.name
|
return utils.IPv4LoopbackAddress, client.server.name
|
||||||
@ -223,7 +235,7 @@ func (client *Client) setAutoAwayNoMutex(config *Config) {
|
|||||||
// aggregate the away statuses of the individual sessions:
|
// aggregate the away statuses of the individual sessions:
|
||||||
var globalAwayState string
|
var globalAwayState string
|
||||||
var awaySetAt time.Time
|
var awaySetAt time.Time
|
||||||
for _, cSession := range client.sessions {
|
for _, cSession := range client.Sessions() {
|
||||||
if cSession.awayMessage == "" {
|
if cSession.awayMessage == "" {
|
||||||
// a session is active, we are not auto-away
|
// a session is active, we are not auto-away
|
||||||
client.awayMessage = ""
|
client.awayMessage = ""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user