Compare commits
10 Commits
cdn-downlo
...
lightfinde
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53f663fcbf | ||
|
|
47a94cb79f | ||
| f933b40368 | |||
| 7e565ff85e | |||
|
|
707c565ea9 | ||
|
|
6beda853f7 | ||
|
|
23dc6d7ef4 | ||
|
|
f686f7a6da | ||
| 0fe1a43fb2 | |||
|
|
43b9c6f90e |
Submodule LightlessAPI updated: 44fbe10458...f6b0b999cf
@@ -523,6 +523,52 @@ public partial class LightlessHub
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(BroadcastRedisEntry? Entry, TimeSpan? Expiry)> TryGetBroadcastEntryAsync(string hashedCid)
|
||||
{
|
||||
var key = _broadcastConfiguration.BuildRedisKey(hashedCid);
|
||||
RedisValueWithExpiry value;
|
||||
|
||||
try
|
||||
{
|
||||
value = await _redis.Database.StringGetWithExpiryAsync(key).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileLookupFailed", "CID", hashedCid, "Error", ex));
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
if (value.Value.IsNullOrEmpty || value.Expiry is null || value.Expiry <= TimeSpan.Zero)
|
||||
{
|
||||
return (null, value.Expiry);
|
||||
}
|
||||
|
||||
BroadcastRedisEntry? entry;
|
||||
try
|
||||
{
|
||||
entry = JsonSerializer.Deserialize<BroadcastRedisEntry>(value.Value!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileDeserializeFailed", "CID", hashedCid, "Raw", value.Value.ToString(), "Error", ex));
|
||||
return (null, value.Expiry);
|
||||
}
|
||||
|
||||
if (entry is null || !string.Equals(entry.HashedCID, hashedCid, StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileEntryMismatch", "CID", hashedCid, "EntryCID", entry?.HashedCID ?? "null"));
|
||||
return (null, value.Expiry);
|
||||
}
|
||||
|
||||
return (entry, value.Expiry);
|
||||
}
|
||||
|
||||
private static bool HasActiveBroadcast(BroadcastRedisEntry? entry, TimeSpan? expiry) =>
|
||||
entry?.HasOwner() == true && expiry.HasValue && expiry.Value > TimeSpan.Zero;
|
||||
|
||||
private static bool IsActiveBroadcastForUser(BroadcastRedisEntry? entry, TimeSpan? expiry, string userUid) =>
|
||||
HasActiveBroadcast(entry, expiry) && entry!.OwnedBy(userUid);
|
||||
|
||||
private static bool IsValidHashedCid(string? cid)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(cid))
|
||||
@@ -792,6 +838,97 @@ public partial class LightlessHub
|
||||
return new UserProfileDto(user.User, false, data.IsNSFW, data.Base64ProfileImage, data.UserDescription);
|
||||
}
|
||||
|
||||
[Authorize(Policy = "Identified")]
|
||||
public async Task<UserProfileDto?> UserGetLightfinderProfile(string hashedCid)
|
||||
{
|
||||
_logger.LogCallInfo(LightlessHubLogger.Args("LightfinderProfile", hashedCid));
|
||||
|
||||
if (!_broadcastConfiguration.EnableBroadcasting)
|
||||
{
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Lightfinder is currently disabled.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!IsValidHashedCid(hashedCid))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileInvalidCid", hashedCid));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "Invalid Lightfinder target.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
var viewerCid = UserCharaIdent;
|
||||
if (!IsValidHashedCid(viewerCid))
|
||||
{
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "You must be using Lightfinder to open player profiles.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
var (viewerEntry, viewerExpiry) = await TryGetBroadcastEntryAsync(viewerCid).ConfigureAwait(false);
|
||||
if (!IsActiveBroadcastForUser(viewerEntry, viewerExpiry, UserUID))
|
||||
{
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "You must be using Lightfinder to open player profiles.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
var (targetEntry, targetExpiry) = await TryGetBroadcastEntryAsync(hashedCid).ConfigureAwait(false);
|
||||
if (!HasActiveBroadcast(targetEntry, targetExpiry))
|
||||
{
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "That player is not currently using Lightfinder.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(targetEntry!.OwnerUID))
|
||||
{
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "That player is not currently using Lightfinder.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
var targetUser = await DbContext.Users.AsNoTracking()
|
||||
.SingleOrDefaultAsync(u => u.UID == targetEntry.OwnerUID, cancellationToken: RequestAbortedToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (targetUser == null)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("LightfinderProfileMissingUser", hashedCid, "OwnerUID", targetEntry.OwnerUID));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "Unable to load the players profile at this time.").ConfigureAwait(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
var displayAlias = string.IsNullOrWhiteSpace(targetUser.Alias)
|
||||
? "LightfinderUser"
|
||||
: targetUser.Alias;
|
||||
|
||||
var userData = new UserData(
|
||||
UID: hashedCid,
|
||||
Alias: displayAlias,
|
||||
IsAdmin: false,
|
||||
IsModerator: false,
|
||||
HasVanity: false,
|
||||
TextColorHex: targetUser.TextColorHex,
|
||||
TextGlowColorHex: targetUser.TextGlowColorHex);
|
||||
|
||||
var profile = await DbContext.UserProfileData.AsNoTracking()
|
||||
.SingleOrDefaultAsync(u => u.UserUID == targetEntry.OwnerUID, cancellationToken: RequestAbortedToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (profile == null)
|
||||
{
|
||||
return new UserProfileDto(userData, false, null, null, null);
|
||||
}
|
||||
|
||||
if (profile.FlaggedForReport)
|
||||
{
|
||||
return new UserProfileDto(userData, true, null, null, "This profile is flagged for report and pending evaluation");
|
||||
}
|
||||
|
||||
if (profile.ProfileDisabled)
|
||||
{
|
||||
return new UserProfileDto(userData, true, null, null, "This profile was permanently disabled");
|
||||
}
|
||||
|
||||
return new UserProfileDto(userData, false, profile.IsNSFW, profile.Base64ProfileImage, profile.UserDescription);
|
||||
}
|
||||
|
||||
[Authorize(Policy = "Identified")]
|
||||
public async Task UserPushData(UserCharaDataMessageDto dto)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,9 @@ using LightlessSyncShared.Services;
|
||||
using LightlessSyncShared.Utils.Configuration;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using StackExchange.Redis;
|
||||
using StackExchange.Redis.Extensions.Core.Abstractions;
|
||||
using static LightlessSyncServer.Hubs.LightlessHub;
|
||||
|
||||
namespace LightlessSyncServer.Services;
|
||||
|
||||
@@ -52,6 +54,13 @@ public sealed class SystemInfoService : BackgroundService
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableIOWorkerThreads, ioThreads);
|
||||
|
||||
var onlineUsers = (_redis.SearchKeysAsync("UID:*").GetAwaiter().GetResult()).Count();
|
||||
|
||||
var allLightfinderKeys = _redis.SearchKeysAsync("broadcast:*").GetAwaiter().GetResult().Where(c => !c.Contains("owner", StringComparison.Ordinal)).ToHashSet(StringComparer.Ordinal);
|
||||
var allLightfinderItems = _redis.GetAllAsync<BroadcastRedisEntry>(allLightfinderKeys).GetAwaiter().GetResult();
|
||||
|
||||
var countLightFinderUsers = allLightfinderItems.Count;
|
||||
var countLightFinderSyncshells = allLightfinderItems.Count(static l => !string.IsNullOrEmpty(l.Value.GID));
|
||||
|
||||
SystemInfoDto = new SystemInfoDto()
|
||||
{
|
||||
OnlineUsers = onlineUsers,
|
||||
@@ -66,10 +75,12 @@ public sealed class SystemInfoService : BackgroundService
|
||||
using var db = await _dbContextFactory.CreateDbContextAsync(ct).ConfigureAwait(false);
|
||||
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, onlineUsers);
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeLightFinderConnections, countLightFinderUsers);
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugePairs, db.ClientPairs.AsNoTracking().Count());
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugePairsPaused, db.Permissions.AsNoTracking().Where(p => p.IsPaused).Count());
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugePairsPaused, db.Permissions.AsNoTracking().Count(p => p.IsPaused));
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeGroups, db.Groups.AsNoTracking().Count());
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeGroupPairs, db.GroupPairs.AsNoTracking().Count());
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeLightFinderGroups, countLightFinderSyncshells);
|
||||
_lightlessMetrics.SetGaugeTo(MetricsAPI.GaugeUsersRegistered, db.Users.AsNoTracking().Count());
|
||||
}
|
||||
|
||||
|
||||
@@ -295,6 +295,8 @@ public class Startup
|
||||
}, new List<string>
|
||||
{
|
||||
MetricsAPI.GaugeAuthorizedConnections,
|
||||
MetricsAPI.GaugeLightFinderConnections,
|
||||
MetricsAPI.GaugeLightFinderGroups,
|
||||
MetricsAPI.GaugeConnections,
|
||||
MetricsAPI.GaugePairs,
|
||||
MetricsAPI.GaugePairsPaused,
|
||||
|
||||
@@ -9,6 +9,8 @@ public class MetricsAPI
|
||||
public const string GaugeAvailableIOWorkerThreads = "lightless_available_threadpool_io";
|
||||
public const string GaugeUsersRegistered = "lightless_users_registered";
|
||||
public const string CounterUsersRegisteredDeleted = "lightless_users_registered_deleted";
|
||||
public const string GaugeLightFinderConnections = "lightless_lightfinder_connections";
|
||||
public const string GaugeLightFinderGroups = "lightless_lightfinder_groups";
|
||||
public const string GaugePairs = "lightless_pairs";
|
||||
public const string GaugePairsPaused = "lightless_pairs_paused";
|
||||
public const string GaugeFilesTotal = "lightless_files";
|
||||
|
||||
Reference in New Issue
Block a user