package main import ( "net" "sync" "git.sr.ht/~runxiyu/meseircd/meselog" ) type User struct { Clients []*Client UID uint64 Nick string Ident string Gecos string Host string Caps map[string]struct{} Extra map[string]any Server *Server State ClientState } func (user *User) SendToLocalClients(msg SMsg) (numSent uint) { for _, c := range user.Clients { if c.Server != self { continue } err := c.Send(msg) if err == nil { numSent++ } } return } func (user *User) ClientSource() string { // TODO: Edge cases where these aren't available return user.Nick + "!" + user.Ident + "@" + user.Host } func (user *User) ServerSource() uint64 { return user.UID } // func (user *User) Delete() { // if client.conn != nil { // (*client.conn).Close() // } // if !cidToClient.CompareAndDelete(client.CID, client) { // meselog.Error("cid inconsistent", "cid", client.CID, "client", client) // } // if client.State >= ClientStateRegistered || client.Nick != "*" { // if !nickToClient.CompareAndDelete(client.Nick, client) { // meselog.Error("nick inconsistent", "nick", client.Nick, "client", client) // } // } // } func NewLocalUser(conn *net.Conn) (*User, error) { var uidPart uint32 { uidPartCountLock.Lock() defer uidPartCountLock.Unlock() if uidPartCount == ^uint32(0) { // UINT32_MAX return nil, ErrFullClients } uidPartCount++ uidPart = uidPartCount } client := &Client{ conn: conn, Server: self, State: ClientStatePreRegistration, Nick: "*", Caps: make(map[string]struct{}), Extra: make(map[string]any), CID: uint64(self.SID)<<32 | uint64(uidPart), } return client, nil } const ( ClientStatePreRegistration ClientState = iota ClientStateCapabilities ClientStateCapabilitiesFinished ClientStateRegistered ClientStateRemote ) var ( cidToClient = sync.Map{} nickToClient = sync.Map{} uidPartCount uint32 uidPartCountLock sync.Mutex )