Fixes by Gunnar
This commit is contained in:
parent
2d71da2234
commit
a9a5b17ce4
14
client.go
14
client.go
@ -49,6 +49,7 @@ type Client struct {
|
|||||||
sendTimestamp time.Time
|
sendTimestamp time.Time
|
||||||
outBuf chan *string
|
outBuf chan *string
|
||||||
alive bool
|
alive bool
|
||||||
|
quitMsg *string
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,13 +68,19 @@ func (c *Client) String() string {
|
|||||||
return *c.nickname + "!" + *c.username + "@" + c.Host()
|
return *c.nickname + "!" + *c.username + "@" + c.Host()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Match(other string) bool {
|
||||||
|
return strings.ToLower(*c.nickname) == strings.ToLower(other)
|
||||||
|
}
|
||||||
|
|
||||||
func NewClient(conn *proxyproto.Conn) *Client {
|
func NewClient(conn *proxyproto.Conn) *Client {
|
||||||
nickname := "*"
|
nickname := "*"
|
||||||
username := ""
|
username := ""
|
||||||
|
realname := ""
|
||||||
c := Client{
|
c := Client{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
nickname: &nickname,
|
nickname: &nickname,
|
||||||
username: &username,
|
username: &username,
|
||||||
|
realname: &realname,
|
||||||
recvTimestamp: time.Now(),
|
recvTimestamp: time.Now(),
|
||||||
sendTimestamp: time.Now(),
|
sendTimestamp: time.Now(),
|
||||||
alive: true,
|
alive: true,
|
||||||
@ -88,9 +95,10 @@ func (c *Client) SetDead() {
|
|||||||
c.alive = false
|
c.alive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Close() {
|
func (c *Client) Close(text string) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
if c.alive {
|
if c.alive {
|
||||||
|
c.quitMsg = &text
|
||||||
c.SetDead()
|
c.SetDead()
|
||||||
}
|
}
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
@ -127,8 +135,8 @@ func (c *Client) Processor(sink chan ClientEvent) {
|
|||||||
prev -= (i + 2)
|
prev -= (i + 2)
|
||||||
goto CheckMore
|
goto CheckMore
|
||||||
}
|
}
|
||||||
c.Close()
|
c.Close("error")
|
||||||
sink <- ClientEvent{c, EventDel, ""}
|
sink <- ClientEvent{c, EventDel, *c.quitMsg}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) MsgSender() {
|
func (c *Client) MsgSender() {
|
||||||
|
155
daemon.go
155
daemon.go
@ -38,7 +38,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
RENickname = regexp.MustCompile("^[a-zA-Z0-9-]{1,24}$")
|
RENickname = regexp.MustCompile("^[^\\x00\\x0D\\x0A\\x20\\x3A]{1,64}$") // any octet except NUL, CR, LF, " " and ":"
|
||||||
|
|
||||||
clients map[*Client]struct{} = make(map[*Client]struct{})
|
clients map[*Client]struct{} = make(map[*Client]struct{})
|
||||||
clientsM sync.RWMutex
|
clientsM sync.RWMutex
|
||||||
@ -48,6 +48,18 @@ var (
|
|||||||
roomSinks map[*Room]chan ClientEvent = make(map[*Room]chan ClientEvent)
|
roomSinks map[*Room]chan ClientEvent = make(map[*Room]chan ClientEvent)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetRoom(name string) (r *Room, found bool) {
|
||||||
|
var room string
|
||||||
|
if strings.HasPrefix(name, "#") {
|
||||||
|
room = strings.ToLower(name)
|
||||||
|
} else {
|
||||||
|
room = "#" + strings.ToLower(name)
|
||||||
|
}
|
||||||
|
r, found = rooms[room]
|
||||||
|
|
||||||
|
return r, found
|
||||||
|
}
|
||||||
|
|
||||||
func SendLusers(client *Client) {
|
func SendLusers(client *Client) {
|
||||||
lusers := 0
|
lusers := 0
|
||||||
clientsM.RLock()
|
clientsM.RLock()
|
||||||
@ -86,11 +98,9 @@ func SendWhois(client *Client, nicknames []string) {
|
|||||||
var room *Room
|
var room *Room
|
||||||
var subscriber *Client
|
var subscriber *Client
|
||||||
for _, nickname := range nicknames {
|
for _, nickname := range nicknames {
|
||||||
nickname = strings.ToLower(nickname)
|
|
||||||
clientsM.RLock()
|
clientsM.RLock()
|
||||||
for c = range clients {
|
for c = range clients {
|
||||||
if strings.ToLower(*c.nickname) == nickname {
|
if c.Match(nickname) {
|
||||||
clientsM.RUnlock()
|
|
||||||
goto Found
|
goto Found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,7 +122,7 @@ func SendWhois(client *Client, nicknames []string) {
|
|||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
for _, room = range rooms {
|
for _, room = range rooms {
|
||||||
for subscriber = range room.members {
|
for subscriber = range room.members {
|
||||||
if *subscriber.nickname == nickname {
|
if subscriber.Match(nickname) {
|
||||||
subscriptions = append(subscriptions, *room.name)
|
subscriptions = append(subscriptions, *room.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,6 +131,7 @@ func SendWhois(client *Client, nicknames []string) {
|
|||||||
sort.Strings(subscriptions)
|
sort.Strings(subscriptions)
|
||||||
client.ReplyNicknamed("319", *c.nickname, strings.Join(subscriptions, " "))
|
client.ReplyNicknamed("319", *c.nickname, strings.Join(subscriptions, " "))
|
||||||
client.ReplyNicknamed("318", *c.nickname, "End of /WHOIS list")
|
client.ReplyNicknamed("318", *c.nickname, "End of /WHOIS list")
|
||||||
|
clientsM.RUnlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +156,7 @@ func SendList(client *Client, cols []string) {
|
|||||||
if room, found = rooms[r]; found {
|
if room, found = rooms[r]; found {
|
||||||
client.ReplyNicknamed(
|
client.ReplyNicknamed(
|
||||||
"322",
|
"322",
|
||||||
r,
|
*room.name,
|
||||||
fmt.Sprintf("%d", len(room.members)),
|
fmt.Sprintf("%d", len(room.members)),
|
||||||
*room.topic,
|
*room.topic,
|
||||||
)
|
)
|
||||||
@ -155,6 +166,54 @@ func SendList(client *Client, cols []string) {
|
|||||||
client.ReplyNicknamed("323", "End of /LIST")
|
client.ReplyNicknamed("323", "End of /LIST")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ClientNick(client *Client, cols []string) {
|
||||||
|
if len(cols) == 1 || len(cols[1]) < 1 {
|
||||||
|
client.ReplyParts("431", "No nickname given")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nickname := cols[1]
|
||||||
|
// Compatibility with some clients prepending colons to nickname
|
||||||
|
nickname = strings.TrimPrefix(nickname, ":")
|
||||||
|
rename := false
|
||||||
|
clientsM.RLock()
|
||||||
|
for existingClient := range clients {
|
||||||
|
if existingClient == client {
|
||||||
|
rename = true
|
||||||
|
} else if existingClient.Match(nickname) {
|
||||||
|
clientsM.RUnlock()
|
||||||
|
client.ReplyParts("433", "*", nickname, "Nickname is already in use")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clientsM.RUnlock()
|
||||||
|
if !RENickname.MatchString(nickname) {
|
||||||
|
client.ReplyParts("432", "*", cols[1], "Erroneous nickname")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rename {
|
||||||
|
// find all rooms the client has subscribed,
|
||||||
|
// then gather all clients in those rooms
|
||||||
|
cs := make(map[*Client]struct{})
|
||||||
|
clientsM.RLock() // first clients, then rooms,
|
||||||
|
roomsM.RLock() // to avoid deadlock with SendWhois
|
||||||
|
for _, r := range rooms {
|
||||||
|
if _, subscribed := r.members[client]; subscribed {
|
||||||
|
for c := range r.members {
|
||||||
|
cs[c] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// then notify those clients of the nick change
|
||||||
|
message := ":" + client.String() + " NICK " + nickname
|
||||||
|
for c := range cs {
|
||||||
|
c.Msg(message)
|
||||||
|
}
|
||||||
|
roomsM.RUnlock()
|
||||||
|
clientsM.RUnlock()
|
||||||
|
}
|
||||||
|
client.nickname = &nickname
|
||||||
|
}
|
||||||
|
|
||||||
// Unregistered client workflow processor. Unregistered client:
|
// Unregistered client workflow processor. Unregistered client:
|
||||||
// * is not PINGed
|
// * is not PINGed
|
||||||
// * only QUIT, NICK and USER commands are processed
|
// * only QUIT, NICK and USER commands are processed
|
||||||
@ -170,28 +229,7 @@ func ClientRegister(client *Client, cmd string, cols []string) {
|
|||||||
password := strings.TrimPrefix(cols[1], ":")
|
password := strings.TrimPrefix(cols[1], ":")
|
||||||
client.password = &password
|
client.password = &password
|
||||||
case "NICK":
|
case "NICK":
|
||||||
if len(cols) == 1 || len(cols[1]) < 1 {
|
ClientNick(client, cols)
|
||||||
client.ReplyParts("431", "No nickname given")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nickname := cols[1]
|
|
||||||
// Compatibility with some clients prepending colons to nickname
|
|
||||||
nickname = strings.TrimPrefix(nickname, ":")
|
|
||||||
nickname = strings.ToLower(nickname)
|
|
||||||
clientsM.RLock()
|
|
||||||
for existingClient := range clients {
|
|
||||||
if *existingClient.nickname == nickname {
|
|
||||||
clientsM.RUnlock()
|
|
||||||
client.ReplyParts("433", "*", nickname, "Nickname is already in use")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clientsM.RUnlock()
|
|
||||||
if !RENickname.MatchString(nickname) {
|
|
||||||
client.ReplyParts("432", "*", cols[1], "Erroneous nickname")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
client.nickname = &nickname
|
|
||||||
case "USER":
|
case "USER":
|
||||||
if len(cols) == 1 {
|
if len(cols) == 1 {
|
||||||
client.ReplyNotEnoughParameters("USER")
|
client.ReplyNotEnoughParameters("USER")
|
||||||
@ -210,7 +248,7 @@ func ClientRegister(client *Client, cmd string, cols []string) {
|
|||||||
if passwords != nil && *passwords != "" {
|
if passwords != nil && *passwords != "" {
|
||||||
if client.password == nil {
|
if client.password == nil {
|
||||||
client.ReplyParts("462", "You may not register")
|
client.ReplyParts("462", "You may not register")
|
||||||
client.Close()
|
client.Close("462")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
contents, err := ioutil.ReadFile(*passwords)
|
contents, err := ioutil.ReadFile(*passwords)
|
||||||
@ -224,7 +262,7 @@ func ClientRegister(client *Client, cmd string, cols []string) {
|
|||||||
}
|
}
|
||||||
if lp := strings.Split(entry, ":"); lp[0] == *client.nickname && lp[1] != *client.password {
|
if lp := strings.Split(entry, ":"); lp[0] == *client.nickname && lp[1] != *client.password {
|
||||||
client.ReplyParts("462", "You may not register")
|
client.ReplyParts("462", "You may not register")
|
||||||
client.Close()
|
client.Close("462")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,7 +284,7 @@ func RoomRegister(name string) (*Room, chan ClientEvent) {
|
|||||||
roomNew := NewRoom(name)
|
roomNew := NewRoom(name)
|
||||||
roomSink := make(chan ClientEvent)
|
roomSink := make(chan ClientEvent)
|
||||||
roomsM.Lock()
|
roomsM.Lock()
|
||||||
rooms[name] = roomNew
|
rooms[strings.ToLower(name)] = roomNew
|
||||||
roomSinks[roomNew] = roomSink
|
roomSinks[roomNew] = roomSink
|
||||||
roomsM.Unlock()
|
roomsM.Unlock()
|
||||||
go roomNew.Processor(roomSink)
|
go roomNew.Processor(roomSink)
|
||||||
@ -279,7 +317,7 @@ func HandlerJoin(client *Client, cmd string) {
|
|||||||
}
|
}
|
||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
for roomExisting, roomSink = range roomSinks {
|
for roomExisting, roomSink = range roomSinks {
|
||||||
if room == *roomExisting.name {
|
if roomExisting.Match(room) {
|
||||||
roomsM.RUnlock()
|
roomsM.RUnlock()
|
||||||
if (*roomExisting.key != "") && (*roomExisting.key != key) {
|
if (*roomExisting.key != "") && (*roomExisting.key != key) {
|
||||||
goto Denied
|
goto Denied
|
||||||
@ -320,7 +358,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
for c := range clients {
|
for c := range clients {
|
||||||
if c.recvTimestamp.Add(PingTimeout).Before(now) {
|
if c.recvTimestamp.Add(PingTimeout).Before(now) {
|
||||||
log.Println(c, "ping timeout")
|
log.Println(c, "ping timeout")
|
||||||
c.Close()
|
c.Close("ping timeout")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c.sendTimestamp.Add(PingThreshold).Before(now) {
|
if c.sendTimestamp.Add(PingThreshold).Before(now) {
|
||||||
@ -329,7 +367,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
c.sendTimestamp = time.Now()
|
c.sendTimestamp = time.Now()
|
||||||
} else {
|
} else {
|
||||||
log.Println(c, "ping timeout")
|
log.Println(c, "ping timeout")
|
||||||
c.Close()
|
c.Close("ping timeout")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,7 +412,13 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
}
|
}
|
||||||
if cmd == "QUIT" {
|
if cmd == "QUIT" {
|
||||||
log.Println(client, "quit")
|
log.Println(client, "quit")
|
||||||
client.Close()
|
var quitMsg string
|
||||||
|
if len(cols) >= 2 {
|
||||||
|
quitMsg = strings.TrimPrefix(cols[1], ":")
|
||||||
|
} else {
|
||||||
|
quitMsg = *client.nickname
|
||||||
|
}
|
||||||
|
client.Close(quitMsg)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !client.registered {
|
if !client.registered {
|
||||||
@ -400,6 +444,8 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
HandlerJoin(client, cols[1])
|
HandlerJoin(client, cols[1])
|
||||||
|
case "NICK":
|
||||||
|
ClientNick(client, cols)
|
||||||
case "LIST":
|
case "LIST":
|
||||||
SendList(client, cols)
|
SendList(client, cols)
|
||||||
case "LUSERS":
|
case "LUSERS":
|
||||||
@ -410,7 +456,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cols = strings.SplitN(cols[1], " ", 2)
|
cols = strings.SplitN(cols[1], " ", 2)
|
||||||
if cols[0] == *client.username {
|
if strings.ToLower(cols[0]) == strings.ToLower(*client.username) {
|
||||||
if len(cols) == 1 {
|
if len(cols) == 1 {
|
||||||
client.Msg("221 " + *client.nickname + " +")
|
client.Msg("221 " + *client.nickname + " +")
|
||||||
} else {
|
} else {
|
||||||
@ -420,7 +466,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
}
|
}
|
||||||
room := cols[0]
|
room := cols[0]
|
||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
r, found := rooms[room]
|
r, found := GetRoom(room)
|
||||||
if !found {
|
if !found {
|
||||||
client.ReplyNoChannel(room)
|
client.ReplyNoChannel(room)
|
||||||
roomsM.RUnlock()
|
roomsM.RUnlock()
|
||||||
@ -439,13 +485,18 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
client.ReplyNotEnoughParameters("PART")
|
client.ReplyNotEnoughParameters("PART")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rs := strings.Split(cols[1], " ")[0]
|
rs := strings.SplitN(cols[1], " ", 2)
|
||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
for _, room := range strings.Split(rs, ",") {
|
for _, room := range strings.Split(rs[0], ",") {
|
||||||
if r, found := rooms[room]; found {
|
if r, found := GetRoom(room); found {
|
||||||
roomSinks[r] <- ClientEvent{client, EventDel, ""}
|
var partMsg string
|
||||||
|
if len(rs) >= 2 {
|
||||||
|
partMsg = strings.TrimPrefix(rs[1], ":")
|
||||||
|
} else {
|
||||||
|
partMsg = *client.nickname
|
||||||
|
}
|
||||||
|
roomSinks[r] <- ClientEvent{client, EventDel, partMsg}
|
||||||
} else {
|
} else {
|
||||||
roomsM.RUnlock()
|
|
||||||
client.ReplyNoChannel(room)
|
client.ReplyNoChannel(room)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -470,10 +521,10 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msg := ""
|
msg := ""
|
||||||
target := strings.ToLower(cols[0])
|
target := cols[0]
|
||||||
clientsM.RLock()
|
clientsM.RLock()
|
||||||
for c := range clients {
|
for c := range clients {
|
||||||
if *c.nickname == target {
|
if c.Match(target) {
|
||||||
msg = fmt.Sprintf(":%s %s %s %s", client, cmd, *c.nickname, cols[1])
|
msg = fmt.Sprintf(":%s %s %s %s", client, cmd, *c.nickname, cols[1])
|
||||||
c.Msg(msg)
|
c.Msg(msg)
|
||||||
if c.away != nil {
|
if c.away != nil {
|
||||||
@ -487,7 +538,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
if r, found := rooms[target]; found {
|
if r, found := rooms[strings.ToLower(target)]; found {
|
||||||
roomSinks[r] <- ClientEvent{
|
roomSinks[r] <- ClientEvent{
|
||||||
client,
|
client,
|
||||||
EventMsg,
|
EventMsg,
|
||||||
@ -504,7 +555,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
}
|
}
|
||||||
cols = strings.SplitN(cols[1], " ", 2)
|
cols = strings.SplitN(cols[1], " ", 2)
|
||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
r, found := rooms[cols[0]]
|
r, found := GetRoom(cols[0])
|
||||||
roomsM.RUnlock()
|
roomsM.RUnlock()
|
||||||
if !found {
|
if !found {
|
||||||
client.ReplyNoChannel(cols[0])
|
client.ReplyNoChannel(cols[0])
|
||||||
@ -526,7 +577,7 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
}
|
}
|
||||||
room := strings.Split(cols[1], " ")[0]
|
room := strings.Split(cols[1], " ")[0]
|
||||||
roomsM.RLock()
|
roomsM.RLock()
|
||||||
if r, found := rooms[room]; found {
|
if r, found := GetRoom(room); found {
|
||||||
roomSinks[r] <- ClientEvent{client, EventWho, ""}
|
roomSinks[r] <- ClientEvent{client, EventWho, ""}
|
||||||
} else {
|
} else {
|
||||||
client.ReplyNoChannel(room)
|
client.ReplyNoChannel(room)
|
||||||
@ -545,18 +596,16 @@ func Processor(events chan ClientEvent, finished chan struct{}) {
|
|||||||
client.ReplyNotEnoughParameters("ISON")
|
client.ReplyNotEnoughParameters("ISON")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nicksKnown := make(map[string]struct{})
|
|
||||||
clientsM.RLock()
|
clientsM.RLock()
|
||||||
for c := range clients {
|
|
||||||
nicksKnown[*c.nickname] = struct{}{}
|
|
||||||
}
|
|
||||||
clientsM.RUnlock()
|
|
||||||
var nicksExists []string
|
var nicksExists []string
|
||||||
for _, nickname := range strings.Split(cols[1], " ") {
|
for _, nickname := range strings.Split(cols[1], " ") {
|
||||||
if _, exists := nicksKnown[nickname]; exists {
|
for c := range clients {
|
||||||
|
if c.Match(nickname) {
|
||||||
nicksExists = append(nicksExists, nickname)
|
nicksExists = append(nicksExists, nickname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
clientsM.RUnlock()
|
||||||
client.ReplyNicknamed("303", strings.Join(nicksExists, " "))
|
client.ReplyNicknamed("303", strings.Join(nicksExists, " "))
|
||||||
case "VERSION":
|
case "VERSION":
|
||||||
var debug string
|
var debug string
|
||||||
|
12
room.go
12
room.go
@ -63,6 +63,10 @@ func NewRoom(name string) *Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (room *Room) Match(other string) bool {
|
||||||
|
return strings.ToLower(*room.name) == strings.ToLower(other)
|
||||||
|
}
|
||||||
|
|
||||||
func (room *Room) SendTopic(client *Client) {
|
func (room *Room) SendTopic(client *Client) {
|
||||||
room.RLock()
|
room.RLock()
|
||||||
if *room.topic == "" {
|
if *room.topic == "" {
|
||||||
@ -125,15 +129,13 @@ func (room *Room) Processor(events <-chan ClientEvent) {
|
|||||||
room.RUnlock()
|
room.RUnlock()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
msg := fmt.Sprintf(":%s PART %s :%s", client, room.String(), event.text)
|
||||||
|
room.Broadcast(msg)
|
||||||
|
logSink <- LogEvent{room.String(), *client.nickname, "left", true}
|
||||||
room.RUnlock()
|
room.RUnlock()
|
||||||
room.Lock()
|
room.Lock()
|
||||||
delete(room.members, client)
|
delete(room.members, client)
|
||||||
room.Unlock()
|
room.Unlock()
|
||||||
room.RLock()
|
|
||||||
msg := fmt.Sprintf(":%s PART %s :%s", client, room.String(), *client.nickname)
|
|
||||||
room.Broadcast(msg)
|
|
||||||
logSink <- LogEvent{room.String(), *client.nickname, "left", true}
|
|
||||||
room.RUnlock()
|
|
||||||
case EventTopic:
|
case EventTopic:
|
||||||
room.RLock()
|
room.RLock()
|
||||||
if _, subscribed := room.members[client]; !subscribed {
|
if _, subscribed := room.members[client]; !subscribed {
|
||||||
|
Loading…
Reference in New Issue
Block a user