2024-09-18 07:59:20 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"os/exec"
|
2024-09-20 07:57:04 -07:00
|
|
|
"runtime"
|
2024-09-18 07:59:20 -07:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2024-09-20 07:42:34 -07:00
|
|
|
"time"
|
2024-09-18 07:59:20 -07:00
|
|
|
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
|
|
"github.com/mattermost/mattermost/server/public/plugin"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Plugin implements the interface expected by the Mattermost server to communicate between the server and plugin processes.
|
|
|
|
type Plugin struct {
|
|
|
|
plugin.MattermostPlugin
|
|
|
|
|
|
|
|
// configurationLock synchronizes access to the configuration.
|
|
|
|
configurationLock sync.RWMutex
|
|
|
|
|
|
|
|
// configuration is the active plugin configuration. Consult getConfiguration and
|
|
|
|
// setConfiguration for usage.
|
|
|
|
configuration *configuration
|
2024-09-20 07:42:34 -07:00
|
|
|
|
|
|
|
// stopChannel is used to stop the background process monitor when the plugin is deactivated.
|
|
|
|
stopChannel chan struct{}
|
2024-09-18 07:59:20 -07:00
|
|
|
}
|
|
|
|
|
2024-09-18 08:43:24 -07:00
|
|
|
// Known game processes
|
|
|
|
var knownGames = map[string]bool{
|
2024-09-18 09:12:49 -07:00
|
|
|
"FortniteClient-Win64-Shipping.exe": true,
|
2024-09-20 07:42:34 -07:00
|
|
|
"OpenDental.exe": true,
|
2024-09-18 09:12:49 -07:00
|
|
|
"gameprocess": true,
|
2024-09-18 08:43:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetActiveGame scans processes to determine the active game based on known game names
|
2024-09-18 07:59:20 -07:00
|
|
|
func (p *Plugin) GetActiveGame() (string, error) {
|
2024-09-20 07:57:04 -07:00
|
|
|
var cmd *exec.Cmd
|
|
|
|
|
|
|
|
// Check the operating system and execute the appropriate command
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
// For Windows, use tasklist command to get the list of processes
|
|
|
|
cmd = exec.Command("tasklist")
|
|
|
|
} else {
|
|
|
|
// For Linux/macOS, use ps -e command to get the list of processes
|
|
|
|
cmd = exec.Command("ps", "-e")
|
|
|
|
}
|
|
|
|
|
2024-09-18 07:59:20 -07:00
|
|
|
output, err := cmd.Output()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2024-09-20 07:57:04 -07:00
|
|
|
// Convert output to a string and split into lines
|
2024-09-18 07:59:20 -07:00
|
|
|
lines := strings.Split(string(output), "\n")
|
|
|
|
for _, line := range lines {
|
2024-09-18 08:43:24 -07:00
|
|
|
for gameName := range knownGames {
|
2024-09-20 07:57:04 -07:00
|
|
|
// Check if the line contains a known game process
|
2024-09-18 08:43:24 -07:00
|
|
|
if strings.Contains(line, gameName) {
|
|
|
|
return gameName, nil
|
|
|
|
}
|
2024-09-18 07:59:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-20 07:42:34 -07:00
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserGameStatus updates the user's custom status to reflect the game they are playing
|
|
|
|
func (p *Plugin) SetUserGameStatus(userID, game string) error {
|
|
|
|
status := fmt.Sprintf("playing: %s", game)
|
|
|
|
user, appErr := p.API.GetUser(userID)
|
|
|
|
if appErr != nil {
|
|
|
|
return appErr
|
|
|
|
}
|
|
|
|
|
|
|
|
// Serialize the custom status to JSON
|
|
|
|
customStatus := model.CustomStatus{
|
|
|
|
Emoji: "video_game",
|
|
|
|
Text: status,
|
|
|
|
Duration: "0", // Status remains until changed
|
|
|
|
}
|
|
|
|
customStatusJSON, err := json.Marshal(customStatus)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the custom status in user.Props
|
|
|
|
user.Props = map[string]string{
|
|
|
|
"custom_status": string(customStatusJSON),
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, appErr := p.API.UpdateUser(user); appErr != nil {
|
|
|
|
return appErr
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// MonitorGameStatus continuously monitors running processes and updates the user's status
|
|
|
|
func (p *Plugin) MonitorGameStatus(userID string) {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-p.stopChannel:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
game, err := p.GetActiveGame()
|
|
|
|
if err != nil {
|
|
|
|
p.API.LogError("Failed to scan processes", "error", err.Error())
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if game != "" {
|
|
|
|
if err := p.SetUserGameStatus(userID, game); err != nil {
|
|
|
|
p.API.LogError("Failed to set user game status", "error", err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sleep for a defined interval before scanning again
|
|
|
|
time.Sleep(30 * time.Second) // Scan every 30 seconds (can be configurable)
|
|
|
|
}
|
|
|
|
}
|
2024-09-18 07:59:20 -07:00
|
|
|
}
|
|
|
|
|
2024-09-20 07:42:34 -07:00
|
|
|
// ExecuteCommand handles the `/setgame` command to manually set a game
|
2024-09-18 07:59:20 -07:00
|
|
|
func (p *Plugin) ExecuteCommand(c *plugin.Context, command *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
|
|
|
split := strings.Fields(command.Command)
|
|
|
|
|
|
|
|
if len(split) == 0 {
|
|
|
|
return &model.CommandResponse{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
switch split[0] {
|
|
|
|
case "/setgame":
|
|
|
|
var game string
|
|
|
|
var err error
|
|
|
|
if len(split) < 2 {
|
|
|
|
// Scan for active game if no specific game is mentioned
|
|
|
|
game, err = p.GetActiveGame()
|
|
|
|
if err != nil {
|
|
|
|
return nil, &model.AppError{Message: "Failed to scan processes", StatusCode: 500}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
game = strings.Join(split[1:], " ")
|
|
|
|
}
|
|
|
|
|
2024-09-20 07:42:34 -07:00
|
|
|
err = p.SetUserGameStatus(command.UserId, game)
|
2024-09-18 07:59:20 -07:00
|
|
|
if err != nil {
|
2024-09-20 07:42:34 -07:00
|
|
|
return nil, &model.AppError{Message: "Failed to set game status", StatusCode: 500}
|
2024-09-18 07:59:20 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return &model.CommandResponse{
|
2024-09-20 07:42:34 -07:00
|
|
|
Text: fmt.Sprintf("your status has been updated to: %s", game),
|
2024-09-18 07:59:20 -07:00
|
|
|
}, nil
|
|
|
|
default:
|
|
|
|
return &model.CommandResponse{}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-20 07:42:34 -07:00
|
|
|
// OnActivate is called when the plugin is activated
|
2024-09-18 07:59:20 -07:00
|
|
|
func (p *Plugin) OnActivate() error {
|
2024-09-20 07:42:34 -07:00
|
|
|
p.stopChannel = make(chan struct{})
|
|
|
|
|
2024-09-18 07:59:20 -07:00
|
|
|
command := &model.Command{
|
|
|
|
Trigger: "setgame",
|
|
|
|
AutoComplete: true,
|
2024-09-20 07:42:34 -07:00
|
|
|
AutoCompleteDesc: "set the game you are currently playing",
|
2024-09-18 07:59:20 -07:00
|
|
|
AutoCompleteHint: "[game]",
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := p.API.RegisterCommand(command); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-09-20 07:42:34 -07:00
|
|
|
// Start background process monitoring for all users
|
|
|
|
go p.MonitorGameStatus("user_id_here") // Replace with actual user ID(s)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnDeactivate is called when the plugin is deactivated
|
|
|
|
func (p *Plugin) OnDeactivate() error {
|
|
|
|
close(p.stopChannel)
|
2024-09-18 07:59:20 -07:00
|
|
|
return nil
|
|
|
|
}
|