diff options
Diffstat (limited to 'hotline/client_conn.go')
| -rw-r--r-- | hotline/client_conn.go | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/hotline/client_conn.go b/hotline/client_conn.go index 3419e0a..fe4dc72 100644 --- a/hotline/client_conn.go +++ b/hotline/client_conn.go @@ -32,13 +32,13 @@ type ClientConn struct { ID ClientID Version []byte // TODO: make fixed size of 2 - Account *Account - Server *Server // TODO: consider adding methods to interact with server + Server *Server // TODO: consider adding methods to interact with server // The following fields hold mutable session state guarded by mu. They are read and written // by multiple goroutines (the client's own transaction loop, other clients' handlers, and the // server keepalive loop), so production code must use the accessor methods below. Direct // field access is only safe before the connection is shared, e.g. in tests. + Account *Account Flags UserFlags UserName []byte Icon []byte // TODO: make fixed size of 2 @@ -197,6 +197,45 @@ func (cc *ClientConn) GetAutoReply() []byte { return cc.AutoReply } +// SetAccount attaches the authenticated account to the client. +func (cc *ClientConn) SetAccount(account *Account) { + cc.mu.Lock() + defer cc.mu.Unlock() + + cc.Account = account +} + +// GetAccount returns the client's account, or nil before login completes. Every account field +// except Access is immutable after login, so callers may read them from the returned struct; +// Access must be read via Authorize or AccessBytes because SetAccountAccess mutates it. +func (cc *ClientConn) GetAccount() *Account { + cc.mu.RLock() + defer cc.mu.RUnlock() + + return cc.Account +} + +// SetAccountAccess replaces the access bitmap on the client's account. +func (cc *ClientConn) SetAccountAccess(access AccessBitmap) { + cc.mu.Lock() + defer cc.mu.Unlock() + + cc.Account.Access = access +} + +// AccessBytes returns a copy of the account's access bitmap, suitable for use as a transaction +// field. It returns nil before login completes. +func (cc *ClientConn) AccessBytes() []byte { + cc.mu.RLock() + defer cc.mu.RUnlock() + + if cc.Account == nil { + return nil + } + access := cc.Account.Access + return access[:] +} + // incrementIdleTime adds interval seconds to the client's idle time. It returns true if this // crossed the idle threshold and marked the client as away, in which case the caller should // notify other clients of the change. @@ -227,8 +266,8 @@ func (cc *ClientConn) clearIdleAndAway() bool { } func (cc *ClientConn) FileRoot() string { - if cc.Account.FileRoot != "" { - return cc.Account.FileRoot + if account := cc.GetAccount(); account != nil && account.FileRoot != "" { + return account.FileRoot } return cc.Server.Config.FileRoot } @@ -331,6 +370,9 @@ func (cc *ClientConn) Authenticate(login string, password []byte) bool { // Authorize checks if the user account has the specified permission func (cc *ClientConn) Authorize(access int) bool { + cc.mu.RLock() + defer cc.mu.RUnlock() + if cc.Account == nil { return false } @@ -424,11 +466,12 @@ func formatDownloadList(fts []FileTransfer) (s string) { } func (cc *ClientConn) String() string { + account := cc.GetAccount() template := fmt.Sprintf( userInfoTemplate, cc.GetUserName(), - cc.Account.Name, - cc.Account.Login, + account.Name, + account.Login, cc.RemoteAddr, formatDownloadList(cc.ClientFileTransferMgr.Get(FileDownload)), formatDownloadList(cc.ClientFileTransferMgr.Get(FolderDownload)), |