Fix race condition
This commit is contained in:
parent
633a5dea16
commit
568e9652da
15
builtin.go
15
builtin.go
|
@ -177,7 +177,7 @@ func handleJOIN(c *Client, e Event) {
|
|||
|
||||
defer c.state.notify(c, UPDATE_STATE)
|
||||
|
||||
channel.addUser(user.Nick, user)
|
||||
channel.addUser(user.Nick.Load().(string), user)
|
||||
user.addChannel(channel.Name, channel)
|
||||
|
||||
// Assume extended-join (ircv3).
|
||||
|
@ -345,8 +345,17 @@ func handleWHO(c *Client, e Event) {
|
|||
}
|
||||
|
||||
user.Host = host
|
||||
user.Ident = ident
|
||||
user.Mask = user.Nick + "!" + user.Ident + "@" + user.Host
|
||||
user.Ident.Store(ident)
|
||||
|
||||
str := strs.Get()
|
||||
str.MustWriteString(user.Nick.Load().(string))
|
||||
str.MustWriteString("!")
|
||||
str.MustWriteString(user.Ident.Load().(string))
|
||||
str.MustWriteString("@")
|
||||
str.MustWriteString(user.Host)
|
||||
user.Mask.Store(str.String())
|
||||
strs.MustPut(str)
|
||||
|
||||
user.Extras.Name = realname
|
||||
|
||||
if account != "0" {
|
||||
|
|
2
cap.go
2
cap.go
|
@ -307,7 +307,7 @@ func handleCHGHOST(c *Client, e Event) {
|
|||
|
||||
user := c.state.lookupUser(e.Source.Name)
|
||||
if user != nil {
|
||||
user.Ident = e.Params[0]
|
||||
user.Ident.Store(e.Params[0])
|
||||
user.Host = e.Params[1]
|
||||
}
|
||||
|
||||
|
|
|
@ -646,7 +646,7 @@ func (c *Client) UserList() []string {
|
|||
if usr.Stale {
|
||||
continue
|
||||
}
|
||||
users = append(users, usr.Nick)
|
||||
users = append(users, usr.Nick.Load().(string))
|
||||
}
|
||||
|
||||
sort.Strings(users)
|
||||
|
@ -665,7 +665,7 @@ func (c *Client) Users() []*User {
|
|||
}
|
||||
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
return users[i].Nick < users[j].Nick
|
||||
return users[i].Nick.Load().(string) < users[j].Nick.Load().(string)
|
||||
})
|
||||
return users
|
||||
}
|
||||
|
|
|
@ -225,11 +225,7 @@ func (c *Caller) exec(command string, bg bool, client *Client, event *Event) {
|
|||
if (strings.HasSuffix(cuid, ":bg") && !bg) || (!strings.HasSuffix(cuid, ":bg") && bg) {
|
||||
continue
|
||||
}
|
||||
hi, _ := hmap.Get(cuid)
|
||||
hndlr, ok := hi.(Handler)
|
||||
if !ok {
|
||||
panic("improper handler type in map")
|
||||
}
|
||||
hndlr, _ := hmap.Get(cuid)
|
||||
stack = append(stack, execStack{hndlr, cuid})
|
||||
}
|
||||
}
|
||||
|
|
16
state.go
16
state.go
|
@ -92,11 +92,11 @@ func (s *state) reset(initial bool) {
|
|||
// User represents an IRC user and the state attached to them.
|
||||
type User struct {
|
||||
// Nick is the users current nickname. rfc1459 compliant.
|
||||
Nick string `json:"nick"`
|
||||
Nick *MarshalableAtomicValue `json:"nick"`
|
||||
// Ident is the users username/ident. Ident is commonly prefixed with a
|
||||
// "~", which indicates that they do not have a identd server setup for
|
||||
// authentication.
|
||||
Ident string `json:"ident"`
|
||||
Ident *MarshalableAtomicValue `json:"ident"`
|
||||
// Host is the visible host of the users connection that the server has
|
||||
// provided to us for their connection. May not always be accurate due to
|
||||
// many networks spoofing/hiding parts of the hostname for privacy
|
||||
|
@ -104,7 +104,7 @@ type User struct {
|
|||
Host string `json:"host"`
|
||||
|
||||
// Mask is the combined Nick!Ident@Host of the given user.
|
||||
Mask string `json:"mask"`
|
||||
Mask *MarshalableAtomicValue `json:"mask"`
|
||||
|
||||
// Network is the name of the IRC network where this user was found.
|
||||
// This has been added for the purposes of girc being used in multi-client scenarios with data persistence.
|
||||
|
@ -366,7 +366,7 @@ func (ch *Channel) Copy() *Channel {
|
|||
*nc = *ch
|
||||
|
||||
for v := range ch.UserList.IterBuffered() {
|
||||
nc.UserList.Set(v.Val.Nick, v.Val)
|
||||
nc.UserList.Set(v.Val.Nick.Load().(string), v.Val)
|
||||
}
|
||||
|
||||
// And modes.
|
||||
|
@ -466,10 +466,10 @@ func (s *state) createUser(src *Source) (u *User, ok bool) {
|
|||
mask.MustWriteString(src.Host)
|
||||
|
||||
u = &User{
|
||||
Nick: src.Name,
|
||||
Nick: NewAtomicString(src.Name),
|
||||
Host: src.Host,
|
||||
Ident: src.Ident,
|
||||
Mask: mask.String(),
|
||||
Ident: NewAtomicString(src.Ident),
|
||||
Mask: NewAtomicString(mask.String()),
|
||||
ChannelList: cmap.New[*Channel](),
|
||||
FirstSeen: time.Now(),
|
||||
LastActive: time.Now(),
|
||||
|
@ -532,7 +532,7 @@ func (s *state) renameUser(from, to string) {
|
|||
user = old
|
||||
}
|
||||
|
||||
user.Nick = to
|
||||
user.Nick.Store(to)
|
||||
user.LastActive = time.Now()
|
||||
s.users.Set(ToRFC1459(to), user)
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ func TestState(t *testing.T) {
|
|||
|
||||
fullUsers := c.Users()
|
||||
for i := 0; i < len(fullUsers); i++ {
|
||||
if fullUsers[i].Nick != users[i] {
|
||||
if fullUsers[i].Nick.Load().(string) != users[i] {
|
||||
t.Errorf("fullUsers nick doesn't map to same nick in UsersList: %q :: %#v", fullUsers[i].Nick, users)
|
||||
return
|
||||
}
|
||||
|
@ -138,12 +138,12 @@ func TestState(t *testing.T) {
|
|||
adm := ch.Admins(c)
|
||||
var admList []string
|
||||
for i := 0; i < len(adm); i++ {
|
||||
admList = append(admList, adm[i].Nick)
|
||||
admList = append(admList, adm[i].Nick.Load().(string))
|
||||
}
|
||||
trusted := ch.Trusted(c)
|
||||
var trustedList []string
|
||||
for i := 0; i < len(trusted); i++ {
|
||||
trustedList = append(trustedList, trusted[i].Nick)
|
||||
trustedList = append(trustedList, trusted[i].Nick.Load().(string))
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(admList, []string{"nick2"}) {
|
||||
|
@ -213,7 +213,7 @@ func TestState(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
if user.Nick != "fhjones" {
|
||||
if user.Nick.Load().(string) != "fhjones" {
|
||||
t.Errorf("User.Nick == %q, wanted \"nick\"", user.Nick)
|
||||
return
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ func TestState(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
if user.Ident != "~user" {
|
||||
if user.Ident.Load().(string) != "~user" {
|
||||
t.Errorf("User.Ident == %q, wanted \"~user\"", user.Ident)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package girc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type MarshalableAtomicValue struct {
|
||||
*atomic.Value
|
||||
}
|
||||
|
||||
func (m *MarshalableAtomicValue) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%v", m.Value.Load())), nil
|
||||
}
|
||||
|
||||
func (m *MarshalableAtomicValue) UnmarshalJSON(b []byte) error {
|
||||
m.Value.Store(string(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MarshalableAtomicValue) String() string {
|
||||
return m.Value.Load().(string)
|
||||
}
|
||||
|
||||
func NewAtomicString(s string) *MarshalableAtomicValue {
|
||||
obj := &atomic.Value{}
|
||||
obj.Store(s)
|
||||
return &MarshalableAtomicValue{Value: obj}
|
||||
}
|
Loading…
Reference in New Issue