From 28b551c3af01fcd6fbcca11b7100bd052665057c Mon Sep 17 00:00:00 2001 From: Tim Cooper Date: Fri, 21 Nov 2014 15:10:47 -0400 Subject: [PATCH] replaced outgoing goroutine with function call --- gumble/audio_outgoing.go | 2 +- gumble/channel.go | 8 +++--- gumble/client.go | 51 ++++++++++++++++++++++++++++++--------- gumble/client_outgoing.go | 44 --------------------------------- gumble/user.go | 18 +++++++------- 5 files changed, 54 insertions(+), 69 deletions(-) delete mode 100644 gumble/client_outgoing.go diff --git a/gumble/audio_outgoing.go b/gumble/audio_outgoing.go index 2e4d54c..12305ab 100644 --- a/gumble/audio_outgoing.go +++ b/gumble/audio_outgoing.go @@ -18,7 +18,7 @@ func audioOutgoing(audio *Audio) { return } else { if opusBuf, err := encoder.Encode(buf.Pcm, SampleRate/100, 1024); err == nil { - audio.client.outgoing <- &message + audio.client.Send(&message) message.sequence = (message.sequence + 1) % 10000 message.opus = opusBuf } diff --git a/gumble/channel.go b/gumble/channel.go index 7e089f8..ed7ffc0 100644 --- a/gumble/channel.go +++ b/gumble/channel.go @@ -59,7 +59,7 @@ func (c *Channel) Add(name string, temporary bool) { Name: &name, Temporary: proto.Bool(temporary), } - c.client.outgoing <- protoMessage{&packet} + c.client.Send(protoMessage{&packet}) } // Remove will remove the given channel and all sub-channels from the server's @@ -68,7 +68,7 @@ func (c *Channel) Remove() { packet := MumbleProto.ChannelRemove{ ChannelId: &c.id, } - c.client.outgoing <- protoMessage{&packet} + c.client.Send(protoMessage{&packet}) } // Name returns the channel name. @@ -83,7 +83,7 @@ func (c *Channel) SetName(name string) { ChannelId: &c.id, Name: &name, } - c.client.outgoing <- protoMessage{&packet} + c.client.Send(protoMessage{&packet}) } // Description returns the channel's description. @@ -97,7 +97,7 @@ func (c *Channel) SetDescription(description string) { ChannelId: &c.id, Description: &description, } - c.client.outgoing <- protoMessage{&packet} + c.client.Send(protoMessage{&packet}) } // Children returns a container containing the channels directly underneath the diff --git a/gumble/client.go b/gumble/client.go index 3d8a65d..cc95c03 100644 --- a/gumble/client.go +++ b/gumble/client.go @@ -6,6 +6,7 @@ import ( "net" "runtime" "sync" + "time" "code.google.com/p/goprotobuf/proto" "github.com/bontibon/gumble/gumble/MumbleProto" @@ -20,6 +21,10 @@ const ( Synced ) +// PingInterval is the interval at which ping packets are be sent by the client +// to the server. +const pingInterval time.Duration = time.Second * 10 + var ( ErrConnected = errors.New("client is already connected to a server") ) @@ -45,7 +50,7 @@ type Client struct { end chan bool closeMutex sync.Mutex - outgoing chan Message + sendMutex sync.Mutex } // NewClient creates a new gumble client. @@ -71,12 +76,10 @@ func (c *Client) Connect() error { c.channels = Channels{} c.state = Connected - // Channels and event loops + // Channels and goroutines c.end = make(chan bool) - c.outgoing = make(chan Message, 2) - - go clientOutgoing(c) go clientIncoming(c) + go c.pingRoutine() // Initial packets version := Version{ @@ -97,11 +100,32 @@ func (c *Client) Connect() error { Password: &c.config.Password, Opus: proto.Bool(true), } - c.outgoing <- protoMessage{&versionPacket} - c.outgoing <- protoMessage{&authenticationPacket} + c.Send(protoMessage{&versionPacket}) + c.Send(protoMessage{&authenticationPacket}) return nil } +// pingRoutine sends ping packets to the server at regular intervals. +func (c *Client) pingRoutine() { + ticker := time.NewTicker(pingInterval) + defer ticker.Stop() + + pingPacket := MumbleProto.Ping{ + Timestamp: proto.Uint64(0), + } + pingProto := protoMessage{&pingPacket} + + for { + select { + case <-c.end: + return + case time := <-ticker.C: + *pingPacket.Timestamp = uint64(time.Unix()) + c.Send(pingProto) + } + } +} + // Close disconnects the client from the server. func (c *Client) Close() error { c.closeMutex.Lock() @@ -114,8 +138,7 @@ func (c *Client) Close() error { c.audio.Detach() c.audio = nil } - close(c.end) - close(c.outgoing) + c.end <- true c.connection.Close() c.connection = nil c.state = Disconnected @@ -211,6 +234,12 @@ func (c *Client) Channels() Channels { } // Send will send a message to the server. -func (c *Client) Send(message Message) { - c.outgoing <- message +func (c *Client) Send(message Message) error { + c.sendMutex.Lock() + defer c.sendMutex.Unlock() + + if _, err := message.WriteTo(c.connection); err != nil { + return err + } + return nil } diff --git a/gumble/client_outgoing.go b/gumble/client_outgoing.go deleted file mode 100644 index 0f7610b..0000000 --- a/gumble/client_outgoing.go +++ /dev/null @@ -1,44 +0,0 @@ -package gumble - -import ( - "time" - - "code.google.com/p/goprotobuf/proto" - "github.com/bontibon/gumble/gumble/MumbleProto" -) - -// PingInterval is the interval at which ping packets are be sent by the client -// to the server. -const pingInterval time.Duration = time.Second * 10 - -// clientOutgoing writes protobuf messages to the server. -func clientOutgoing(client *Client) { - defer client.Close() - - pingTicker := time.NewTicker(pingInterval) - pingPacket := MumbleProto.Ping{ - Timestamp: proto.Uint64(0), - } - pingProto := protoMessage{&pingPacket} - defer pingTicker.Stop() - - conn := client.connection - - for { - select { - case <-client.end: - return - case time := <-pingTicker.C: - *pingPacket.Timestamp = uint64(time.Unix()) - client.outgoing <- pingProto - case message, ok := <-client.outgoing: - if !ok { - return - } else { - if _, err := message.WriteTo(conn); err != nil { - return - } - } - } - } -} diff --git a/gumble/user.go b/gumble/user.go index 60ba9fc..0865112 100644 --- a/gumble/user.go +++ b/gumble/user.go @@ -117,7 +117,7 @@ func (u *User) Register() { Session: &u.session, UserId: proto.Uint32(0), } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // SetComment will set the user's comment to the given string. The user's @@ -127,7 +127,7 @@ func (u *User) SetComment(comment string) { Session: &u.session, Comment: &comment, } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // Move will move the user to the given channel. @@ -136,7 +136,7 @@ func (u *User) Move(channel *Channel) { Session: &u.session, ChannelId: &channel.id, } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // Kick will kick the user from the server. @@ -145,7 +145,7 @@ func (u *User) Kick(reason string) { Session: &u.session, Reason: &reason, } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // Ban will ban the user from the server. @@ -155,7 +155,7 @@ func (u *User) Ban(reason string) { Reason: &reason, Ban: proto.Bool(true), } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // SetMuted sets whether the user can transmit audio or not. @@ -164,7 +164,7 @@ func (u *User) SetMuted(muted bool) { Session: &u.session, Mute: proto.Bool(muted), } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // SetDeafened sets whether the user can receive audio or not. @@ -173,7 +173,7 @@ func (u *User) SetDeafened(muted bool) { Session: &u.session, Deaf: proto.Bool(muted), } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // SetSelfMuted sets whether the user can transmit audio or not. @@ -184,7 +184,7 @@ func (u *User) SetSelfMuted(muted bool) { Session: &u.session, SelfMute: proto.Bool(muted), } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) } // SetSelfDeafened sets whether the user can receive audio or not. @@ -195,5 +195,5 @@ func (u *User) SetSelfDeafened(muted bool) { Session: &u.session, SelfDeaf: proto.Bool(muted), } - u.client.outgoing <- protoMessage{&packet} + u.client.Send(protoMessage{&packet}) }