mirror of
https://github.com/CannedNet/CannedNet.git
synced 2026-10-25 15:09:23 -07:00
attempt to fix notifications for ConsumableMappingAdded
it didnt work
This commit is contained in:
@@ -28,7 +28,11 @@ public class NotificationsHub : Hub
|
||||
|
||||
public async Task SubscribeToPlayers(SubscriptionList subscriptionList)
|
||||
{
|
||||
await _notificationService.SubscribeToPlayers(Context.ConnectionId, subscriptionList);
|
||||
var hubContext = GetService<IHubContext<NotificationsHub>>();
|
||||
if (hubContext != null)
|
||||
{
|
||||
await _notificationService.SubscribeToPlayers(Context.ConnectionId, subscriptionList, hubContext);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<HashSet<int>> GetSubscriptions()
|
||||
@@ -40,4 +44,9 @@ public class NotificationsHub : Hub
|
||||
{
|
||||
return _notificationService;
|
||||
}
|
||||
|
||||
private T? GetService<T>() where T : class
|
||||
{
|
||||
return Context.GetHttpContext()?.RequestServices.GetService(typeof(T)) as T;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,21 @@ public class BuyItemRequest
|
||||
public int? CouponConsumablePlayerMappingId { get; set; }
|
||||
|
||||
[JsonPropertyName("Gift")]
|
||||
public object? Gift { get; set; }
|
||||
public GiftRequest? Gift { get; set; }
|
||||
}
|
||||
|
||||
public class GiftRequest
|
||||
{
|
||||
[JsonPropertyName("ToPlayerId")]
|
||||
public int ToPlayerId { get; set; }
|
||||
|
||||
[JsonPropertyName("Message")]
|
||||
public string Message { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("Anonymous")]
|
||||
public bool Anonymous { get; set; }
|
||||
|
||||
[JsonPropertyName("GiftContext")]
|
||||
public int GiftContext { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ public class NotificationMessage
|
||||
public string? NotificationId { get; set; }
|
||||
|
||||
[JsonPropertyName("notificationType")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public PushNotificationId? NotificationType { get; set; }
|
||||
|
||||
[JsonPropertyName("id")]
|
||||
|
||||
@@ -1353,15 +1353,26 @@ public class APIController
|
||||
db.TokenBalances.Update(tokenBalance);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Store each gift in the database as a received gift with all properties
|
||||
var receiverAccountId = id;
|
||||
int? senderPlayerId = null;
|
||||
|
||||
if (buyRequest.Gift != null)
|
||||
{
|
||||
receiverAccountId = buyRequest.Gift.ToPlayerId;
|
||||
if (!buyRequest.Gift.Anonymous)
|
||||
{
|
||||
senderPlayerId = id;
|
||||
}
|
||||
}
|
||||
|
||||
var storedGifts = new List<ReceivedGift>();
|
||||
foreach (var giftDrop in storefrontItem.GiftDrops)
|
||||
{
|
||||
var receivedGift = new ReceivedGift
|
||||
{
|
||||
ReceiverAccountId = id,
|
||||
FromPlayerId = null,
|
||||
Message = "A gift for you <3",
|
||||
ReceiverAccountId = receiverAccountId,
|
||||
FromPlayerId = senderPlayerId,
|
||||
Message = buyRequest.Gift?.Message ?? "A gift for you <3",
|
||||
ConsumableItemDesc = giftDrop.ConsumableItemDesc ?? string.Empty,
|
||||
AvatarItemDesc = giftDrop.AvatarItemDesc ?? string.Empty,
|
||||
FriendlyName = giftDrop.FriendlyName ?? string.Empty,
|
||||
@@ -1375,7 +1386,7 @@ public class APIController
|
||||
Platform = -1,
|
||||
PlatformsToSpawnOn = -1,
|
||||
BalanceType = 0,
|
||||
GiftContext = giftDrop.Context,
|
||||
GiftContext = buyRequest.Gift?.GiftContext ?? giftDrop.Context,
|
||||
GiftRarity = giftDrop.Rarity,
|
||||
ReceivedAt = DateTime.UtcNow,
|
||||
IsConsumed = false
|
||||
@@ -1386,7 +1397,6 @@ public class APIController
|
||||
}
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Build the response with stored gift IDs
|
||||
var giftData = storedGifts.Select(rg => new GiftData
|
||||
{
|
||||
Id = rg.Id,
|
||||
@@ -1424,11 +1434,7 @@ public class APIController
|
||||
Platform = -1
|
||||
};
|
||||
|
||||
// Send notification for purchase
|
||||
try
|
||||
{
|
||||
var hubContext = app.Services.GetService<IHubContext>();
|
||||
if (hubContext != null)
|
||||
{
|
||||
var purchaseNotification = notificationService.CreateNotification(
|
||||
PushNotificationId.StorefrontBalancePurchase,
|
||||
@@ -1442,10 +1448,13 @@ public class APIController
|
||||
{ "NewBalance", tokenBalance.Balance }
|
||||
}
|
||||
);
|
||||
await notificationService.SendNotificationToPlayer(null, hubContext, id, purchaseNotification);
|
||||
await notificationService.SendNotificationToPlayer(id, purchaseNotification);
|
||||
}
|
||||
catch (Exception notifEx)
|
||||
{
|
||||
Console.WriteLine($"Error sending purchase notification: {notifEx.Message}");
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
return Results.Ok(response);
|
||||
}
|
||||
@@ -1501,7 +1510,6 @@ public class APIController
|
||||
}
|
||||
}
|
||||
|
||||
// Get all earnable rewards for this context
|
||||
var earnableRewards = await db.EarnableRewards
|
||||
.Where(er => er.RewardContext == giftContext)
|
||||
.ToListAsync();
|
||||
@@ -1515,30 +1523,25 @@ public class APIController
|
||||
int giftRarity = 0;
|
||||
string consumableItemDesc = "";
|
||||
|
||||
// 60/40 roll - 60% earnable item, 40% tokens
|
||||
bool isEarnableItem = random.Next(0, 100) < 60;
|
||||
|
||||
if (isEarnableItem && earnableRewards.Any())
|
||||
{
|
||||
// Get rewards that are avatar items (have avatarItemDesc set)
|
||||
var avatarRewards = earnableRewards.Where(er => !string.IsNullOrEmpty(er.AvatarItemDesc)).ToList();
|
||||
|
||||
if (avatarRewards.Any())
|
||||
{
|
||||
// Get all avatar items the player currently owns
|
||||
var ownedAvatarItems = await db.AvatarItems
|
||||
.Where(ai => ai.OwnerAccountId == id)
|
||||
.Select(ai => ai.AvatarItemDesc)
|
||||
.ToListAsync();
|
||||
|
||||
// Filter to rewards the player doesn't own
|
||||
var unownedRewards = avatarRewards
|
||||
.Where(ar => !ownedAvatarItems.Contains(ar.AvatarItemDesc))
|
||||
.ToList();
|
||||
|
||||
if (unownedRewards.Any())
|
||||
{
|
||||
// Randomly select one of the unowned rewards
|
||||
var selectedReward = unownedRewards[random.Next(unownedRewards.Count)];
|
||||
avatarItemDesc = selectedReward.AvatarItemDesc;
|
||||
friendlyName = selectedReward.FriendlyName;
|
||||
@@ -1547,28 +1550,23 @@ public class APIController
|
||||
}
|
||||
else
|
||||
{
|
||||
// Player owns all avatar items, give token box instead
|
||||
isEarnableItem = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No avatar rewards, give token box instead
|
||||
isEarnableItem = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If not earnable item or player owns all items, generate a token box
|
||||
if (!isEarnableItem)
|
||||
{
|
||||
int[] tokenAmounts = { 10, 25, 50, 100, 250, 500 };
|
||||
int[] tokenAmounts = {10, 25, 50, 100, 250, 500};
|
||||
currency = tokenAmounts[random.Next(tokenAmounts.Length)];
|
||||
currencyType = 2;
|
||||
consumableItemDesc = $"TokenBox_{currency}";
|
||||
giftRarity = 20;
|
||||
}
|
||||
|
||||
// Create the received gift record
|
||||
var receivedGift = new ReceivedGift
|
||||
{
|
||||
ReceiverAccountId = id,
|
||||
@@ -1640,7 +1638,6 @@ public class APIController
|
||||
if (string.IsNullOrEmpty(accountId) || !int.TryParse(accountId.AsSpan(), out var id))
|
||||
return Results.Unauthorized();
|
||||
|
||||
// Parse form data
|
||||
request.EnableBuffering();
|
||||
request.Body.Position = 0;
|
||||
using var reader = new StreamReader(request.Body);
|
||||
@@ -1669,7 +1666,6 @@ public class APIController
|
||||
return Results.BadRequest(new { success = false, error = "Invalid gift ID" });
|
||||
}
|
||||
|
||||
// Look for the ReceivedGift
|
||||
var receivedGift = await db.ReceivedGifts
|
||||
.FirstOrDefaultAsync(rg => rg.Id == giftId && rg.ReceiverAccountId == id);
|
||||
|
||||
@@ -1678,7 +1674,6 @@ public class APIController
|
||||
return Results.NotFound(new { success = false, error = "Gift not found" });
|
||||
}
|
||||
|
||||
// Process the gift based on its properties
|
||||
if (!string.IsNullOrEmpty(receivedGift.ConsumableItemDesc))
|
||||
{
|
||||
var existingConsumable = await db.ConsumableItems
|
||||
@@ -1720,18 +1715,38 @@ public class APIController
|
||||
db.AvatarItems.Add(avatarItem);
|
||||
}
|
||||
|
||||
// Mark the gift as consumed
|
||||
if (!string.IsNullOrEmpty(receivedGift.Currency.ToString()) && receivedGift.CurrencyType == 2)
|
||||
{
|
||||
var tokenBalance = await db.TokenBalances
|
||||
.FirstOrDefaultAsync(tb => tb.Id == id &&
|
||||
tb.CurrencyType == receivedGift.CurrencyType &&
|
||||
tb.BalanceType == -1);
|
||||
|
||||
if (tokenBalance == null)
|
||||
{
|
||||
tokenBalance = new TokenBalance
|
||||
{
|
||||
Id = id,
|
||||
CurrencyType = receivedGift.CurrencyType,
|
||||
BalanceType = -1,
|
||||
Balance = receivedGift.Currency
|
||||
};
|
||||
db.TokenBalances.Add(tokenBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenBalance.Balance += receivedGift.Currency;
|
||||
db.TokenBalances.Update(tokenBalance);
|
||||
}
|
||||
}
|
||||
|
||||
receivedGift.IsConsumed = true;
|
||||
receivedGift.ConsumedAt = DateTime.UtcNow;
|
||||
db.ReceivedGifts.Update(receivedGift);
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Send notifications based on what was added
|
||||
try
|
||||
{
|
||||
var hubContext = app.Services.GetService<IHubContext>();
|
||||
if (hubContext != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(receivedGift.ConsumableItemDesc))
|
||||
{
|
||||
@@ -1741,22 +1756,27 @@ public class APIController
|
||||
toAccountId: id,
|
||||
data: new Dictionary<string, object>
|
||||
{
|
||||
{ "Id", (long)giftId },
|
||||
{ "ConsumableItemDesc", receivedGift.ConsumableItemDesc },
|
||||
{ "PlatformMask", -1 },
|
||||
{ "CreatedAt", DateTime.UtcNow },
|
||||
{ "Id", giftId },
|
||||
{ "ConsumableType", "JfnVXFmilU6ysv-VbTAe3A" },
|
||||
{ "PlatformMask", 4294967295 },
|
||||
{ "Count", 1 },
|
||||
{ "InitialCount", 1 },
|
||||
{ "UnlockedLevel", 0 },
|
||||
{ "CreatedAt", DateTime.UtcNow },
|
||||
{ "IsActive", false },
|
||||
{ "ActiveDurationMinutes", null }
|
||||
{ "ActiveDurationMinutes", null },
|
||||
{ "Category", 0 },
|
||||
{ "IsPlatformLocked", false }
|
||||
}
|
||||
);
|
||||
await notificationService.SendNotificationToPlayer(null, hubContext, id, consumableNotification);
|
||||
await notificationService.SendNotificationToPlayer(id, consumableNotification);
|
||||
}
|
||||
}
|
||||
catch (Exception notifEx)
|
||||
{
|
||||
// Log the error but don't fail the gift consumption
|
||||
Console.WriteLine($"Error sending notification: {notifEx.Message}");
|
||||
}
|
||||
catch { }
|
||||
|
||||
return Results.Ok(new { success = true });
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public class AccountsController
|
||||
return Results.Ok("FUCKL MYSJDIOJD");
|
||||
});
|
||||
|
||||
app.MapGet("/account/me", (HttpRequest request, AppDbContext db) =>
|
||||
app.MapGet("/account/me", async (HttpRequest request, AppDbContext db) =>
|
||||
{
|
||||
var authHeader = request.Headers.Authorization.ToString();
|
||||
|
||||
@@ -32,17 +32,21 @@ public class AccountsController
|
||||
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||
return Results.Unauthorized();
|
||||
|
||||
var account = await db.Accounts.FindAsync(id);
|
||||
if (account == null)
|
||||
return Results.NotFound();
|
||||
|
||||
var selfAccount = new SelfAccount
|
||||
{
|
||||
AccountId = id,
|
||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = false,
|
||||
Platforms = 0,
|
||||
PersonalPronouns = 0,
|
||||
IdentityFlags = 0,
|
||||
Username = $"Player{id}",
|
||||
DisplayName = $"Player{id}",
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ProfileImage = account.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = account.IsJunior,
|
||||
Platforms = account.Platforms ?? 0,
|
||||
PersonalPronouns = account.PersonalPronouns ?? 0,
|
||||
IdentityFlags = account.IdentityFlags ?? 0,
|
||||
Username = account.Username ?? $"Player{id}",
|
||||
DisplayName = account.DisplayName ?? $"Player{id}",
|
||||
CreatedAt = account.CreatedAt,
|
||||
Email = null,
|
||||
Phone = null,
|
||||
JuniorState = null,
|
||||
@@ -54,54 +58,62 @@ public class AccountsController
|
||||
return Results.Ok(selfAccount);
|
||||
});
|
||||
|
||||
app.MapGet("/account/bulk", (HttpRequest request) =>
|
||||
app.MapGet("/account/bulk", async (HttpRequest request, AppDbContext db) =>
|
||||
{
|
||||
var ids = request.Query["id"];
|
||||
var accounts = new List<Account>();
|
||||
var accountIds = new List<int>();
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
if (int.TryParse(id, out var accountId))
|
||||
{
|
||||
accounts.Add(new Account
|
||||
{
|
||||
AccountId = accountId,
|
||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = false,
|
||||
Platforms = 0,
|
||||
PersonalPronouns = 0,
|
||||
IdentityFlags = 0,
|
||||
Username = $"Player{accountId}",
|
||||
DisplayName = $"Player{accountId}",
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
accountIds.Add(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
return Results.Json(accounts);
|
||||
var accounts = await db.Accounts
|
||||
.Where(a => accountIds.Contains(a.AccountId.Value))
|
||||
.ToListAsync();
|
||||
|
||||
var result = accounts.Select(a => new Account
|
||||
{
|
||||
AccountId = a.AccountId,
|
||||
ProfileImage = a.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = a.IsJunior,
|
||||
Platforms = a.Platforms ?? 0,
|
||||
PersonalPronouns = a.PersonalPronouns ?? 0,
|
||||
IdentityFlags = a.IdentityFlags ?? 0,
|
||||
Username = a.Username ?? $"Player{a.AccountId}",
|
||||
DisplayName = a.DisplayName ?? $"Player{a.AccountId}",
|
||||
CreatedAt = a.CreatedAt
|
||||
}).ToList();
|
||||
|
||||
return Results.Json(result);
|
||||
});
|
||||
|
||||
app.MapGet("/account/{id}", (HttpRequest request, string id) =>
|
||||
app.MapGet("/account/{id}", async (HttpRequest request, string id, AppDbContext db) =>
|
||||
{
|
||||
var accounts = new Account();
|
||||
if (!int.TryParse(id, out var accountId))
|
||||
return Results.BadRequest();
|
||||
|
||||
if (int.TryParse(id, out var accountId))
|
||||
var account = await db.Accounts.FindAsync(accountId);
|
||||
if (account == null)
|
||||
return Results.NotFound();
|
||||
|
||||
var result = new Account
|
||||
{
|
||||
accounts = new Account
|
||||
{
|
||||
AccountId = accountId,
|
||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = false,
|
||||
Platforms = 0,
|
||||
PersonalPronouns = 0,
|
||||
IdentityFlags = 0,
|
||||
Username = $"Player{accountId}",
|
||||
DisplayName = $"Player{accountId}",
|
||||
CreatedAt = DateTime.UtcNow
|
||||
AccountId = account.AccountId,
|
||||
ProfileImage = account.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = account.IsJunior,
|
||||
Platforms = account.Platforms ?? 0,
|
||||
PersonalPronouns = account.PersonalPronouns ?? 0,
|
||||
IdentityFlags = account.IdentityFlags ?? 0,
|
||||
Username = account.Username ?? $"Player{account.AccountId}",
|
||||
DisplayName = account.DisplayName ?? $"Player{account.AccountId}",
|
||||
CreatedAt = account.CreatedAt
|
||||
};
|
||||
}
|
||||
|
||||
return Results.Json(accounts);
|
||||
return Results.Json(result);
|
||||
});
|
||||
|
||||
app.MapPost("/account/create", async (HttpRequest httpRequest, AppDbContext db) =>
|
||||
@@ -300,7 +312,146 @@ public class AccountsController
|
||||
account.DisplayName = newDisplayName;
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.Ok();
|
||||
return Results.Ok(RecNetResult.Ok());
|
||||
});
|
||||
|
||||
app.MapPut("/account/me/username", async (HttpRequest request, AppDbContext db) =>
|
||||
{
|
||||
var authHeader = request.Headers.Authorization.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||
return Results.Unauthorized();
|
||||
|
||||
var token = authHeader.Substring("Bearer ".Length);
|
||||
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||
|
||||
if (string.IsNullOrEmpty(accountId))
|
||||
return Results.Unauthorized();
|
||||
|
||||
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||
return Results.Unauthorized();
|
||||
|
||||
string newAccountName = "";
|
||||
|
||||
if (request.ContentLength.HasValue && request.ContentLength > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
request.EnableBuffering();
|
||||
using var reader = new StreamReader(request.Body, leaveOpen: true);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
foreach (var pair in body.Split('&'))
|
||||
{
|
||||
var keyValue = pair.Split('=');
|
||||
if (keyValue.Length == 2)
|
||||
{
|
||||
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||
var value = Uri.UnescapeDataString(keyValue[1]);
|
||||
|
||||
if (key == "username")
|
||||
newAccountName = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
var account = await db.Accounts.FindAsync(id);
|
||||
if (account == null)
|
||||
return Results.NotFound();
|
||||
|
||||
account.Username = newAccountName;
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.Ok(RecNetResult.Ok());
|
||||
});
|
||||
|
||||
app.MapGet("/account/{id}/bio", async (HttpRequest request, string id, AppDbContext db) =>
|
||||
{
|
||||
if (!int.TryParse(id, out var accountId))
|
||||
return Results.BadRequest();
|
||||
|
||||
var bio = await db.PlayerBios.FirstOrDefaultAsync(b => b.accountId == accountId);
|
||||
|
||||
if (bio == null)
|
||||
{
|
||||
return Results.Json(new { accountId = accountId, bio = "" });
|
||||
}
|
||||
|
||||
return Results.Json(new { accountId = bio.accountId, bio = bio.bio });
|
||||
});
|
||||
|
||||
app.MapPut("/account/me/bio", async (HttpRequest request, AppDbContext db) =>
|
||||
{
|
||||
var authHeader = request.Headers.Authorization.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
|
||||
return Results.Unauthorized();
|
||||
|
||||
var token = authHeader.Substring("Bearer ".Length);
|
||||
var accountId = jwtService.ValidateAndGetAccountId(token);
|
||||
|
||||
if (string.IsNullOrEmpty(accountId))
|
||||
return Results.Unauthorized();
|
||||
|
||||
if (!int.TryParse(accountId.AsSpan(), out var id))
|
||||
return Results.Unauthorized();
|
||||
|
||||
string newBio = "";
|
||||
|
||||
if (request.ContentLength.HasValue && request.ContentLength > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
request.EnableBuffering();
|
||||
using var reader = new StreamReader(request.Body, leaveOpen: true);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
foreach (var pair in body.Split('&'))
|
||||
{
|
||||
var keyValue = pair.Split('=');
|
||||
if (keyValue.Length == 2)
|
||||
{
|
||||
var key = Uri.UnescapeDataString(keyValue[0]);
|
||||
var value = Uri.UnescapeDataString(keyValue[1]);
|
||||
|
||||
if (key == "bio")
|
||||
newBio = Uri.UnescapeDataString(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
var bio = await db.PlayerBios.FirstOrDefaultAsync(b => b.accountId == id);
|
||||
|
||||
if (bio == null)
|
||||
{
|
||||
bio = new PlayerBio
|
||||
{
|
||||
accountId = id,
|
||||
bio = newBio
|
||||
};
|
||||
db.PlayerBios.Add(bio);
|
||||
}
|
||||
else
|
||||
{
|
||||
bio.bio = newBio;
|
||||
db.PlayerBios.Update(bio);
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return Results.Json(new { success = true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,32 +17,39 @@ public class MatchmakingController
|
||||
|
||||
app.MapPost("/player/login", () => Results.Ok());
|
||||
|
||||
app.MapGet("/player", (HttpRequest request) =>
|
||||
app.MapGet("/player", async (HttpRequest request, AppDbContext db) =>
|
||||
{
|
||||
/*
|
||||
var id = request.Query["id"];
|
||||
var accounts = new List<Account>();
|
||||
|
||||
if (int.TryParse(id, out var accountId))
|
||||
var id = request.Query["id"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(id) || !int.TryParse(id, out var accountId))
|
||||
{
|
||||
accounts.Add(new Account
|
||||
{
|
||||
AccountId = accountId,
|
||||
ProfileImage = "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = false,
|
||||
Platforms = 0,
|
||||
PersonalPronouns = 0,
|
||||
IdentityFlags = 0,
|
||||
Username = $"Player{accountId}",
|
||||
DisplayName = $"Player{accountId}",
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
||||
return Results.Json(accounts);*/
|
||||
|
||||
var json = File.ReadAllText("JSON/getplayer.json");
|
||||
return Results.Content(json, "application/json");
|
||||
}
|
||||
|
||||
var account = await db.Accounts.FindAsync(accountId);
|
||||
if (account == null)
|
||||
{
|
||||
var json = File.ReadAllText("JSON/getplayer.json");
|
||||
return Results.Content(json, "application/json");
|
||||
}
|
||||
|
||||
var result = new List<Account>
|
||||
{
|
||||
new Account
|
||||
{
|
||||
AccountId = account.AccountId,
|
||||
ProfileImage = account.ProfileImage ?? "hdqeamlcmatc6qzoi2ybgf0ddijjcf.jpg",
|
||||
IsJunior = account.IsJunior,
|
||||
Platforms = account.Platforms ?? 0,
|
||||
PersonalPronouns = account.PersonalPronouns ?? 0,
|
||||
IdentityFlags = account.IdentityFlags ?? 0,
|
||||
Username = account.Username ?? $"Player{account.AccountId}",
|
||||
DisplayName = account.DisplayName ?? $"Player{account.AccountId}",
|
||||
CreatedAt = account.CreatedAt
|
||||
}
|
||||
};
|
||||
|
||||
return Results.Json(result);
|
||||
});
|
||||
|
||||
app.MapPost("/goto/room/{room}", async (HttpRequest request, string room, AppDbContext db) =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using CannedNet.Hubs;
|
||||
using CannedNet.Services.Infrastructure;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace CannedNet.Services.Controllers;
|
||||
|
||||
@@ -10,5 +11,8 @@ public class NotifyController
|
||||
public void MapEndpoints(WebApplication app)
|
||||
{
|
||||
app.MapHub<NotificationsHub>("/hub/v1");
|
||||
|
||||
var hubContext = app.Services.GetRequiredService<IHubContext<NotificationsHub>>();
|
||||
NotificationService.SetHubContext(hubContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,39 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using CannedNet.Hubs;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace CannedNet.Services;
|
||||
|
||||
public class NotificationService
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, HashSet<int>> _connectionSubscriptions = new();
|
||||
private readonly ConcurrentDictionary<int, HashSet<string>> _playerConnections = new();
|
||||
private static readonly ConcurrentDictionary<string, HashSet<int>> _connectionSubscriptions = new();
|
||||
private static readonly ConcurrentDictionary<int, HashSet<string>> _playerConnections = new();
|
||||
private static readonly ConcurrentDictionary<int, Queue<NotificationMessage>> _pendingNotifications = new();
|
||||
private static IHubContext<NotificationsHub>? _hubContext;
|
||||
private readonly ILogger<NotificationService> _logger;
|
||||
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
||||
|
||||
public NotificationService(ILogger<NotificationService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public static void SetHubContext(IHubContext<NotificationsHub> hubContext)
|
||||
{
|
||||
_hubContext = hubContext;
|
||||
}
|
||||
|
||||
public void OnConnected(string connectionId)
|
||||
{
|
||||
_logger.LogInformation($"Client connected: {connectionId}");
|
||||
_connectionSubscriptions.TryAdd(connectionId, new HashSet<int>());
|
||||
}
|
||||
|
||||
public void OnDisconnected(string connectionId)
|
||||
{
|
||||
_logger.LogInformation($"Client disconnected: {connectionId}");
|
||||
if (_connectionSubscriptions.TryRemove(connectionId, out var subscriptions))
|
||||
{
|
||||
foreach (var playerId in subscriptions)
|
||||
@@ -37,11 +50,13 @@ public class NotificationService
|
||||
}
|
||||
}
|
||||
|
||||
public Task SubscribeToPlayers(string connectionId, SubscriptionList subscriptionList)
|
||||
public async Task SubscribeToPlayers(string connectionId, SubscriptionList subscriptionList, IHubContext<NotificationsHub> hubContext)
|
||||
{
|
||||
var oldSubscriptions = _connectionSubscriptions.GetValueOrDefault(connectionId, new HashSet<int>());
|
||||
var newPlayerIds = subscriptionList.PlayerIds ?? new List<int>();
|
||||
|
||||
_logger.LogInformation($"Connection {connectionId} subscribing to players: {string.Join(", ", newPlayerIds)}");
|
||||
|
||||
_connectionSubscriptions[connectionId] = new HashSet<int>(newPlayerIds);
|
||||
|
||||
foreach (var playerId in newPlayerIds)
|
||||
@@ -54,6 +69,22 @@ public class NotificationService
|
||||
existing.Add(connectionId);
|
||||
return existing;
|
||||
});
|
||||
|
||||
if (_pendingNotifications.TryRemove(playerId, out var pendingQueue))
|
||||
{
|
||||
_logger.LogInformation($"Found {pendingQueue.Count} pending notifications for player {playerId}. Sending to connection {connectionId}");
|
||||
while (pendingQueue.TryDequeue(out var notification))
|
||||
{
|
||||
try
|
||||
{
|
||||
await SendToConnection(hubContext, connectionId, notification);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error sending pending notification to player {playerId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var playerId in oldSubscriptions)
|
||||
@@ -63,8 +94,6 @@ public class NotificationService
|
||||
connections.Remove(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public HashSet<int>? GetSubscriptions(string connectionId)
|
||||
@@ -90,19 +119,26 @@ public class NotificationService
|
||||
return Enumerable.Empty<int>();
|
||||
}
|
||||
|
||||
public async Task SendNotificationToPlayer(string callerConnectionId, IHubContext hubContext, int playerId, NotificationMessage notification)
|
||||
public async Task SendNotificationToPlayer(int playerId, NotificationMessage notification)
|
||||
{
|
||||
try
|
||||
if (_hubContext == null)
|
||||
{
|
||||
var connections = GetConnectionsForPlayer(playerId);
|
||||
foreach (var connectionId in connections)
|
||||
{
|
||||
if (connectionId == callerConnectionId)
|
||||
continue;
|
||||
_logger.LogWarning("No hub context available. Cannot send notification.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await hubContext.Clients.Client(connectionId).SendAsync("Notification", notification);
|
||||
var connections = GetConnectionsForPlayer(playerId).ToList();
|
||||
_logger.LogInformation($"Attempting to send notification to player {playerId}. Found {connections.Count} connections. NotificationType: {notification.NotificationType}");
|
||||
|
||||
if (connections.Any())
|
||||
{
|
||||
foreach (var connectionId in connections)
|
||||
{
|
||||
try
|
||||
{
|
||||
await SendToConnection(_hubContext, connectionId, notification);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -110,17 +146,42 @@ public class NotificationService
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning($"No connections found for player {playerId}. Queueing notification for later delivery. NotificationType: {notification.NotificationType}");
|
||||
_pendingNotifications.AddOrUpdate(
|
||||
playerId,
|
||||
_ => new Queue<NotificationMessage>(new[] { notification }),
|
||||
(_, queue) =>
|
||||
{
|
||||
queue.Enqueue(notification);
|
||||
return queue;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Error sending notification to player {playerId}. NotificationType: {notification.NotificationType}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task BroadcastNotification(IHubContext hubContext, NotificationMessage notification)
|
||||
public async Task BroadcastNotification(NotificationMessage notification)
|
||||
{
|
||||
if (_hubContext == null)
|
||||
{
|
||||
_logger.LogWarning("No hub context available. Cannot broadcast notification.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await hubContext.Clients.All.SendAsync("Notification", notification);
|
||||
foreach (var kvp in _playerConnections)
|
||||
{
|
||||
foreach (var connectionId in kvp.Value)
|
||||
{
|
||||
await SendToConnection(_hubContext, connectionId, notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -141,4 +202,58 @@ public class NotificationService
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task SendToConnection(IHubContext<NotificationsHub> hubContext, string connectionId, NotificationMessage notification)
|
||||
{
|
||||
var notificationData = BuildNotificationObject(notification);
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(notificationData);
|
||||
System.Console.WriteLine($"[NotificationService] Sending notification to {connectionId}: {json}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Console.WriteLine($"[NotificationService] Error serializing notification: {ex.Message}");
|
||||
}
|
||||
await hubContext.Clients.Client(connectionId).SendAsync("Notification", notificationData);
|
||||
}
|
||||
|
||||
private static Dictionary<string, object?> BuildNotificationObject(NotificationMessage notification)
|
||||
{
|
||||
var dict = new Dictionary<string, object?>
|
||||
{
|
||||
{ "notificationId", notification.NotificationId ?? "" },
|
||||
{ "notificationType", (int?)notification.NotificationType ?? 0 },
|
||||
};
|
||||
|
||||
// Only add optional fields if they have values
|
||||
if (notification.Id.HasValue)
|
||||
dict.Add("id", notification.Id.Value);
|
||||
if (notification.FromAccountId.HasValue)
|
||||
dict.Add("fromAccountId", notification.FromAccountId.Value);
|
||||
if (notification.ToAccountId.HasValue)
|
||||
dict.Add("toAccountId", notification.ToAccountId.Value);
|
||||
if (notification.CreatedAt.HasValue)
|
||||
dict.Add("createdAt", notification.CreatedAt.Value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
|
||||
|
||||
// Properly serialize the data dictionary, converting DateTime objects to ISO 8601 strings
|
||||
var serializedData = new Dictionary<string, object>();
|
||||
if (notification.Data != null && notification.Data.Count > 0)
|
||||
{
|
||||
foreach (var kvp in notification.Data)
|
||||
{
|
||||
if (kvp.Value is DateTime dt)
|
||||
{
|
||||
serializedData[kvp.Key] = dt.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
|
||||
}
|
||||
else if (kvp.Value != null)
|
||||
{
|
||||
serializedData[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dict.Add("data", serializedData);
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user