diff --git a/README.md b/README.md index 36035c4..36c5f2c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,10 @@ This program is configured using environment variables: - `TS_QUERY_ADDR`: Address to the TeamSpeak ServerQuery port. Example: `127.0.0.1:10011` - `TS_QUERY_USER`: The username you selected for ServerQuery in the setup - `TS_QUERY_PASS`: The password TeamSpeak generated for ServerQuery in the setup +- `TS_QUERY_SERVER_ID`: Virtual server ID to monitor. Defaults to `1` - `TS_DISCORD_WEBHOOK`: Webhook URL for Discord. You can create this from the channel "Integrations" page +- `TS_DISCORD_AVATAR`: Optional URL for Discord bot avatar +- `TS_DISCORD_USERNAME`: Optional nickname for Discord bot ## Run it [![docker hub](https://img.shields.io/docker/v/aramperes/ts-activity?color=%232496ed&label=docker%20hub&logo=docker&logoColor=fff&sort=semver)](https://hub.docker.com/r/aramperes/ts-activity) diff --git a/cmd.go b/cmd.go index 674fe48..54e4b9e 100644 --- a/cmd.go +++ b/cmd.go @@ -1,6 +1,7 @@ package main import ( + "errors" "fmt" "log" "os" @@ -10,26 +11,83 @@ import ( "github.com/multiplay/go-ts3" ) +// App holds the configuration +type App struct { + discordURL string + discordUsername string + discordAvatarURL *string + tsQueryAddr string + tsQueryUser string + tsQueryPass string + tsQueryServerID int +} + +func appFromEnv() (*App, error) { + discordURL := os.Getenv("TS_DISCORD_WEBHOOK") + if discordURL == "" { + return nil, errors.New("must configure: TS_DISCORD_WEBHOOK") + } + discordUsername := os.Getenv("TS_DISCORD_USERNAME") + if discordUsername == "" { + discordUsername = "TeamSpeak" + } + + var discordAvatarURL *string = nil + if val, ok := os.LookupEnv("TS_DISCORD_AVATAR"); ok { + discordAvatarURL = &val + } + + tsQueryAddr := os.Getenv("TS_QUERY_ADDR") + if tsQueryAddr == "" { + return nil, errors.New("must configure: TS_QUERY_ADDR") + } + tsQueryUser := os.Getenv("TS_QUERY_USER") + if tsQueryUser == "" { + return nil, errors.New("must configure: TS_QUERY_USER") + } + tsQueryPass := os.Getenv("TS_QUERY_PASS") + if tsQueryPass == "" { + return nil, errors.New("must configure: TS_QUERY_PASS") + } + tsQueryServerID := 1 + if val, ok := os.LookupEnv("TS_QUERY_SERVER_ID"); ok { + val, err := strconv.Atoi(val) + if err == nil { + tsQueryServerID = val + } else { + return nil, errors.New("invalid TS_QUERY_SERVER_ID, must be int") + } + } + + return &App{ + discordURL: discordURL, + discordUsername: discordUsername, + discordAvatarURL: discordAvatarURL, + tsQueryAddr: tsQueryAddr, + tsQueryUser: tsQueryUser, + tsQueryPass: tsQueryPass, + tsQueryServerID: tsQueryServerID, + }, nil +} + func main() { - discord := os.Getenv("TS_DISCORD_WEBHOOK") - if discord == "" { - log.Fatal("Must configure: TS_DISCORD_WEBHOOK") + app, err := appFromEnv() + if err != nil { + log.Fatal(err) } // Connect and login - c, err := ts3.NewClient(os.Getenv("TS_QUERY_ADDR")) + c, err := ts3.NewClient(app.tsQueryAddr) if err != nil { log.Fatal(err) } defer c.Close() - user := os.Getenv("TS_QUERY_USER") - pass := os.Getenv("TS_QUERY_PASS") - if err := c.Login(user, pass); err != nil { + if err := c.Login(app.tsQueryUser, app.tsQueryPass); err != nil { log.Fatal(err) } - if err := c.Use(1); err != nil { + if err := c.Use(app.tsQueryServerID); err != nil { log.Fatal(err) } @@ -66,7 +124,6 @@ func main() { for { event := <-notifs - log.Println("=>", event) if event.Type == "cliententerview" { if event.Data["client_type"] != "0" { @@ -89,7 +146,7 @@ func main() { clientMap[clientID] = clientNick if !previous { - clientConnected(discord, clientNick) + app.clientConnected(clientNick) } } else if event.Type == "clientleftview" { clientID, ok := event.Data["clid"] @@ -105,41 +162,29 @@ func main() { } delete(clientMap, clientID) - clientDisconnected(discord, clientNick) + app.clientDisconnected(clientNick) } } } -func clientConnected(discord string, nick string) { - bot := os.Getenv("TS_DISCORD_USERNAME") - if bot == "" { - bot = "Jeff" +func (app *App) sendWebhook(content string) { + message := discordwebhook.Message{ + Username: &app.discordUsername, + Content: &content, + AvatarUrl: app.discordAvatarURL, } + if err := discordwebhook.SendMessage(app.discordURL, message); err != nil { + log.Println("Failed to log Discord message:", err) + } +} + +func (app *App) clientConnected(nick string) { content := fmt.Sprintf("Client connected: %s", nick) - message := discordwebhook.Message{ - Username: &bot, - Content: &content, - } - - if err := discordwebhook.SendMessage(discord, message); err != nil { - log.Println("Failed to log Discord message:", err) - } + app.sendWebhook(content) } -func clientDisconnected(discord string, nick string) { - bot := os.Getenv("TS_DISCORD_USERNAME") - if bot == "" { - bot = "Jeff" - } - +func (app *App) clientDisconnected(nick string) { content := fmt.Sprintf("Client disconnected: %s", nick) - message := discordwebhook.Message{ - Username: &bot, - Content: &content, - } - - if err := discordwebhook.SendMessage(discord, message); err != nil { - log.Println("Failed to log Discord message:", err) - } + app.sendWebhook(content) } diff --git a/helm/ts-activity/templates/deployment.yaml b/helm/ts-activity/templates/deployment.yaml index edfd5fd..ef8efe5 100644 --- a/helm/ts-activity/templates/deployment.yaml +++ b/helm/ts-activity/templates/deployment.yaml @@ -32,8 +32,16 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: + {{- with .Values.config.discordUsername }} - name: TS_DISCORD_USERNAME - value: "{{ .Values.config.discordUsername | default "Jeff" }}" + value: {{ . | quote }} + {{- end }} + {{- with .Values.config.discordAvatar }} + - name: TS_DISCORD_AVATAR + value: {{ . | quote }} + {{- end }} + - name: TS_QUERY_SERVER_ID + value: {{ .Values.config.serverQueryId | quote }} - name: TS_QUERY_ADDR value: "{{ .Values.config.serverQueryAddr | required "must provide serverQueryAddr" }}" - name: TS_QUERY_USER diff --git a/helm/ts-activity/values.yaml b/helm/ts-activity/values.yaml index 20c0371..3aad80e 100644 --- a/helm/ts-activity/values.yaml +++ b/helm/ts-activity/values.yaml @@ -5,19 +5,23 @@ image: repository: aramperes/ts-activity pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart version. + # Overrides the image tag whose default is the chart appVersion. tag: "" config: # Discord username displayed in webhook messages. # Defaults to 'Jeff' discordUsername: "" + # Discord avatar displayed in webhook messages. + discordAvatar: "" # Address to plain ServerQuery. Usually :10011 serverQueryAddr: "" # Secret containing 'username' and 'password' for ServerQuery. serverQuerySecret: "" # Secret containing 'discord' with the Webhook URL. webhookSecret: "" + # TeamSpeak virtual server ID. + serverQueryId: 1 imagePullSecrets: [] nameOverride: ""