mirror of
https://github.com/ergochat/ergo.git
synced 2025-01-03 08:32:43 +01:00
get rid of unnecessary concurrency for channels and clients
This commit is contained in:
parent
54ca916c85
commit
4e56ea1bdc
208
irc/channel.go
208
irc/channel.go
@ -5,15 +5,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
banList []UserMask
|
banList []UserMask
|
||||||
commands chan<- ChannelCommand
|
flags ChannelModeSet
|
||||||
flags ChannelModeSet
|
key string
|
||||||
key string
|
members MemberSet
|
||||||
members MemberSet
|
name string
|
||||||
name string
|
server *Server
|
||||||
replies chan<- Reply
|
topic string
|
||||||
server *Server
|
|
||||||
topic string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsChannel(target string) bool {
|
func IsChannel(target string) bool {
|
||||||
@ -30,65 +28,27 @@ func IsChannel(target string) bool {
|
|||||||
// NewChannel creates a new channel from a `Server` and a `name`
|
// NewChannel creates a new channel from a `Server` and a `name`
|
||||||
// string, which must be unique on the server.
|
// string, which must be unique on the server.
|
||||||
func NewChannel(s *Server, name string) *Channel {
|
func NewChannel(s *Server, name string) *Channel {
|
||||||
commands := make(chan ChannelCommand)
|
|
||||||
replies := make(chan Reply)
|
|
||||||
channel := &Channel{
|
channel := &Channel{
|
||||||
banList: make([]UserMask, 0),
|
banList: make([]UserMask, 0),
|
||||||
commands: commands,
|
flags: make(ChannelModeSet),
|
||||||
flags: make(ChannelModeSet),
|
members: make(MemberSet),
|
||||||
members: make(MemberSet),
|
name: name,
|
||||||
name: name,
|
server: s,
|
||||||
replies: replies,
|
|
||||||
server: s,
|
|
||||||
}
|
}
|
||||||
go channel.receiveCommands(commands)
|
|
||||||
go channel.receiveReplies(replies)
|
|
||||||
return channel
|
return channel
|
||||||
}
|
}
|
||||||
|
|
||||||
type DestroyChannel struct {
|
|
||||||
BaseCommand
|
|
||||||
channel *Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (channel *Channel) Destroy() {
|
|
||||||
channel.server.Command(&DestroyChannel{
|
|
||||||
channel: channel,
|
|
||||||
})
|
|
||||||
close(channel.commands)
|
|
||||||
close(channel.replies)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (channel *Channel) Command(command ChannelCommand) {
|
|
||||||
channel.commands <- command
|
|
||||||
}
|
|
||||||
|
|
||||||
func (channel *Channel) Reply(reply Reply) {
|
func (channel *Channel) Reply(reply Reply) {
|
||||||
channel.replies <- reply
|
if DEBUG_CHANNEL {
|
||||||
}
|
log.Printf("%s ← %s %s", channel, reply.Source(), reply)
|
||||||
|
|
||||||
func (channel *Channel) receiveCommands(commands <-chan ChannelCommand) {
|
|
||||||
for command := range commands {
|
|
||||||
if DEBUG_CHANNEL {
|
|
||||||
log.Printf("%s → %s %s", command.Source(), channel, command)
|
|
||||||
}
|
|
||||||
command.HandleChannel(channel)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (channel *Channel) receiveReplies(replies <-chan Reply) {
|
for client := range channel.members {
|
||||||
for reply := range replies {
|
if (reply.Code() == ReplyCode(PRIVMSG)) &&
|
||||||
if DEBUG_CHANNEL {
|
(reply.Source() == Identifier(client)) {
|
||||||
log.Printf("%s ← %s %s", channel, reply.Source(), reply)
|
continue
|
||||||
}
|
|
||||||
|
|
||||||
for client := range channel.members {
|
|
||||||
if (reply.Code() == ReplyCode(PRIVMSG)) &&
|
|
||||||
(reply.Source() == Identifier(client)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
client.Reply(reply)
|
|
||||||
}
|
}
|
||||||
|
client.Reply(reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,16 +56,6 @@ func (channel *Channel) IsEmpty() bool {
|
|||||||
return len(channel.members) == 0
|
return len(channel.members) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channel *Channel) GetTopic(replier Replier) {
|
|
||||||
if channel.topic == "" {
|
|
||||||
// clients appear not to expect this
|
|
||||||
//replier.Reply(RplNoTopic(channel))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
replier.Reply(RplTopic(channel))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (channel *Channel) GetUsers(replier Replier) {
|
func (channel *Channel) GetUsers(replier Replier) {
|
||||||
replier.Reply(NewNamesReply(channel))
|
replier.Reply(NewNamesReply(channel))
|
||||||
}
|
}
|
||||||
@ -164,18 +114,8 @@ func (channel *Channel) ModeString() (str string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type JoinChannel struct {
|
func (channel *Channel) Join(client *Client, key string) {
|
||||||
BaseCommand
|
if (channel.key != "") && (channel.key != key) {
|
||||||
channel *Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// commands
|
|
||||||
//
|
|
||||||
|
|
||||||
func (m *JoinCommand) HandleChannel(channel *Channel) {
|
|
||||||
client := m.Client()
|
|
||||||
if (channel.key != "") && (channel.key != m.channels[channel.name]) {
|
|
||||||
client.Reply(ErrBadChannelKey(channel))
|
client.Reply(ErrBadChannelKey(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -186,18 +126,11 @@ func (m *JoinCommand) HandleChannel(channel *Channel) {
|
|||||||
channel.members[client][ChannelOperator] = true
|
channel.members[client][ChannelOperator] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
client.commands <- &JoinChannel{
|
client.channels.Add(channel)
|
||||||
channel: channel,
|
|
||||||
}
|
|
||||||
|
|
||||||
addClient := &AddFriend{
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
client.commands <- &AddFriend{
|
client.AddFriend(member)
|
||||||
client: member,
|
member.AddFriend(client)
|
||||||
}
|
|
||||||
member.commands <- addClient
|
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Reply(RplJoin(client, channel))
|
channel.Reply(RplJoin(client, channel))
|
||||||
@ -205,77 +138,73 @@ func (m *JoinCommand) HandleChannel(channel *Channel) {
|
|||||||
channel.GetUsers(client)
|
channel.GetUsers(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PartChannel struct {
|
func (channel *Channel) Part(client *Client, message string) {
|
||||||
channel *Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *PartCommand) HandleChannel(channel *Channel) {
|
|
||||||
client := m.Client()
|
|
||||||
|
|
||||||
if !channel.members.Has(client) {
|
if !channel.members.Has(client) {
|
||||||
client.Reply(ErrNotOnChannel(channel))
|
client.Reply(ErrNotOnChannel(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Reply(RplPart(client, channel, m.Message()))
|
channel.Reply(RplPart(client, channel, message))
|
||||||
|
|
||||||
channel.members.Remove(client)
|
channel.members.Remove(client)
|
||||||
client.commands <- &PartChannel{
|
client.channels.Remove(channel)
|
||||||
channel: channel,
|
|
||||||
}
|
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
member.commands <- &RemoveFriend{
|
member.RemoveFriend(client)
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.IsEmpty() {
|
if channel.IsEmpty() {
|
||||||
channel.Destroy()
|
channel.server.channels.Remove(channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TopicCommand) HandleChannel(channel *Channel) {
|
func (channel *Channel) GetTopic(client *Client) {
|
||||||
client := m.Client()
|
|
||||||
|
|
||||||
if !channel.members.Has(client) {
|
if !channel.members.Has(client) {
|
||||||
client.Reply(ErrNotOnChannel(channel))
|
client.Reply(ErrNotOnChannel(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !m.setTopic {
|
if channel.topic == "" {
|
||||||
channel.GetTopic(client)
|
// clients appear not to expect this
|
||||||
|
//replier.Reply(RplNoTopic(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if channel.flags[OpOnlyTopic] {
|
client.Reply(RplTopic(channel))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (channel *Channel) SetTopic(client *Client, topic string) {
|
||||||
|
if !channel.members.Has(client) {
|
||||||
|
client.Reply(ErrNotOnChannel(channel))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if channel.flags[OpOnlyTopic] && !channel.members[client][ChannelOperator] {
|
||||||
client.Reply(ErrChanOPrivIsNeeded(channel))
|
client.Reply(ErrChanOPrivIsNeeded(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.topic = m.topic
|
channel.topic = topic
|
||||||
channel.Reply(RplTopicMsg(client, channel))
|
channel.Reply(RplTopicMsg(client, channel))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PrivMsgCommand) HandleChannel(channel *Channel) {
|
func (channel *Channel) PrivMsg(client *Client, message string) {
|
||||||
client := m.Client()
|
|
||||||
if channel.flags[NoOutside] && !channel.members.Has(client) {
|
if channel.flags[NoOutside] && !channel.members.Has(client) {
|
||||||
client.Reply(ErrCannotSendToChan(channel))
|
client.Reply(ErrCannotSendToChan(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channel.Reply(RplPrivMsg(client, channel, m.message))
|
channel.Reply(RplPrivMsg(client, channel, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *ChannelModeCommand) HandleChannel(channel *Channel) {
|
func (channel *Channel) Mode(client *Client, changes ChannelModeChanges) {
|
||||||
client := msg.Client()
|
if len(changes) == 0 {
|
||||||
|
|
||||||
if len(msg.changes) == 0 {
|
|
||||||
client.Reply(RplChannelModeIs(channel))
|
client.Reply(RplChannelModeIs(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
changes := make(ChannelModeChanges, 0)
|
applied := make(ChannelModeChanges, 0)
|
||||||
|
|
||||||
for _, change := range msg.changes {
|
for _, change := range changes {
|
||||||
switch change.mode {
|
switch change.mode {
|
||||||
case BanMask:
|
case BanMask:
|
||||||
// TODO add/remove
|
// TODO add/remove
|
||||||
@ -294,11 +223,11 @@ func (msg *ChannelModeCommand) HandleChannel(channel *Channel) {
|
|||||||
switch change.op {
|
switch change.op {
|
||||||
case Add:
|
case Add:
|
||||||
channel.flags[change.mode] = true
|
channel.flags[change.mode] = true
|
||||||
changes = append(changes, change)
|
applied = append(applied, change)
|
||||||
|
|
||||||
case Remove:
|
case Remove:
|
||||||
delete(channel.flags, change.mode)
|
delete(channel.flags, change.mode)
|
||||||
changes = append(changes, change)
|
applied = append(applied, change)
|
||||||
}
|
}
|
||||||
|
|
||||||
case Key:
|
case Key:
|
||||||
@ -315,11 +244,11 @@ func (msg *ChannelModeCommand) HandleChannel(channel *Channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel.key = change.arg
|
channel.key = change.arg
|
||||||
changes = append(changes, change)
|
applied = append(applied, change)
|
||||||
|
|
||||||
case Remove:
|
case Remove:
|
||||||
channel.key = ""
|
channel.key = ""
|
||||||
changes = append(changes, change)
|
applied = append(applied, change)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ChannelOperator, Voice:
|
case ChannelOperator, Voice:
|
||||||
@ -347,40 +276,33 @@ func (msg *ChannelModeCommand) HandleChannel(channel *Channel) {
|
|||||||
switch change.op {
|
switch change.op {
|
||||||
case Add:
|
case Add:
|
||||||
channel.members[target][change.mode] = true
|
channel.members[target][change.mode] = true
|
||||||
changes = append(changes, change)
|
applied = append(applied, change)
|
||||||
|
|
||||||
case Remove:
|
case Remove:
|
||||||
channel.members[target][change.mode] = false
|
channel.members[target][change.mode] = false
|
||||||
changes = append(changes, change)
|
applied = append(applied, change)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(changes) > 0 {
|
if len(applied) > 0 {
|
||||||
channel.Reply(RplChannelMode(client, channel, changes))
|
channel.Reply(RplChannelMode(client, channel, applied))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *NoticeCommand) HandleChannel(channel *Channel) {
|
func (channel *Channel) Notice(client *Client, message string) {
|
||||||
client := m.Client()
|
|
||||||
if channel.flags[NoOutside] && !channel.members.Has(client) {
|
if channel.flags[NoOutside] && !channel.members.Has(client) {
|
||||||
client.Reply(ErrCannotSendToChan(channel))
|
client.Reply(ErrCannotSendToChan(channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channel.Reply(RplNotice(client, channel, m.message))
|
channel.Reply(RplNotice(client, channel, message))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *QuitCommand) HandleChannel(channel *Channel) {
|
func (channel *Channel) Quit(client *Client) {
|
||||||
client := msg.Client()
|
|
||||||
removeClient := &RemoveFriend{
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
for member := range channel.members {
|
for member := range channel.members {
|
||||||
member.commands <- removeClient
|
client.RemoveFriend(member)
|
||||||
|
member.RemoveFriend(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.members.Remove(client)
|
channel.members.Remove(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *DestroyClient) HandleChannel(channel *Channel) {
|
|
||||||
channel.members.Remove(msg.client)
|
|
||||||
}
|
|
||||||
|
143
irc/client.go
143
irc/client.go
@ -12,7 +12,6 @@ type Client struct {
|
|||||||
away bool
|
away bool
|
||||||
awayMessage string
|
awayMessage string
|
||||||
channels ChannelSet
|
channels ChannelSet
|
||||||
commands chan ClientCommand
|
|
||||||
ctime time.Time
|
ctime time.Time
|
||||||
friends map[*Client]uint
|
friends map[*Client]uint
|
||||||
hostname string
|
hostname string
|
||||||
@ -35,7 +34,6 @@ func NewClient(server *Server, conn net.Conn) *Client {
|
|||||||
client := &Client{
|
client := &Client{
|
||||||
atime: now,
|
atime: now,
|
||||||
channels: make(ChannelSet),
|
channels: make(ChannelSet),
|
||||||
commands: make(chan ClientCommand),
|
|
||||||
ctime: now,
|
ctime: now,
|
||||||
friends: make(map[*Client]uint),
|
friends: make(map[*Client]uint),
|
||||||
hostname: AddrLookupHostname(conn.RemoteAddr()),
|
hostname: AddrLookupHostname(conn.RemoteAddr()),
|
||||||
@ -45,14 +43,42 @@ func NewClient(server *Server, conn net.Conn) *Client {
|
|||||||
socket: NewSocket(conn),
|
socket: NewSocket(conn),
|
||||||
}
|
}
|
||||||
|
|
||||||
client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.Destroy)
|
client.loginTimer = time.AfterFunc(LOGIN_TIMEOUT, client.ConnectionClosed)
|
||||||
go client.readClientCommands()
|
|
||||||
go client.readCommands()
|
go client.readCommands()
|
||||||
go client.writeReplies()
|
go client.writeReplies()
|
||||||
|
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) readCommands() {
|
||||||
|
for line := range client.socket.Read() {
|
||||||
|
msg, err := ParseCommand(line)
|
||||||
|
if err != nil {
|
||||||
|
switch err {
|
||||||
|
case NotEnoughArgsError:
|
||||||
|
client.Reply(ErrNeedMoreParams(client.server, line))
|
||||||
|
default:
|
||||||
|
client.Reply(ErrUnknownCommand(client.server, line))
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.SetClient(client)
|
||||||
|
client.server.commands <- msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) writeReplies() {
|
||||||
|
for reply := range client.replies {
|
||||||
|
if DEBUG_CLIENT {
|
||||||
|
log.Printf("%s ← %s", client, reply)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.socket.Write(reply.Format(client))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (client *Client) Touch() {
|
func (client *Client) Touch() {
|
||||||
client.atime = time.Now()
|
client.atime = time.Now()
|
||||||
|
|
||||||
@ -82,7 +108,7 @@ func (client *Client) ConnectionTimeout() {
|
|||||||
message: "connection timeout",
|
message: "connection timeout",
|
||||||
}
|
}
|
||||||
msg.SetClient(client)
|
msg.SetClient(client)
|
||||||
client.server.Command(msg)
|
client.server.commands <- msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) ConnectionClosed() {
|
func (client *Client) ConnectionClosed() {
|
||||||
@ -90,57 +116,14 @@ func (client *Client) ConnectionClosed() {
|
|||||||
message: "connection closed",
|
message: "connection closed",
|
||||||
}
|
}
|
||||||
msg.SetClient(client)
|
msg.SetClient(client)
|
||||||
client.server.Command(msg)
|
client.server.commands <- msg
|
||||||
}
|
|
||||||
|
|
||||||
func (client *Client) readClientCommands() {
|
|
||||||
for command := range client.commands {
|
|
||||||
command.HandleClient(client)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) readCommands() {
|
|
||||||
for line := range c.socket.Read() {
|
|
||||||
m, err := ParseCommand(line)
|
|
||||||
if err != nil {
|
|
||||||
switch err {
|
|
||||||
case NotEnoughArgsError:
|
|
||||||
c.Reply(ErrNeedMoreParams(c.server, line))
|
|
||||||
default:
|
|
||||||
c.Reply(ErrUnknownCommand(c.server, line))
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
m.SetClient(c)
|
|
||||||
c.server.Command(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.phase == Normal {
|
|
||||||
c.ConnectionClosed()
|
|
||||||
} else {
|
|
||||||
c.Destroy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (client *Client) writeReplies() {
|
|
||||||
for reply := range client.replies {
|
|
||||||
if DEBUG_CLIENT {
|
|
||||||
log.Printf("%s ← %s", client, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.socket.Write(reply.Format(client)) != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type DestroyClient struct {
|
|
||||||
BaseCommand
|
|
||||||
client *Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Destroy() {
|
func (client *Client) Destroy() {
|
||||||
|
if DEBUG_CLIENT {
|
||||||
|
log.Printf("%s destroy", client)
|
||||||
|
}
|
||||||
|
|
||||||
client.socket.Close()
|
client.socket.Close()
|
||||||
|
|
||||||
client.loginTimer.Stop()
|
client.loginTimer.Stop()
|
||||||
@ -153,15 +136,11 @@ func (client *Client) Destroy() {
|
|||||||
client.quitTimer.Stop()
|
client.quitTimer.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := &DestroyClient{
|
client.server.clients.Remove(client)
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
|
|
||||||
for channel := range client.channels {
|
if DEBUG_CLIENT {
|
||||||
channel.Command(cmd)
|
log.Printf("%s destroyed", client)
|
||||||
}
|
}
|
||||||
|
|
||||||
client.server.Command(cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Reply(reply Reply) {
|
func (client *Client) Reply(reply Reply) {
|
||||||
@ -220,51 +199,31 @@ func (c *Client) String() string {
|
|||||||
return c.UserHost()
|
return c.UserHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
func (client *Client) AddFriend(friend *Client) {
|
||||||
// commands
|
client.friends[friend] += 1
|
||||||
//
|
|
||||||
|
|
||||||
type AddFriend struct {
|
|
||||||
client *Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *AddFriend) HandleClient(client *Client) {
|
func (client *Client) RemoveFriend(friend *Client) {
|
||||||
client.friends[msg.client] += 1
|
client.friends[friend] -= 1
|
||||||
}
|
if client.friends[friend] <= 0 {
|
||||||
|
delete(client.friends, friend)
|
||||||
type RemoveFriend struct {
|
|
||||||
client *Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg *RemoveFriend) HandleClient(client *Client) {
|
|
||||||
client.friends[msg.client] -= 1
|
|
||||||
if client.friends[msg.client] <= 0 {
|
|
||||||
delete(client.friends, msg.client)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *JoinChannel) HandleClient(client *Client) {
|
func (client *Client) ChangeNickname(nickname string) {
|
||||||
client.channels.Add(msg.channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg *PartChannel) HandleClient(client *Client) {
|
|
||||||
client.channels.Remove(msg.channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg *NickCommand) HandleClient(client *Client) {
|
|
||||||
// Make reply before changing nick.
|
// Make reply before changing nick.
|
||||||
reply := RplNick(client, msg.nickname)
|
reply := RplNick(client, nickname)
|
||||||
|
|
||||||
client.nick = msg.nickname
|
client.nick = nickname
|
||||||
|
|
||||||
for friend := range client.friends {
|
for friend := range client.friends {
|
||||||
friend.Reply(reply)
|
friend.Reply(reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *QuitCommand) HandleClient(client *Client) {
|
func (client *Client) Quit(message string) {
|
||||||
if len(client.friends) > 0 {
|
if len(client.friends) > 0 {
|
||||||
reply := RplQuit(client, msg.message)
|
reply := RplQuit(client, message)
|
||||||
for friend := range client.friends {
|
for friend := range client.friends {
|
||||||
if friend == client {
|
if friend == client {
|
||||||
continue
|
continue
|
||||||
@ -274,7 +233,7 @@ func (msg *QuitCommand) HandleClient(client *Client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for channel := range client.channels {
|
for channel := range client.channels {
|
||||||
channel.commands <- msg
|
channel.Quit(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
client.Destroy()
|
client.Destroy()
|
||||||
|
@ -362,10 +362,6 @@ func NewPrivMsgCommand(args []string) (editableCommand, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PrivMsgCommand) TargetIsChannel() bool {
|
|
||||||
return IsChannel(m.target)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOPIC [newtopic]
|
// TOPIC [newtopic]
|
||||||
|
|
||||||
type TopicCommand struct {
|
type TopicCommand struct {
|
||||||
|
109
irc/server.go
109
irc/server.go
@ -83,10 +83,6 @@ func (server *Server) receiveCommands() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) Command(command Command) {
|
|
||||||
server.commands <- command
|
|
||||||
}
|
|
||||||
|
|
||||||
func (server *Server) InitPhase() Phase {
|
func (server *Server) InitPhase() Phase {
|
||||||
if server.password == "" {
|
if server.password == "" {
|
||||||
return Registration
|
return Registration
|
||||||
@ -228,7 +224,8 @@ func (s *Server) Nick() string {
|
|||||||
//
|
//
|
||||||
|
|
||||||
func (msg *ProxyCommand) HandleAuthServer(server *Server) {
|
func (msg *ProxyCommand) HandleAuthServer(server *Server) {
|
||||||
msg.Client().hostname = LookupHostname(msg.sourceIP)
|
client := msg.Client()
|
||||||
|
client.hostname = LookupHostname(msg.sourceIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *CapCommand) HandleAuthServer(server *Server) {
|
func (msg *CapCommand) HandleAuthServer(server *Server) {
|
||||||
@ -264,15 +261,15 @@ func (m *NickCommand) HandleRegServer(s *Server) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client.nick = m.nickname
|
client.ChangeNickname(m.nickname)
|
||||||
s.clients.Add(client)
|
s.clients.Add(client)
|
||||||
s.tryRegister(client)
|
s.tryRegister(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMsgCommand) HandleRegServer(s *Server) {
|
func (msg *UserMsgCommand) HandleRegServer(server *Server) {
|
||||||
c := m.Client()
|
client := msg.Client()
|
||||||
c.username, c.realname = m.user, m.realname
|
client.username, client.realname = msg.user, msg.realname
|
||||||
s.tryRegister(c)
|
server.tryRegister(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -291,54 +288,52 @@ func (m *PongCommand) HandleServer(s *Server) {
|
|||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *NickCommand) HandleServer(s *Server) {
|
func (msg *NickCommand) HandleServer(server *Server) {
|
||||||
c := m.Client()
|
client := msg.Client()
|
||||||
|
|
||||||
if m.nickname == "" {
|
if msg.nickname == "" {
|
||||||
c.Reply(ErrNoNicknameGiven(s))
|
client.Reply(ErrNoNicknameGiven(server))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.clients[m.nickname] != nil {
|
if server.clients[msg.nickname] != nil {
|
||||||
c.Reply(ErrNickNameInUse(s, m.nickname))
|
client.Reply(ErrNickNameInUse(server, msg.nickname))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.clients.Remove(c)
|
server.clients.Remove(client)
|
||||||
c.commands <- m
|
client.ChangeNickname(msg.nickname)
|
||||||
s.clients.Add(c)
|
server.clients.Add(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *UserMsgCommand) HandleServer(s *Server) {
|
func (m *UserMsgCommand) HandleServer(s *Server) {
|
||||||
m.Client().Reply(ErrAlreadyRegistered(s))
|
m.Client().Reply(ErrAlreadyRegistered(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *QuitCommand) HandleServer(server *Server) {
|
func (msg *QuitCommand) HandleServer(server *Server) {
|
||||||
client := m.Client()
|
client := msg.Client()
|
||||||
|
client.Quit(msg.message)
|
||||||
server.clients.Remove(client)
|
server.clients.Remove(client)
|
||||||
|
|
||||||
client.commands <- m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *JoinCommand) HandleServer(s *Server) {
|
func (m *JoinCommand) HandleServer(s *Server) {
|
||||||
c := m.Client()
|
client := m.Client()
|
||||||
|
|
||||||
if m.zero {
|
if m.zero {
|
||||||
cmd := &PartCommand{}
|
for channel := range client.channels {
|
||||||
cmd.SetClient(c)
|
channel.Part(client, client.Nick())
|
||||||
for channel := range c.channels {
|
|
||||||
channel.Command(cmd)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for name := range m.channels {
|
for name := range m.channels {
|
||||||
s.GetOrMakeChannel(name).Command(m)
|
channel := s.GetOrMakeChannel(name)
|
||||||
|
channel.Join(client, m.channels[name])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PartCommand) HandleServer(server *Server) {
|
func (m *PartCommand) HandleServer(server *Server) {
|
||||||
|
client := m.Client()
|
||||||
for _, chname := range m.channels {
|
for _, chname := range m.channels {
|
||||||
channel := server.channels[chname]
|
channel := server.channels[chname]
|
||||||
|
|
||||||
@ -347,40 +342,46 @@ func (m *PartCommand) HandleServer(server *Server) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Command(m)
|
channel.Part(client, m.Message())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TopicCommand) HandleServer(s *Server) {
|
func (msg *TopicCommand) HandleServer(server *Server) {
|
||||||
channel := s.channels[m.channel]
|
client := msg.Client()
|
||||||
|
channel := server.channels[msg.channel]
|
||||||
if channel == nil {
|
if channel == nil {
|
||||||
m.Client().Reply(ErrNoSuchChannel(s, m.channel))
|
client.Reply(ErrNoSuchChannel(server, msg.channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Command(m)
|
if msg.setTopic {
|
||||||
|
channel.SetTopic(client, msg.topic)
|
||||||
|
} else {
|
||||||
|
channel.GetTopic(client)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PrivMsgCommand) HandleServer(s *Server) {
|
func (msg *PrivMsgCommand) HandleServer(server *Server) {
|
||||||
if m.TargetIsChannel() {
|
client := msg.Client()
|
||||||
channel := s.channels[m.target]
|
if IsChannel(msg.target) {
|
||||||
|
channel := server.channels[msg.target]
|
||||||
if channel == nil {
|
if channel == nil {
|
||||||
m.Client().Reply(ErrNoSuchChannel(s, m.target))
|
client.Reply(ErrNoSuchChannel(server, msg.target))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Command(m)
|
channel.PrivMsg(client, msg.message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
target := s.clients[m.target]
|
target := server.clients[msg.target]
|
||||||
if target == nil {
|
if target == nil {
|
||||||
m.Client().Reply(ErrNoSuchNick(s, m.target))
|
client.Reply(ErrNoSuchNick(server, msg.target))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target.Reply(RplPrivMsg(m.Client(), target, m.message))
|
target.Reply(RplPrivMsg(client, target, msg.message))
|
||||||
if target.away {
|
if target.away {
|
||||||
m.Client().Reply(RplAway(s, target))
|
client.Reply(RplAway(server, target))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +437,8 @@ func (msg *ChannelModeCommand) HandleServer(server *Server) {
|
|||||||
client.Reply(ErrNoSuchChannel(server, msg.channel))
|
client.Reply(ErrNoSuchChannel(server, msg.channel))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
channel.Command(msg)
|
|
||||||
|
channel.Mode(client, msg.changes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func whoChannel(client *Client, server *Server, channel *Channel) {
|
func whoChannel(client *Client, server *Server, channel *Channel) {
|
||||||
@ -513,29 +515,22 @@ func (msg *MOTDCommand) HandleServer(server *Server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (msg *NoticeCommand) HandleServer(server *Server) {
|
func (msg *NoticeCommand) HandleServer(server *Server) {
|
||||||
|
client := msg.Client()
|
||||||
if IsChannel(msg.target) {
|
if IsChannel(msg.target) {
|
||||||
channel := server.channels[msg.target]
|
channel := server.channels[msg.target]
|
||||||
if channel == nil {
|
if channel == nil {
|
||||||
msg.Client().Reply(ErrNoSuchChannel(server, msg.target))
|
client.Reply(ErrNoSuchChannel(server, msg.target))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Command(msg)
|
channel.Notice(client, msg.message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
target := server.clients[msg.target]
|
target := server.clients[msg.target]
|
||||||
if target == nil {
|
if target == nil {
|
||||||
msg.Client().Reply(ErrNoSuchNick(server, msg.target))
|
client.Reply(ErrNoSuchNick(server, msg.target))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target.Reply(RplPrivMsg(msg.Client(), target, msg.message))
|
target.Reply(RplNotice(client, target, msg.message))
|
||||||
}
|
|
||||||
|
|
||||||
func (msg *DestroyChannel) HandleServer(server *Server) {
|
|
||||||
server.channels.Remove(msg.channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (msg *DestroyClient) HandleServer(server *Server) {
|
|
||||||
server.clients.Remove(msg.client)
|
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,13 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Socket struct {
|
type Socket struct {
|
||||||
closed bool
|
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
mutex *sync.Mutex
|
|
||||||
reader *bufio.Reader
|
reader *bufio.Reader
|
||||||
receive chan string
|
receive chan string
|
||||||
send chan string
|
send chan string
|
||||||
@ -25,7 +21,6 @@ func NewSocket(conn net.Conn) *Socket {
|
|||||||
reader: bufio.NewReader(conn),
|
reader: bufio.NewReader(conn),
|
||||||
receive: make(chan string),
|
receive: make(chan string),
|
||||||
send: make(chan string),
|
send: make(chan string),
|
||||||
mutex: &sync.Mutex{},
|
|
||||||
writer: bufio.NewWriter(conn),
|
writer: bufio.NewWriter(conn),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,40 +34,19 @@ func (socket *Socket) String() string {
|
|||||||
return socket.conn.RemoteAddr().String()
|
return socket.conn.RemoteAddr().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (socket *Socket) IsClosed() bool {
|
|
||||||
socket.mutex.Lock()
|
|
||||||
defer socket.mutex.Unlock()
|
|
||||||
return socket.closed
|
|
||||||
}
|
|
||||||
|
|
||||||
func (socket *Socket) Close() {
|
func (socket *Socket) Close() {
|
||||||
if socket.IsClosed() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if DEBUG_NET {
|
|
||||||
log.Printf("%s closed", socket)
|
|
||||||
}
|
|
||||||
|
|
||||||
socket.mutex.Lock()
|
|
||||||
socket.closed = true
|
|
||||||
socket.conn.Close()
|
socket.conn.Close()
|
||||||
close(socket.receive)
|
|
||||||
socket.mutex.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (socket *Socket) Read() <-chan string {
|
func (socket *Socket) Read() <-chan string {
|
||||||
return socket.receive
|
return socket.receive
|
||||||
}
|
}
|
||||||
|
|
||||||
func (socket *Socket) Write(lines []string) error {
|
func (socket *Socket) Write(lines []string) {
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if socket.IsClosed() {
|
|
||||||
return io.EOF
|
|
||||||
}
|
|
||||||
socket.send <- line
|
socket.send <- line
|
||||||
}
|
}
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (socket *Socket) readLines() {
|
func (socket *Socket) readLines() {
|
||||||
@ -92,7 +66,7 @@ func (socket *Socket) readLines() {
|
|||||||
|
|
||||||
socket.receive <- line
|
socket.receive <- line
|
||||||
}
|
}
|
||||||
socket.Close()
|
close(socket.receive)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (socket *Socket) writeLines() {
|
func (socket *Socket) writeLines() {
|
||||||
@ -106,6 +80,7 @@ func (socket *Socket) writeLines() {
|
|||||||
if _, err := socket.writer.WriteString(CRLF); socket.maybeLogWriteError(err) {
|
if _, err := socket.writer.WriteString(CRLF); socket.maybeLogWriteError(err) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := socket.writer.Flush(); socket.maybeLogWriteError(err) {
|
if err := socket.writer.Flush(); socket.maybeLogWriteError(err) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -192,15 +192,6 @@ type RegServerCommand interface {
|
|||||||
HandleRegServer(*Server)
|
HandleRegServer(*Server)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelCommand interface {
|
|
||||||
Command
|
|
||||||
HandleChannel(channel *Channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientCommand interface {
|
|
||||||
HandleClient(client *Client)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// structs
|
// structs
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user