Archived
195 lines
4.6 KiB
Go
195 lines
4.6 KiB
Go
// slacktsbot by Daniel Aberger
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Payload struct {
|
|
Channel string `json:"channel"`
|
|
IconEmoji string `json:"icon_emoji"`
|
|
Text string `json:"text"`
|
|
Username string `json:"username"`
|
|
}
|
|
|
|
var (
|
|
users = map[string]bool{}
|
|
|
|
port *string = flag.String("port", "12345", "teamspeak 3 query port number")
|
|
host *string = flag.String("host", "your.ts-server.com", "teamspeak 3 server host")
|
|
user *string = flag.String("user", "youradminuser", "teamspeak 3 server admin user")
|
|
pass *string = flag.String("password", "yourpassword", "teamspeak 3 server admin user password")
|
|
slackhookurl *string = flag.String("slack", "https://hooks.slack.com/services/YOURSLACKWEBHOOKURL", "slack webhook url")
|
|
slackchannel *string = flag.String("slackchan", "#yourslackchannel", "slack channel name")
|
|
)
|
|
|
|
func init() {
|
|
// ./slacktsbot -port=12345 -host=your.ts-server.com -user=yourusername -pass=yourpassword
|
|
flag.Parse()
|
|
}
|
|
func main() {
|
|
|
|
for {
|
|
var err error
|
|
users, err = getUsers()
|
|
if err != nil {
|
|
log.Println(err)
|
|
log.Println("Trying again in 60 seconds.")
|
|
time.Sleep(60 * time.Second)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
for {
|
|
neu, err := getUsers()
|
|
if err != nil {
|
|
log.Println(err)
|
|
time.Sleep(50 * time.Second)
|
|
} else {
|
|
for i, _ := range neu {
|
|
if users[i] != neu[i] {
|
|
generateAndSendPayload(i, "join")
|
|
}
|
|
}
|
|
for i, _ := range users {
|
|
if users[i] != neu[i] {
|
|
generateAndSendPayload(i, "leave")
|
|
}
|
|
}
|
|
users = neu
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
|
}
|
|
}
|
|
|
|
func generateAndSendPayload(user string, action string) {
|
|
payload := Payload{
|
|
Channel: *slackchannel,
|
|
IconEmoji: ":poop:",
|
|
Text: "",
|
|
Username: "TS3 Bot",
|
|
}
|
|
var actiontext string
|
|
if action == "join" {
|
|
actiontext = " joined TS3."
|
|
}
|
|
if action == "leave" {
|
|
actiontext = " left TS3."
|
|
}
|
|
timestamp := time.Now().Format(time.RFC822)
|
|
payload.Text = timestamp + " " + user + actiontext
|
|
b, err := json.Marshal(payload)
|
|
if err != nil {
|
|
fmt.Println("error:", err)
|
|
} else {
|
|
sendToSlack(b)
|
|
}
|
|
}
|
|
|
|
func sendToSlack(json []byte) {
|
|
url := *slackhookurl
|
|
log.Println("URL:>", url)
|
|
|
|
var jsonStr = json
|
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
|
|
req.Header.Set("X-Custom-Header", "myvalue")
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
log.Println("response Status:", resp.Status)
|
|
//log.Println("response Headers:", resp.Header)
|
|
//body, _ := ioutil.ReadAll(resp.Body)
|
|
//log.Println("response Body:", string(body))
|
|
}
|
|
|
|
func getUsers() (u map[string]bool, e error) {
|
|
log.Println("Querying Teamspeak 3 server '" + *host + ":" + *port + "'...")
|
|
conn, err := net.Dial("tcp", *host+":"+*port)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
reader := bufio.NewReader(conn)
|
|
writer := bufio.NewWriter(conn)
|
|
|
|
for i := 0; i < 2; i++ { // get rid of banner
|
|
_, _, err := reader.ReadLine()
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
log.Println("Connection closed by foreign host.")
|
|
}
|
|
return nil, err
|
|
}
|
|
}
|
|
writer.WriteString("login " + *user + " " + *pass + "\n")
|
|
writer.Flush()
|
|
_, _, err = reader.ReadLine() // get rid of "OK" message
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
log.Println("Connection closed by foreign host.")
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
writer.WriteString("use sid=1\n")
|
|
writer.Flush()
|
|
_, _, err = reader.ReadLine() // get rid of "OK" message
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
log.Println("Connection closed by foreign host.")
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
writer.WriteString("clientlist\n")
|
|
writer.Flush()
|
|
line, _, err := reader.ReadLine() // get rid of "OK" message
|
|
if err != nil {
|
|
if err.Error() == "EOF" {
|
|
log.Println("Connection closed by foreign host.")
|
|
}
|
|
return nil, err
|
|
}
|
|
users_raw := string(line)
|
|
|
|
re := regexp.MustCompile("client_nickname=(.*?) ")
|
|
users_still_raw := re.FindAllString(users_raw, -1)
|
|
|
|
for i := range users_still_raw {
|
|
users_still_raw[i] = strings.Trim(users_still_raw[i], " ")
|
|
users_still_raw[i] = strings.Replace(users_still_raw[i], "client_nickname=", "", 1)
|
|
users_still_raw[i] = strings.Replace(users_still_raw[i], "\\s", " ", -1)
|
|
}
|
|
users := make([]string, 0)
|
|
for i := range users_still_raw {
|
|
if !strings.HasPrefix(users_still_raw[i], "serveradmin from") {
|
|
users = append(users, users_still_raw[i])
|
|
}
|
|
}
|
|
result := make(map[string]bool)
|
|
for i := range users {
|
|
result[users[i]] = true
|
|
}
|
|
conn.Close()
|
|
return result, nil
|
|
}
|