237 lines
4.2 KiB
Go
237 lines
4.2 KiB
Go
|
package irc
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
type state struct {
|
||
|
client *Client
|
||
|
|
||
|
users map[string][]*User
|
||
|
topic map[string]string
|
||
|
|
||
|
userBuffers map[string][]string
|
||
|
|
||
|
motd []string
|
||
|
|
||
|
lock sync.Mutex
|
||
|
}
|
||
|
|
||
|
const userModePrefixes = "~&@%+"
|
||
|
const userModeChars = "qaohv"
|
||
|
|
||
|
type User struct {
|
||
|
nick string
|
||
|
modes string
|
||
|
prefix string
|
||
|
}
|
||
|
|
||
|
func NewUser(nick string) *User {
|
||
|
user := &User{nick: nick}
|
||
|
|
||
|
if i := strings.IndexAny(nick, userModePrefixes); i == 0 {
|
||
|
i = strings.Index(userModePrefixes, string(nick[0]))
|
||
|
user.modes = string(userModeChars[i])
|
||
|
user.nick = nick[1:]
|
||
|
user.updatePrefix()
|
||
|
}
|
||
|
|
||
|
return user
|
||
|
}
|
||
|
|
||
|
func (u *User) String() string {
|
||
|
return u.prefix + u.nick
|
||
|
}
|
||
|
|
||
|
func (u *User) AddModes(modes string) {
|
||
|
for _, mode := range modes {
|
||
|
if strings.Contains(u.modes, string(mode)) {
|
||
|
continue
|
||
|
}
|
||
|
u.modes += string(mode)
|
||
|
}
|
||
|
u.updatePrefix()
|
||
|
}
|
||
|
|
||
|
func (u *User) RemoveModes(modes string) {
|
||
|
for _, mode := range modes {
|
||
|
u.modes = strings.Replace(u.modes, string(mode), "", 1)
|
||
|
}
|
||
|
u.updatePrefix()
|
||
|
}
|
||
|
|
||
|
func (u *User) updatePrefix() {
|
||
|
for i, mode := range userModeChars {
|
||
|
if strings.Contains(u.modes, string(mode)) {
|
||
|
u.prefix = string(userModePrefixes[i])
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
u.prefix = ""
|
||
|
}
|
||
|
|
||
|
func newState(client *Client) *state {
|
||
|
return &state{
|
||
|
client: client,
|
||
|
users: make(map[string][]*User),
|
||
|
topic: make(map[string]string),
|
||
|
userBuffers: make(map[string][]string),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *state) reset() {
|
||
|
s.lock.Lock()
|
||
|
s.users = make(map[string][]*User)
|
||
|
s.topic = make(map[string]string)
|
||
|
s.userBuffers = make(map[string][]string)
|
||
|
s.motd = []string{}
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) removeChannel(channel string) {
|
||
|
s.lock.Lock()
|
||
|
delete(s.users, channel)
|
||
|
delete(s.topic, channel)
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) getUsers(channel string) []string {
|
||
|
s.lock.Lock()
|
||
|
|
||
|
users := make([]string, len(s.users[channel]))
|
||
|
for i, user := range s.users[channel] {
|
||
|
users[i] = user.String()
|
||
|
}
|
||
|
|
||
|
s.lock.Unlock()
|
||
|
|
||
|
return users
|
||
|
}
|
||
|
|
||
|
func (s *state) setUsers(users []string, channel string) {
|
||
|
s.lock.Lock()
|
||
|
|
||
|
s.users[channel] = make([]*User, len(users))
|
||
|
for i, nick := range users {
|
||
|
s.users[channel][i] = NewUser(nick)
|
||
|
}
|
||
|
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) addUser(user, channel string) {
|
||
|
s.lock.Lock()
|
||
|
|
||
|
if users, ok := s.users[channel]; ok {
|
||
|
for _, u := range users {
|
||
|
if u.nick == user {
|
||
|
s.lock.Unlock()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s.users[channel] = append(users, NewUser(user))
|
||
|
} else {
|
||
|
s.users[channel] = []*User{NewUser(user)}
|
||
|
}
|
||
|
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) removeUser(user, channel string) {
|
||
|
s.lock.Lock()
|
||
|
s.internalRemoveUser(user, channel)
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) removeUserAll(user string) []string {
|
||
|
channels := []string{}
|
||
|
s.lock.Lock()
|
||
|
|
||
|
for channel := range s.users {
|
||
|
if s.internalRemoveUser(user, channel) {
|
||
|
channels = append(channels, channel)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s.lock.Unlock()
|
||
|
return channels
|
||
|
}
|
||
|
|
||
|
func (s *state) renameUser(oldNick, newNick string) []string {
|
||
|
s.lock.Lock()
|
||
|
channels := s.renameAll(oldNick, newNick)
|
||
|
s.lock.Unlock()
|
||
|
return channels
|
||
|
}
|
||
|
|
||
|
func (s *state) setMode(channel, user, add, remove string) {
|
||
|
s.lock.Lock()
|
||
|
|
||
|
for _, u := range s.users[channel] {
|
||
|
if u.nick == user {
|
||
|
u.AddModes(add)
|
||
|
u.RemoveModes(remove)
|
||
|
|
||
|
s.lock.Unlock()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) getTopic(channel string) string {
|
||
|
s.lock.Lock()
|
||
|
topic := s.topic[channel]
|
||
|
s.lock.Unlock()
|
||
|
return topic
|
||
|
}
|
||
|
|
||
|
func (s *state) setTopic(topic, channel string) {
|
||
|
s.lock.Lock()
|
||
|
s.topic[channel] = topic
|
||
|
s.lock.Unlock()
|
||
|
}
|
||
|
|
||
|
func (s *state) getMOTD() []string {
|
||
|
s.lock.Lock()
|
||
|
motd := s.motd
|
||
|
s.lock.Unlock()
|
||
|
return motd
|
||
|
}
|
||
|
|
||
|
func (s *state) rename(channel, oldNick, newNick string) bool {
|
||
|
for _, user := range s.users[channel] {
|
||
|
if user.nick == oldNick {
|
||
|
user.nick = newNick
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (s *state) renameAll(oldNick, newNick string) []string {
|
||
|
channels := []string{}
|
||
|
|
||
|
for channel := range s.users {
|
||
|
if s.rename(channel, oldNick, newNick) {
|
||
|
channels = append(channels, channel)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return channels
|
||
|
}
|
||
|
|
||
|
func (s *state) internalRemoveUser(user, channel string) bool {
|
||
|
for i, u := range s.users[channel] {
|
||
|
if u.nick == user {
|
||
|
users := s.users[channel]
|
||
|
s.users[channel] = append(users[:i], users[i+1:]...)
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|