From 7f101f36565433bb97c5e3aeba506af1bd2709b0 Mon Sep 17 00:00:00 2001 From: "kayos@tcp.direct" Date: Sun, 17 Oct 2021 17:16:59 -0700 Subject: [PATCH] More: hellfire --- builtin.go | 6 ++++-- client.go | 17 +++++++++++++---- conn.go | 3 ++- modes.go | 14 ++++++++++---- state.go | 4 ++-- 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/builtin.go b/builtin.go index ec80a15..abbb314 100644 --- a/builtin.go +++ b/builtin.go @@ -484,13 +484,15 @@ func handleISUPPORT(c *Client, e Event) { j := strings.IndexByte(e.Params[i], '=') if j < 1 || (j+1) == len(e.Params[i]) { - c.state.serverOptions[e.Params[i]] = "" + opt := c.state.serverOptions[e.Params[i]] + opt.Store("") continue } name := e.Params[i][0:j] val := e.Params[i][j+1:] - c.state.serverOptions[name] = val + opt := c.state.serverOptions[name] + opt.Store(val) } c.state.Unlock() diff --git a/client.go b/client.go index c2c7f94..0da2575 100644 --- a/client.go +++ b/client.go @@ -19,6 +19,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" ) @@ -678,10 +679,12 @@ func (c *Client) IsInChannel(channel string) (in bool) { // func (c *Client) GetServerOption(key string) (result string, ok bool) { c.panicIfNotTracking() + var opt atomic.Value + + if opt, ok = c.state.serverOptions[key]; ok { + result = opt.Load().(string) + } - c.state.RLock() - result, ok = c.state.serverOptions[key] - c.state.RUnlock() return result, ok } @@ -693,7 +696,13 @@ func (c *Client) GetAllServerOption() (map[string]string, error) { c.state.RLock() defer c.state.RUnlock() if len(c.state.serverOptions) > 0 { - return c.state.serverOptions, nil + copied := make(map[string]string) + for k, av := range c.state.serverOptions { + if v := av.Load(); v != nil { + copied[k] = av.Load().(string) + } + } + return copied, nil } else { return nil, errors.New("server options is empty") } diff --git a/conn.go b/conn.go index 90040e6..5421a77 100644 --- a/conn.go +++ b/conn.go @@ -428,13 +428,14 @@ func (c *Client) readLoop(ctx context.Context, errs chan error, wg *sync.WaitGro func (c *Client) Send(event *Event) { var delay time.Duration + event.Network = c.NetworkName() + for atomic.CompareAndSwapUint32(&c.atom, stateUnlocked, stateLocked) { randSleep() } defer atomic.StoreUint32(&c.atom, stateUnlocked) if !c.Config.AllowFlood { - // Drop the event early as we're disconnected, this way we don't have to wait // the (potentially long) rate limit delay before dropping. if c.conn == nil { diff --git a/modes.go b/modes.go index 5335730..1bb9cb0 100644 --- a/modes.go +++ b/modes.go @@ -370,8 +370,11 @@ func handleMODE(c *Client, e Event) { // chanModes returns the ISUPPORT list of server-supported channel modes, // alternatively falling back to ModeDefaults. func (s *state) chanModes() string { - if modes, ok := s.serverOptions["CHANMODES"]; ok && IsValidChannelMode(modes) { - return modes + if validmodes, ok := s.serverOptions["CHANMODES"]; ok { + modes := validmodes.Load().(string) + if IsValidChannelMode(modes) { + return modes + } } return ModeDefaults @@ -381,8 +384,11 @@ func (s *state) chanModes() string { // This includes mode characters, as well as user prefix symbols. Falls back // to DefaultPrefixes if not server-supported. func (s *state) userPrefixes() string { - if prefix, ok := s.serverOptions["PREFIX"]; ok && isValidUserPrefix(prefix) { - return prefix + if atomicprefix, ok := s.serverOptions["PREFIX"]; ok { + prefix := atomicprefix.Load().(string) + if isValidUserPrefix(prefix) { + return prefix + } } return DefaultPrefixes diff --git a/state.go b/state.go index 275ade6..4d652a1 100644 --- a/state.go +++ b/state.go @@ -32,7 +32,7 @@ type state struct { // serverOptions are the standard capabilities and configurations // supported by the server at connection time. This also includes // RPL_ISUPPORT entries. - serverOptions map[string]string + serverOptions map[string]atomic.Value // motd is the servers message of the day. motd string @@ -52,7 +52,7 @@ func (s *state) reset(initial bool) { s.host.Store("") s.channels = make(map[string]*Channel) s.users = make(map[string]*User) - s.serverOptions = make(map[string]string) + s.serverOptions = make(map[string]atomic.Value) s.enabledCap = make(map[string]map[string]string) s.tmpCap = make(map[string]map[string]string) s.motd = ""