Skip to content

Commit

Permalink
Merge pull request #27 from leighmacdonald/23-player-query
Browse files Browse the repository at this point in the history
Initial Player Query Window
  • Loading branch information
leighmacdonald authored Mar 3, 2023
2 parents c7d7774 + 766e976 commit e7a14b0
Show file tree
Hide file tree
Showing 10 changed files with 323 additions and 20 deletions.
17 changes: 14 additions & 3 deletions internal/detector/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ func (bd *BD) gameStateTracker(ctx context.Context) {
var sourcePlayer *model.Player
if update.source.Valid() {
sourcePlayer = bd.GetPlayer(update.source)
if sourcePlayer == nil && update.kind != updateStatus {
if sourcePlayer == nil && update.kind != updateStatus && update.kind != updateMark {
// Only register a new user to track once we received a status line
continue
}
Expand All @@ -600,7 +600,8 @@ func (bd *BD) gameStateTracker(ctx context.Context) {
log.Printf("updateStatus error: %v\n", errUpdate)
}
case updateMark:
if errUpdate := bd.onUpdateMark(update.data.(updateMarkEvent)); errUpdate != nil {
d := update.data.(updateMarkEvent)
if errUpdate := bd.onUpdateMark(d); errUpdate != nil {
log.Printf("updateMark error: %v\n", errUpdate)
}
case updateWhitelist:
Expand Down Expand Up @@ -783,10 +784,20 @@ func (bd *BD) onUpdateWhitelist(event updateWhitelistEvent) error {

func (bd *BD) onUpdateMark(status updateMarkEvent) error {
player := bd.GetPlayer(status.target)
if player == nil {
player = model.NewPlayer(status.target, "")
if err := bd.store.GetPlayer(context.Background(), status.target, player); err != nil {
return err
}
}
name := player.Name
if name == "" {
name = player.NamePrevious
}
if errMark := bd.rules.Mark(rules.MarkOpts{
SteamID: status.target,
Attributes: status.attrs,
Name: player.Name,
Name: name,
}); errMark != nil {
return errors.Wrap(errMark, "Failed to add mark")
}
Expand Down
10 changes: 10 additions & 0 deletions internal/model/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ type SteamIDErrFunc func(sid64 steamid.SID64) error

type GetPlayer func(sid64 steamid.SID64) *Player

type GetPlayerOffline func(ctx context.Context, sid64 steamid.SID64, player *Player) error

type SearchOpts struct {
Query string
}

type SavePlayer func(ctx context.Context, state *Player) error

type SearchPlayers func(ctx context.Context, opts SearchOpts) (PlayerCollection, error)

type MarkFunc func(sid64 steamid.SID64, attrs []string) error

type NoteFunc func(sid64 steamid.SID64, note string) error
Expand Down
1 change: 1 addition & 0 deletions internal/platform/linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package platform

import (
"github.com/mitchellh/go-homedir"
"github.com/mitchellh/go-ps"
"log"
"os/exec"
"strings"
Expand Down
117 changes: 115 additions & 2 deletions internal/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"embed"
"fmt"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite"
"github.com/golang-migrate/migrate/v4/source/iofs"
Expand All @@ -24,9 +25,11 @@ type DataStore interface {
SaveName(ctx context.Context, steamID steamid.SID64, name string) error
SaveMessage(ctx context.Context, message *model.UserMessage) error
SavePlayer(ctx context.Context, state *model.Player) error
SearchPlayers(ctx context.Context, opts model.SearchOpts) (model.PlayerCollection, error)
FetchNames(ctx context.Context, sid64 steamid.SID64) (model.UserNameHistoryCollection, error)
FetchMessages(ctx context.Context, sid steamid.SID64) (model.UserMessageCollection, error)
LoadOrCreatePlayer(ctx context.Context, steamID steamid.SID64, player *model.Player) error
GetPlayer(ctx context.Context, steamID steamid.SID64, player *model.Player) error
}

type SqliteStore struct {
Expand Down Expand Up @@ -200,6 +203,116 @@ func (store *SqliteStore) SavePlayer(ctx context.Context, state *model.Player) e
return store.updatePlayer(ctx, state)
}

func (store *SqliteStore) SearchPlayers(ctx context.Context, opts model.SearchOpts) (model.PlayerCollection, error) {
sid64, errSid := steamid.StringToSID64(opts.Query)
if errSid == nil && sid64.Valid() {
var player model.Player
if errPlayer := store.LoadOrCreatePlayer(ctx, sid64, &player); errPlayer != nil {
return nil, errPlayer
}
player.SteamId = sid64
return model.PlayerCollection{&player}, nil
}
const query = `
SELECT
p.steam_id,
p.visibility,
p.real_name,
p.account_created_on,
p.avatar_hash,
p.community_banned,
p.game_bans,
p.vac_bans,
p.last_vac_ban_on,
p.kills_on,
p.deaths_by,
p.rage_quits,
p.notes,
p.whitelist,
p.created_on,
p.updated_on,
p.profile_updated_on,
pn.name
FROM player p
LEFT JOIN player_names pn ON p.steam_id = pn.steam_id
WHERE pn.name LIKE '%%%s%%'
ORDER BY p.updated_on DESC
LIMIT 1000`

rows, rowErr := store.db.Query(fmt.Sprintf(query, opts.Query))
if rowErr != nil {
return nil, rowErr
}
defer util.LogClose(rows)
var col model.PlayerCollection
for rows.Next() {
var prevName *string
var player model.Player
if errScan := rows.Scan(&player.SteamId, &player.Visibility, &player.RealName, &player.AccountCreatedOn, &player.AvatarHash,
&player.CommunityBanned, &player.NumberOfGameBans, &player.NumberOfVACBans,
&player.LastVACBanOn, &player.KillsOn, &player.DeathsBy, &player.RageQuits, &player.Notes,
&player.Whitelisted, &player.CreatedOn, &player.UpdatedOn, &player.ProfileUpdatedOn, &prevName,
); errScan != nil {
return nil, errScan
}
if prevName != nil {
player.Name = *prevName
player.NamePrevious = *prevName
}
col = append(col, &player)

}
return col, nil
}

func (store *SqliteStore) GetPlayer(ctx context.Context, steamID steamid.SID64, player *model.Player) error {
const query = `
SELECT
p.visibility,
p.real_name,
p.account_created_on,
p.avatar_hash,
p.community_banned,
p.game_bans,
p.vac_bans,
p.last_vac_ban_on,
p.kills_on,
p.deaths_by,
p.rage_quits,
p.notes,
p.whitelist,
p.created_on,
p.updated_on,
p.profile_updated_on,
pn.name
FROM player p
LEFT JOIN player_names pn ON p.steam_id = pn.steam_id
WHERE p.steam_id = ?
ORDER BY pn.created_on DESC
LIMIT 1`

var prevName *string
rowErr := store.db.
QueryRowContext(ctx, query, steamID).
Scan(&player.Visibility, &player.RealName, &player.AccountCreatedOn, &player.AvatarHash,
&player.CommunityBanned, &player.NumberOfGameBans, &player.NumberOfVACBans,
&player.LastVACBanOn, &player.KillsOn, &player.DeathsBy, &player.RageQuits, &player.Notes,
&player.Whitelisted, &player.CreatedOn, &player.UpdatedOn, &player.ProfileUpdatedOn, &prevName,
)
if rowErr != nil {
if rowErr != sql.ErrNoRows {
return rowErr
}
player.Dangling = true
}
player.SteamId = steamID
player.Dangling = false
if prevName != nil {
player.NamePrevious = *prevName
}
return nil
}

func (store *SqliteStore) LoadOrCreatePlayer(ctx context.Context, steamID steamid.SID64, player *model.Player) error {
const query = `
SELECT
Expand Down Expand Up @@ -228,18 +341,18 @@ func (store *SqliteStore) LoadOrCreatePlayer(ctx context.Context, steamID steami

var prevName *string
rowErr := store.db.
QueryRow(query, steamID).
QueryRowContext(ctx, query, steamID).
Scan(&player.Visibility, &player.RealName, &player.AccountCreatedOn, &player.AvatarHash,
&player.CommunityBanned, &player.NumberOfGameBans, &player.NumberOfVACBans,
&player.LastVACBanOn, &player.KillsOn, &player.DeathsBy, &player.RageQuits, &player.Notes,
&player.Whitelisted, &player.CreatedOn, &player.UpdatedOn, &player.ProfileUpdatedOn, &prevName,
)
player.SteamId = steamID
if rowErr != nil {
if rowErr != sql.ErrNoRows {
return rowErr
}
player.Dangling = true
player.SteamId = steamID
return store.SavePlayer(ctx, player)
}
player.Dangling = false
Expand Down
6 changes: 6 additions & 0 deletions internal/translations/active.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ menu_name_history:
label_message_count:
one: "Message Count: "

label_result_count:
one: "Results: "

window_name_history:
one: "Name History: {{ .SteamId }}"

Expand All @@ -221,6 +224,9 @@ window_chat_history_user:
window_chat_history_game:
one: "Chat History"

window_player_search:
one: "Player Search"

window_mark_custom:
one: "Mark with custom attribute"

Expand Down
2 changes: 2 additions & 0 deletions internal/translations/translations.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
LabelEnabled Key = "label_enabled"
LabelAttributeName Key = "label_attribute_name"
LabelMessageCount Key = "label_message_count"
LabelResultCount Key = "label_result_count"
LabelAboutBuiltBy Key = "label_about_built_by"
LabelAboutBuildDate Key = "label_about_build_date"
LabelAboutVersion Key = "label_about_version"
Expand Down Expand Up @@ -93,6 +94,7 @@ const (
WindowNameHistory Key = "window_name_history"
WindowChatHistoryUser Key = "window_chat_history_user"
WindowChatHistoryGame Key = "window_chat_history_game"
WindowPlayerSearch Key = "window_player_search"
TitleSettings Key = "title_settings"
WindowMarkCustom Key = "window_mark_custom"
ErrorNameEmpty Key = "error_name_empty"
Expand Down
41 changes: 29 additions & 12 deletions internal/ui/menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,49 +178,59 @@ func generateKickMenu(ctx context.Context, userId int64, kickFunc model.KickFunc

func generateUserMenu(ctx context.Context, app fyne.App, window fyne.Window, steamId steamid.SID64, userId int64, cb callBacks,
knownAttributes binding.StringList, links []model.LinkConfig) *fyne.Menu {
menu := fyne.NewMenu("User Actions",
&fyne.MenuItem{

var items []*fyne.MenuItem
if userId > 0 {
items = append(items, &fyne.MenuItem{
Icon: theme.CheckButtonCheckedIcon(),
ChildMenu: generateKickMenu(ctx, userId, cb.kickFunc),
Label: translations.One(translations.MenuCallVote)},
&fyne.MenuItem{
Label: translations.One(translations.MenuCallVote)})
}
items = append(items, []*fyne.MenuItem{
{
Icon: theme.ZoomFitIcon(),
ChildMenu: generateAttributeMenu(window, steamId, knownAttributes, cb.markFn),
Label: translations.One(translations.MenuMarkAs)},
&fyne.MenuItem{
{
Icon: theme.SearchIcon(),
ChildMenu: generateExternalLinksMenu(steamId, links, app.OpenURL),
Label: translations.One(translations.MenuOpenExternal)},
&fyne.MenuItem{
{
Icon: theme.ContentCopyIcon(),
ChildMenu: generateSteamIdMenu(window, steamId),
Label: translations.One(translations.MenuCopySteamId)},
&fyne.MenuItem{
{
Icon: theme.ListIcon(),
Action: func() {
cb.createUserChat(steamId)
},
Label: translations.One(translations.MenuChatHistory)},
&fyne.MenuItem{
{
Icon: theme.VisibilityIcon(),
Action: func() {
cb.createNameHistory(steamId)
},
Label: translations.One(translations.MenuNameHistory)},
&fyne.MenuItem{
{
Icon: theme.VisibilityOffIcon(),
Action: func() {
if err := cb.whitelistFn(steamId); err != nil {
showUserError(err, window)
}
},
Label: translations.One(translations.MenuWhitelist)},
&fyne.MenuItem{
{
Icon: theme.DocumentCreateIcon(),
Action: func() {
offline := false
player := cb.getPlayer(steamId)
if player == nil {
return
player = model.NewPlayer(steamId, "")
if errOffline := cb.getPlayerOffline(ctx, steamId, player); errOffline != nil {
showUserError(errors.Errorf("Unknown player: %v", errOffline), window)
return
}
offline = true
}
entry := widget.NewMultiLineEntry()
entry.SetMinRowsVisible(30)
Expand All @@ -239,11 +249,18 @@ func generateUserMenu(ctx context.Context, app fyne.App, window fyne.Window, ste
player.Notes = entry.Text
player.Touch()
player.Unlock()
if offline {
if errSave := cb.savePlayer(ctx, player); errSave != nil {
log.Printf("Failed to save: %v\n", errSave)
}
}

}, window)
d.Resize(fyne.NewSize(700, 600))
d.Show()
},
Label: "Edit Notes"},
)
}...)
menu := fyne.NewMenu("User Actions", items...)
return menu
}
Loading

0 comments on commit e7a14b0

Please sign in to comment.