Files
go-ts3/rawevent.go

212 lines
4.6 KiB
Go

package ts3
import (
"bufio"
"fmt"
"net"
"net/url"
"strings"
"time"
"github.com/asaskevich/EventBus"
"github.com/jkoenig134/schema"
)
type EventClient struct {
conn net.Conn
user string
password string
bus EventBus.Bus
decoder *schema.Decoder
}
func newEventClient(host string, user string, password string, bus EventBus.Bus) (*EventClient, error) {
conn, err := net.Dial("tcp", host)
if err != nil {
return nil, err
}
evc := &EventClient{
conn: conn,
user: user,
password: password,
bus: bus,
decoder: schema.NewDecoder(),
}
go evc.keepAlive()
go evc.HandlePayloads()
return evc, nil
}
func (cl *EventClient) HandlePayloads() {
scanner := bufio.NewScanner(cl.conn)
for scanner.Scan() {
text := strings.Trim(scanner.Text(), "\n\r ")
length := len(text)
if length != 0 {
if strings.HasPrefix(text, "Welcome to the TeamSpeak 3 ServerQuery interface") {
_ = cl.login()
} else if strings.HasPrefix(text, "notify") {
cl.handleEvent(text)
}
}
}
}
func (cl *EventClient) Stop() error {
err := cl.conn.Close()
if err != nil {
return err
}
return nil
}
func (cl *EventClient) login() error {
err := cl.write(fmt.Sprintf("login %s %s", cl.user, cl.password))
if err != nil {
return err
}
return nil
}
func (cl *EventClient) handleEvent(event string) {
eventName, parameters := splitEvent(event)
switch eventName {
case "notifycliententerview":
cl.publishEvent(eventName, parameters, &ClientEnterViewEvent{})
case "notifyclientleftview":
cl.publishEvent(eventName, parameters, &ClientLeftViewEvent{})
case "notifyserveredited":
cl.publishEvent(eventName, parameters, &ServerEditedEvent{})
case "notifychannelpasswordchanged":
cl.publishEvent(eventName, parameters, &ChannelPasswordChangedEvent{})
case "notifychanneldescriptionchanged":
cl.publishEvent(eventName, parameters, &ChannelDescriptionChangedEvent{})
case "notifychannelmoved":
cl.publishEvent(eventName, parameters, &ChannelMovedEvent{})
case "notifychanneledited":
cl.publishEvent(eventName, parameters, &ChannelEditedEvent{})
case "notifychannelcreated":
cl.publishEvent(eventName, parameters, &ChannelCreatedEvent{})
case "notifychanneldeleted":
cl.publishEvent(eventName, parameters, &ChannelDeletedEvent{})
case "notifyclientmoved":
cl.publishEvent(eventName, parameters, &ClientMovedEvent{})
case "notifytextmessage":
cl.publishEvent(eventName, parameters, &TextMessageEvent{})
case "notifytokenused":
cl.publishEvent(eventName, parameters, &TokenUsedEvent{})
default:
fmt.Printf("Event %s not registered.\nPayload %s\n\n", eventName, parameters)
}
}
func (cl *EventClient) publishEvent(eventName string, parameters url.Values, v interface{}) {
err := cl.decoder.Decode(v, parameters)
if err != nil {
fmt.Printf(
"Decoding Failed\nevent %s\nparams: %s\nerror:%s",
eventName, parameters.Encode(), err.Error(),
)
return
}
cl.bus.Publish(eventName, v)
}
func splitEvent(e string) (eventName string, values url.Values) {
split := strings.Split(e, " ")
eventName = split[0]
parameters := split[1:]
values = url.Values{}
applyParameters(parameters, &values)
return
}
func applyParameters(parameters []string, val *url.Values) {
for _, parameter := range parameters {
if strings.Contains(parameter, "|") {
splitArray := strings.Split(parameter, "|")
applyParameters(splitArray, val)
} else {
applyParameter(parameter, val)
}
}
}
func applyParameter(parameter string, val *url.Values) {
splitParam := strings.SplitN(parameter, "=", 2)
if len(splitParam) == 2 {
val.Add(splitParam[0], splitParam[1])
}
}
func (cl *EventClient) keepAlive() {
for {
err := cl.write(" \n")
if err != nil {
break
}
time.Sleep(5 * time.Second)
}
}
func (cl *EventClient) write(payload string) error {
command := fmt.Sprintf("%s\n", payload)
_, err := cl.conn.Write([]byte(command))
return err
}
func (cl *EventClient) SwitchServer(server int) error {
err := cl.write(fmt.Sprintf("use %d", server))
if err != nil {
return err
}
err = cl.registerNotifications()
if err != nil {
return err
}
return nil
}
func (cl *EventClient) registerNotifications() error {
err := cl.write("servernotifyregister event=channel id=0")
if err != nil {
return err
}
err = cl.write("servernotifyregister event=server")
if err != nil {
return err
}
err = cl.write("servernotifyregister event=textserver")
if err != nil {
return err
}
err = cl.write("servernotifyregister event=textchannel")
if err != nil {
return err
}
err = cl.write("servernotifyregister event=textprivate")
if err != nil {
return err
}
return nil
}