199 lines
7.1 KiB
C#
199 lines
7.1 KiB
C#
using GlaxLogger;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace SteamGameTimeTrack;
|
|
|
|
public class Tracker : IDisposable
|
|
{
|
|
private bool _running = true;
|
|
// ReSharper disable once MemberInitializerValueIgnored
|
|
private readonly ILogger _logger = null!;
|
|
internal readonly HashSet<Player> _players = new();
|
|
private readonly Net net;
|
|
private readonly Config config;
|
|
private readonly API api;
|
|
|
|
private readonly TimeSpan _updateFriendsInterval = TimeSpan.FromMinutes(30);
|
|
private readonly TimeSpan _updateGamesInterval = TimeSpan.FromMinutes(60);
|
|
private readonly TimeSpan _updateInfoInterval = TimeSpan.FromSeconds(60);
|
|
private readonly Thread _updateFriendsThread, _updateGamesThread, _updateInfoThread;
|
|
|
|
public Tracker(Config config)
|
|
{
|
|
this.config = config;
|
|
this._logger = new Logger(config.LogLevel, consoleOut: Console.Out);
|
|
this.net = new(this._logger, config.ApiToken);
|
|
this._logger.LogInformation(config.ToString());
|
|
|
|
LoadKnownInformation();
|
|
if(!_players.Any(player => player.IsMe))
|
|
_players.Add(new Player(config.SteamId, net, true));
|
|
|
|
if (config.TrackFriends)
|
|
UpdateFriends();
|
|
|
|
UpdatePlayerGames();
|
|
UpdatePlayerInfo();
|
|
|
|
this._updateFriendsThread = new (() =>
|
|
{
|
|
lock(_updateFriendsThread!)
|
|
{
|
|
while (_running)
|
|
{
|
|
_logger.LogInformation($"Waiting {_updateFriendsInterval:g} for next Friends-List-Update. {DateTime.Now.Add(_updateFriendsInterval):HH:mm:ss zz}");
|
|
Monitor.Wait(_updateFriendsThread, _updateFriendsInterval);
|
|
if (!_running)
|
|
break;
|
|
UpdateFriends();
|
|
}
|
|
}
|
|
});
|
|
this._updateFriendsThread.Start();
|
|
|
|
this._updateGamesThread = new(() =>
|
|
{
|
|
lock(_updateGamesThread!)
|
|
{
|
|
while (_running)
|
|
{
|
|
_logger.LogInformation($"Waiting {_updateGamesInterval:g} for next Player-Games-Update. {DateTime.Now.Add(_updateGamesInterval):HH:mm:ss zz}");
|
|
Monitor.Wait(_updateGamesThread, _updateGamesInterval);
|
|
if (!_running)
|
|
break;
|
|
UpdatePlayerGames();
|
|
}
|
|
}
|
|
});
|
|
this._updateGamesThread.Start();
|
|
|
|
this._updateInfoThread = new(() =>
|
|
{
|
|
lock(_updateInfoThread!)
|
|
{
|
|
while (_running)
|
|
{
|
|
_logger.LogInformation($"Waiting {_updateInfoInterval:g} for next Player-Info-Update. {DateTime.Now.Add(_updateInfoInterval):HH:mm:ss zz}");
|
|
Monitor.Wait(_updateInfoThread, _updateInfoInterval);
|
|
if (!_running)
|
|
break;
|
|
UpdatePlayerInfo();
|
|
}
|
|
}
|
|
});
|
|
this._updateInfoThread.Start();
|
|
|
|
this.api = new(this, config.ApiPort, this._logger);
|
|
}
|
|
|
|
public Tracker(string steamId, string apiToken, bool trackFriends = true, int apiPort = 8888, LogLevel logLevel = LogLevel.Information) : this(new Config()
|
|
{
|
|
ApiToken = apiToken,
|
|
LogLevel = logLevel,
|
|
SteamId = steamId,
|
|
TrackFriends = trackFriends,
|
|
ApiPort = apiPort
|
|
})
|
|
{
|
|
File.WriteAllText("config.json", JsonConvert.SerializeObject(config, Formatting.Indented));
|
|
}
|
|
|
|
private void UpdateFriends()
|
|
{
|
|
this._logger.LogInformation("Getting Friends-List...");
|
|
JObject? friendsResult = net.MakeRequestGetJObject($"https://api.steampowered.com/ISteamUser/GetFriendList/v0001/?steamid={config.SteamId}&relationship=friend");
|
|
if (friendsResult is not null && friendsResult.TryGetValue("friendslist", out JToken? value) && value.SelectToken("friends") is not null)
|
|
{
|
|
this._logger.LogDebug("Got Friends-List.");
|
|
foreach (JToken friend in value["friends"]!)
|
|
{
|
|
string steamid = friend["steamid"]!.Value<string>()!;
|
|
if(!_players.Any(player => player.steamid.Equals(steamid)))
|
|
this._players.Add(new(steamid, net)
|
|
{
|
|
friend_since = friend["friend_since"]!.Value<long>()
|
|
});
|
|
}
|
|
this._logger.LogInformation($"Got {this._players.Count - 1} friends.");
|
|
}
|
|
}
|
|
|
|
private void UpdatePlayerGames()
|
|
{
|
|
int i = 1;
|
|
foreach (Player player in this._players)
|
|
{
|
|
_logger.LogInformation($"Getting GameInfo {i++}/{_players.Count} {player.personaname} {player.steamid}");
|
|
player.GetGames();
|
|
}
|
|
}
|
|
|
|
private void UpdatePlayerInfo()
|
|
{
|
|
this._logger.LogInformation("Getting Player-info...");
|
|
string steamIds = string.Join(',', _players.Select(player => player.steamid));
|
|
JObject? result = net.MakeRequestGetJObject($"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?steamids={steamIds}");
|
|
if (result is not null && result.TryGetValue("response", out JToken? response))
|
|
{
|
|
foreach (JToken player in response["players"]!)
|
|
{
|
|
Player p = player.ToObject<Player>();
|
|
UpdatePlayer(p);
|
|
}
|
|
}
|
|
this._logger.LogInformation("Done getting Player-info...");
|
|
}
|
|
|
|
private void LoadKnownInformation()
|
|
{
|
|
if (!Directory.Exists("states"))
|
|
return;
|
|
foreach (DirectoryInfo subDir in new DirectoryInfo("states").GetDirectories())
|
|
{
|
|
FileInfo? latest = subDir.GetFiles().MaxBy(file => file.CreationTimeUtc);
|
|
if (latest is not null)
|
|
{
|
|
Player player = JsonConvert.DeserializeObject<Player>(File.ReadAllText(latest.FullName), new Player.PlayerJsonConverter(net));
|
|
this._players.Add(player);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdatePlayer(Player player)
|
|
{
|
|
this._logger.LogDebug($"Updating Player {player.personaname} {player.steamid}");
|
|
Player p = this._players.First(pp => pp.steamid.Equals(player.steamid));
|
|
this._players.Remove(p);
|
|
Player updated = p.WithInfo(player);
|
|
|
|
this._players.Add(updated);
|
|
if (p.Diffs(updated, out string diffStr))
|
|
{
|
|
updated.Export();
|
|
this._logger.LogDebug($"Diffs: {diffStr}");
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
this._logger.LogInformation("Stopping...");
|
|
_running = false;
|
|
lock (_updateInfoThread)
|
|
{
|
|
Monitor.Pulse(_updateInfoThread);
|
|
}
|
|
lock (_updateGamesThread)
|
|
{
|
|
Monitor.Pulse(_updateGamesThread);
|
|
}
|
|
lock (_updateFriendsThread)
|
|
{
|
|
Monitor.Pulse(_updateFriendsThread);
|
|
}
|
|
this._logger.LogInformation("Exporting Player-States...");
|
|
foreach (Player player in this._players)
|
|
player.ShuttingDownSaveSessions();
|
|
}
|
|
} |