feat: refactor client into reusable ts3client library

This commit is contained in:
Jose Luis Montañes Ojados
2026-01-15 22:06:35 +01:00
parent 7878ad3d5b
commit 02318b1490
10 changed files with 1050 additions and 47 deletions

View File

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