3
0
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:
Jeremy Latt 2014-02-16 22:20:42 -08:00
parent 54ca916c85
commit 4e56ea1bdc
6 changed files with 172 additions and 334 deletions

View File

@ -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)
}

View File

@ -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()

View File

@ -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 {

View File

@ -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)
} }

View File

@ -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
} }

View File

@ -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
// //