feat: refactor client into reusable ts3client library
This commit is contained in:
@@ -17,6 +17,9 @@ type Channel struct {
|
||||
Order uint64
|
||||
}
|
||||
|
||||
// EventHandler is called when events occur
|
||||
type EventHandler func(eventType string, data map[string]any)
|
||||
|
||||
type Client struct {
|
||||
Conn *transport.TS3Conn
|
||||
Handshake *HandshakeState
|
||||
@@ -29,7 +32,8 @@ type Client struct {
|
||||
VoicePacketID uint16
|
||||
|
||||
// State
|
||||
Connected bool
|
||||
Connected bool
|
||||
ServerName string
|
||||
|
||||
// Fragment reassembly
|
||||
FragmentBuffer []byte
|
||||
@@ -43,6 +47,12 @@ type Client struct {
|
||||
// Audio
|
||||
VoiceDecoders map[uint16]*opus.Decoder // Map VID (sender ID) to decoder
|
||||
VoiceEncoder *opus.Encoder // Encoder for outgoing audio
|
||||
|
||||
// Event handler for public API
|
||||
eventHandler EventHandler
|
||||
|
||||
// Done channel to signal shutdown
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewClient(nickname string) *Client {
|
||||
@@ -52,6 +62,29 @@ func NewClient(nickname string) *Client {
|
||||
VoicePacketID: 1,
|
||||
Channels: make(map[uint64]*Channel),
|
||||
VoiceDecoders: make(map[uint16]*opus.Decoder),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// SetEventHandler sets the callback for events
|
||||
func (c *Client) SetEventHandler(handler EventHandler) {
|
||||
c.eventHandler = handler
|
||||
}
|
||||
|
||||
// emitEvent sends an event to the handler if set
|
||||
func (c *Client) emitEvent(eventType string, data map[string]any) {
|
||||
if c.eventHandler != nil {
|
||||
c.eventHandler(eventType, data)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop signals the client to stop its loops
|
||||
func (c *Client) Stop() {
|
||||
select {
|
||||
case <-c.done:
|
||||
// Already closed
|
||||
default:
|
||||
close(c.done)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,11 +118,21 @@ func (c *Client) Connect(address string) error {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-c.done:
|
||||
log.Println("Client loop stopped")
|
||||
return nil
|
||||
case pkt := <-pktChan:
|
||||
if pkt == nil {
|
||||
// Channel closed
|
||||
return nil
|
||||
}
|
||||
if err := c.handlePacket(pkt); err != nil {
|
||||
log.Printf("Error handling packet: %v", err)
|
||||
}
|
||||
case <-ticker.C:
|
||||
if !c.Connected {
|
||||
continue // Don't send pings if not connected yet
|
||||
}
|
||||
ping := protocol.NewPacket(protocol.PacketTypePing, nil)
|
||||
c.PacketIDCounterC2S++
|
||||
ping.Header.PacketID = c.PacketIDCounterC2S
|
||||
|
||||
Reference in New Issue
Block a user