mirror of
https://github.com/9ParsonsB/Pulsar.git
synced 2025-07-01 16:33:43 -04:00
Implement Other state events
now emitted to websocket connections on connect
This commit is contained in:
@ -1,9 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
namespace Pulsar.Context.Configuration;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Observatory.Framework.Files.Journal.Startup;
|
||||
|
||||
namespace Pulsar.Context.Configuration;
|
||||
|
||||
public class CargoConfiguration : IEntityTypeConfiguration<Cargo>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Cargo> builder)
|
||||
|
@ -1,9 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
namespace Pulsar.Context.Configuration;
|
||||
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Observatory.Framework.Files.Journal.Odyssey;
|
||||
|
||||
namespace Pulsar.Context.Configuration;
|
||||
|
||||
public class ShipLockerConfiguration : IEntityTypeConfiguration<ShipLockerMaterials>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ShipLockerMaterials> builder)
|
||||
|
@ -1,12 +1,11 @@
|
||||
namespace Pulsar.Context;
|
||||
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Files.Journal.Odyssey;
|
||||
using Observatory.Framework.Files.Journal.Startup;
|
||||
using Observatory.Framework.Files.Journal.StationServices;
|
||||
using Observatory.Framework.Files.Journal.Travel;
|
||||
using Pulsar.Features.ShipLocker;
|
||||
|
||||
/// <summary>
|
||||
/// An in-memory database context for Pulsar.
|
||||
@ -14,7 +13,6 @@ using Pulsar.Features.ShipLocker;
|
||||
public class PulsarContext : DbContext
|
||||
{
|
||||
public SqliteConnection Connection { get; private set; }
|
||||
|
||||
|
||||
public DbSet<Commander> Commander { get; set; }
|
||||
public DbSet<Materials> Materials { get; set; }
|
||||
|
@ -1,17 +1,20 @@
|
||||
using Pulsar.Features.Journal;
|
||||
|
||||
namespace Pulsar.Features;
|
||||
|
||||
using Observatory.Framework.Files;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Files.Journal.Odyssey;
|
||||
|
||||
|
||||
public class EventsHub(IJournalService journalService) : Hub<IEventsHub>
|
||||
{
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
await base.OnConnectedAsync();
|
||||
await Clients.Caller.JournalUpdated(await journalService.GetLastStartupEvents());
|
||||
var state = await journalService.GetLatestState();
|
||||
if (state.Any())
|
||||
{
|
||||
await Clients.Caller.JournalUpdated(state);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Status([FromServices] IStatusService statusService)
|
||||
@ -30,7 +33,7 @@ public class EventsHub(IJournalService journalService) : Hub<IEventsHub>
|
||||
|
||||
public async Task MarketUpdated(MarketFile market) => await Clients.All.MarketUpdated(market);
|
||||
|
||||
public async Task JournalUpdated(IReadOnlyCollection<JournalBase> journals) => await Clients.All.JournalUpdated(journals);
|
||||
public async Task JournalUpdated(List<JournalBase> journals) => await Clients.All.JournalUpdated(journals);
|
||||
|
||||
public async Task ModuleInfoUpdated(ModuleInfoFile moduleInfo) => await Clients.All.ModuleInfoUpdated(moduleInfo);
|
||||
|
||||
@ -55,7 +58,7 @@ public interface IEventsHub
|
||||
|
||||
Task MarketUpdated(MarketFile market);
|
||||
|
||||
Task JournalUpdated(IReadOnlyCollection<JournalBase> journals);
|
||||
Task JournalUpdated(List<JournalBase> journals);
|
||||
|
||||
Task ModuleInfoUpdated(ModuleInfoFile moduleInfo);
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
using System.Collections.Concurrent;
|
||||
namespace Pulsar.Features;
|
||||
|
||||
using Observatory.Framework.Files;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Files.Journal.Odyssey;
|
||||
namespace Pulsar.Features;
|
||||
|
||||
public interface IFileHandler
|
||||
{
|
||||
|
@ -1,10 +1,9 @@
|
||||
using Observatory.Framework.Files.Journal.StationServices;
|
||||
|
||||
namespace Pulsar.Features.Journal;
|
||||
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Files.Journal.Startup;
|
||||
using Observatory.Framework.Files.Journal.StationServices;
|
||||
|
||||
public class JournalProcessor(
|
||||
ILogger<JournalProcessor> logger,
|
||||
|
@ -1,14 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Observatory.Framework.Files.Journal.Startup;
|
||||
using Observatory.Framework.Files.Journal.StationServices;
|
||||
|
||||
namespace Pulsar.Features.Journal;
|
||||
|
||||
using Observatory.Framework.Files.Journal;
|
||||
|
||||
public interface IJournalService : IJournalHandler<List<JournalBase>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Latest of the following (start of game) events:
|
||||
/// Commander
|
||||
/// Materials
|
||||
/// Rank
|
||||
/// Progress
|
||||
/// Reputation
|
||||
/// EngineerProgress
|
||||
/// LoadGame
|
||||
/// Statistics
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<JournalBase>> GetLastStartupEvents();
|
||||
|
||||
/// <summary>
|
||||
/// Get the Latest of the following events:
|
||||
/// <p>
|
||||
/// Location<br/>
|
||||
/// Powerplay<br/>
|
||||
/// Music<br/>
|
||||
/// ShipLocker<br/>
|
||||
/// Missions<br/>
|
||||
/// Loadout</p>
|
||||
/// <p>When there are none of an event since the last game start, no event will be given.</p>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<JournalBase>> GetLatestState();
|
||||
}
|
||||
|
||||
public class JournalService(
|
||||
@ -29,10 +51,8 @@ public class JournalService(
|
||||
store.EnqueueFile(filePath);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Start of game events/order:
|
||||
/** Commander
|
||||
* Materials
|
||||
@ -51,7 +71,7 @@ public class JournalService(
|
||||
Loadout
|
||||
Cargo
|
||||
*/
|
||||
|
||||
|
||||
// StartupEvents:
|
||||
// Commander
|
||||
// Materials
|
||||
@ -60,45 +80,19 @@ public class JournalService(
|
||||
// Reputation
|
||||
// EngineerProgress
|
||||
// LoadGame
|
||||
|
||||
// StateEvents:
|
||||
// Location
|
||||
// Powerplay
|
||||
// Music
|
||||
// ShipLocker
|
||||
// Missions
|
||||
// Loadout
|
||||
// Cargo
|
||||
// -- ...
|
||||
// Statistics
|
||||
public async Task<List<JournalBase>> GetLastStartupEvents()
|
||||
{
|
||||
//TODO: add other state events
|
||||
var commanderTask = context.Commander.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var materialsTask = context.Materials.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var rankTask = context.Rank.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var progressTask = context.Progress.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var reputationTask = context.Reputation.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var engineerProgressTask = context.EngineerProgress.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var loadGameTask = context.LoadGames.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var statisticsTask = context.Statistics.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var commander = await context.Commander.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var materials = await context.Materials.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var rank = await context.Rank.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var progress = await context.Progress.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var reputation = await context.Reputation.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var engineerProgress = await context.EngineerProgress.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var loadGame = await context.LoadGames.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var statistics = await context.Statistics.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
|
||||
await Task.WhenAll(
|
||||
commanderTask,
|
||||
materialsTask,
|
||||
rankTask,
|
||||
progressTask,
|
||||
reputationTask,
|
||||
engineerProgressTask,
|
||||
loadGameTask,
|
||||
statisticsTask);
|
||||
|
||||
var commander = await commanderTask;
|
||||
var materials = await materialsTask;
|
||||
var rank = await rankTask;
|
||||
var progress = await progressTask;
|
||||
var reputation = await reputationTask;
|
||||
var engineerProgress = await engineerProgressTask;
|
||||
var loadGame = await loadGameTask;
|
||||
var statistics = await statisticsTask;
|
||||
|
||||
// if any null, return empty list
|
||||
if (materials == null || rank == null || progress == null || reputation == null || engineerProgress == null ||
|
||||
@ -108,20 +102,62 @@ public class JournalService(
|
||||
}
|
||||
|
||||
// dont check the time of statistics as it may occur a few moments after
|
||||
if (commander.Timestamp != materials.Timestamp ||
|
||||
materials.Timestamp != rank.Timestamp ||
|
||||
rank.Timestamp != progress.Timestamp ||
|
||||
progress.Timestamp != reputation.Timestamp ||
|
||||
reputation.Timestamp != engineerProgress.Timestamp ||
|
||||
engineerProgress.Timestamp != loadGame.Timestamp ||
|
||||
statistics.Timestamp < materials.Timestamp)
|
||||
if (commander.Timestamp > materials.Timestamp ||
|
||||
commander.Timestamp > materials.Timestamp ||
|
||||
commander.Timestamp > rank.Timestamp ||
|
||||
commander.Timestamp > progress.Timestamp ||
|
||||
commander.Timestamp > reputation.Timestamp ||
|
||||
commander.Timestamp > engineerProgress.Timestamp ||
|
||||
commander.Timestamp > loadGame.Timestamp ||
|
||||
commander.Timestamp > statistics.Timestamp)
|
||||
{
|
||||
throw new InvalidOperationException("Timestamps do not match");
|
||||
throw new InvalidOperationException("Timestamps are invalid");
|
||||
}
|
||||
|
||||
return [commander, materials, rank, progress, reputation, engineerProgress, loadGame, statistics];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StateEvents:
|
||||
/// Location
|
||||
/// Powerplay
|
||||
/// Music
|
||||
/// ShipLocker
|
||||
/// Missions
|
||||
/// Loadout
|
||||
/// Cargo
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<JournalBase>> GetLatestState()
|
||||
{
|
||||
// dont get anything before the last command timestamp
|
||||
var commander = await context.Commander.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
|
||||
if (commander == null) return [];
|
||||
|
||||
var location = await context.Locations
|
||||
.Where(x => x.Timestamp > commander.Timestamp)
|
||||
.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var powerplay = await context.PowerPlay
|
||||
.Where(x => x.Timestamp > commander.Timestamp)
|
||||
.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var shiplocker = await context.ShipLocker
|
||||
.Where(x => x.Timestamp > commander.Timestamp)
|
||||
.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var missions = await context.Missions
|
||||
.Where(x => x.Timestamp > commander.Timestamp)
|
||||
.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var loadout = await context.Loadout
|
||||
.Where(x => x.Timestamp > commander.Timestamp)
|
||||
.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
var cargo = await context.Cargo
|
||||
.Where(x => x.Timestamp > commander.Timestamp)
|
||||
.OrderByDescending(x => x.Timestamp).FirstOrDefaultAsync();
|
||||
|
||||
return new List<JournalBase?> { location, powerplay, shiplocker, missions, loadout, cargo }
|
||||
.Where(x => x != null).Cast<JournalBase>().ToList();
|
||||
}
|
||||
|
||||
public async Task<List<JournalBase>> Get()
|
||||
{
|
||||
return [];
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Observatory.Framework.Files.Journal.Startup;
|
||||
using Pulsar.Context;
|
||||
|
||||
namespace Pulsar.Features.Status;
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
global using Pulsar;
|
||||
global using Pulsar.Utils;
|
||||
global using Pulsar.Context;
|
||||
global using Pulsar.Features;
|
||||
global using Pulsar.Features.Status;
|
||||
global using Pulsar.Features.Journal;
|
||||
global using System.Text;
|
||||
global using System.Text.Json;
|
||||
global using System.Text.Json.Nodes;
|
||||
@ -8,4 +11,5 @@ global using System.Text.Json.Serialization;
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.AspNetCore.SignalR;
|
||||
global using Microsoft.Extensions.Options;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using IEventHubContext = Microsoft.AspNetCore.SignalR.IHubContext<Pulsar.Features.EventsHub, Pulsar.Features.IEventsHub>;
|
@ -1,15 +1,16 @@
|
||||
using Lamar.Microsoft.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Pulsar.Features;
|
||||
using Pulsar.Features.Journal;
|
||||
|
||||
Console.WriteLine((string?)null!);
|
||||
|
||||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions()
|
||||
{
|
||||
Args = args, WebRootPath = "static", ContentRootPath = "WebApp", ApplicationName = "Pulsar", EnvironmentName =
|
||||
Args = args,
|
||||
WebRootPath = "static",
|
||||
ContentRootPath = "WebApp",
|
||||
ApplicationName = "Pulsar",
|
||||
EnvironmentName =
|
||||
#if DEBUG
|
||||
"Development"
|
||||
#else
|
||||
|
Reference in New Issue
Block a user