147 lines
5.1 KiB
C#
147 lines
5.1 KiB
C#
using System.Collections.Concurrent;
|
|
using SPTarkov.DI.Annotations;
|
|
using SPTarkov.Server.Core.Models.Common;
|
|
using SPTarkov.Server.Core.Models.Spt.Services;
|
|
using SPTarkov.Server.Core.Utils;
|
|
|
|
namespace SPTarkov.Server.Core.Services;
|
|
|
|
[Injectable(InjectionType.Singleton)]
|
|
public class ProfileActivityService(TimeUtil timeUtil)
|
|
{
|
|
private readonly ConcurrentDictionary<MongoId, ProfileActivityData> _activeProfiles = [];
|
|
|
|
public void AddActiveProfile(MongoId sessionId, long clientStartedTimestamp)
|
|
{
|
|
_activeProfiles.AddOrUpdate(
|
|
sessionId,
|
|
// On add value
|
|
key => new ProfileActivityData { ClientStartedTimestamp = clientStartedTimestamp, LastActive = timeUtil.GetTimeStamp() },
|
|
// On Update value, client was started before but crashed or user restarted
|
|
(key, existingValue) =>
|
|
{
|
|
existingValue.ClientStartedTimestamp = clientStartedTimestamp;
|
|
existingValue.LastActive = timeUtil.GetTimeStamp();
|
|
existingValue.RaidData = null;
|
|
return existingValue;
|
|
}
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Does profile exist in activity cache
|
|
/// </summary>
|
|
/// <param name="sessionId">Profile id to check for</param>
|
|
/// <returns>True when profile exists in cache</returns>
|
|
public bool ContainsActiveProfile(MongoId sessionId)
|
|
{
|
|
return _activeProfiles.ContainsKey(sessionId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// TODO: Yes this is terrible, the other alternative is re-doing half of bot-gen which is currently doing guess-work anyway
|
|
/// </summary>
|
|
/// <returns>ProfileActivityRaidData</returns>
|
|
public ProfileActivityRaidData? GetFirstProfileActivityRaidData()
|
|
{
|
|
return !_activeProfiles.IsEmpty ? _activeProfiles.First().Value.RaidData : null;
|
|
}
|
|
|
|
public ProfileActivityRaidData GetProfileActivityRaidData(MongoId sessionId)
|
|
{
|
|
// Handle edge cases where people might close the server but keep the client alive
|
|
if (!ContainsActiveProfile(sessionId))
|
|
{
|
|
AddActiveProfile(sessionId, timeUtil.GetTimeStamp());
|
|
}
|
|
|
|
if (_activeProfiles.TryGetValue(sessionId, out var currentActiveProfile))
|
|
{
|
|
currentActiveProfile.RaidData ??= new();
|
|
|
|
return currentActiveProfile.RaidData;
|
|
}
|
|
|
|
throw new Exception($"Unable to retrieve active profile for session: {sessionId}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Was the requested profile active within the last x minutes
|
|
/// </summary>
|
|
/// <param name="sessionId"> Profile to check </param>
|
|
/// <param name="minutes"> Minutes to check for activity in </param>
|
|
/// <returns> True when profile was active within past x minutes </returns>
|
|
public bool ActiveWithinLastMinutes(MongoId sessionId, int minutes)
|
|
{
|
|
if (!_activeProfiles.TryGetValue(sessionId, out var profileActivity))
|
|
{
|
|
// No record, exit early
|
|
return false;
|
|
}
|
|
|
|
return timeUtil.GetTimeStamp() - profileActivity.LastActive < minutes * 60;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of profile ids that were active in the last x minutes
|
|
/// </summary>
|
|
/// <param name="minutes"> How many minutes from now to search for profiles </param>
|
|
/// <returns> List of active profile ids </returns>
|
|
public List<string> GetActiveProfileIdsWithinMinutes(int minutes)
|
|
{
|
|
var currentTimestamp = timeUtil.GetTimeStamp();
|
|
var result = new List<string>();
|
|
|
|
foreach (var (sessionId, activeProfile) in _activeProfiles)
|
|
{
|
|
// Profile was active in last x minutes, add to return list
|
|
if (currentTimestamp - activeProfile.LastActive < minutes * 60)
|
|
{
|
|
result.Add(sessionId);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the timestamp a profile was last observed active
|
|
/// </summary>
|
|
/// <param name="sessionId"> Profile to update </param>
|
|
public void SetActivityTimestamp(MongoId sessionId)
|
|
{
|
|
if (_activeProfiles.TryGetValue(sessionId, out var currentActiveProfile))
|
|
{
|
|
currentActiveProfile.LastActive = timeUtil.GetTimeStamp();
|
|
}
|
|
}
|
|
|
|
public IReadOnlyList<ProfileActiveClientMods> GetProfileActiveClientMods(MongoId sessionId)
|
|
{
|
|
if (!ContainsActiveProfile(sessionId))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
if (_activeProfiles.TryGetValue(sessionId, out var currentActiveProfile))
|
|
{
|
|
return currentActiveProfile.ActiveClientMods;
|
|
}
|
|
|
|
throw new Exception($"Unable to retrieve active client mods for session: {sessionId}");
|
|
}
|
|
|
|
public void SetProfileActiveClientMods(MongoId sessionId, IReadOnlyList<ProfileActiveClientMods> activeClientMods)
|
|
{
|
|
if (!ContainsActiveProfile(sessionId))
|
|
{
|
|
AddActiveProfile(sessionId, timeUtil.GetTimeStamp());
|
|
}
|
|
|
|
if (_activeProfiles.TryGetValue(sessionId, out var currentActiveProfile))
|
|
{
|
|
currentActiveProfile.ActiveClientMods = activeClientMods;
|
|
}
|
|
}
|
|
}
|