Start tracking play sessions
parent
aff2e991ed
commit
5324723cee
|
@ -331,12 +331,26 @@ namespace LANCommander.PlaynitePlugin
|
|||
|
||||
public override void OnGameStarting(OnGameStartingEventArgs args)
|
||||
{
|
||||
SaveController.Download(args.Game);
|
||||
if (args.Game.PluginId == Id)
|
||||
{
|
||||
SaveController.Download(args.Game);
|
||||
|
||||
var gameId = Guid.Parse(args.Game.GameId);
|
||||
|
||||
LANCommanderClient.StartPlaySession(gameId);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGameStopped(OnGameStoppedEventArgs args)
|
||||
{
|
||||
SaveController.Upload(args.Game);
|
||||
if (args.Game.PluginId == Id)
|
||||
{
|
||||
SaveController.Upload(args.Game);
|
||||
|
||||
var gameId = Guid.Parse(args.Game.GameId);
|
||||
|
||||
LANCommanderClient.EndPlaySession(gameId);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<TopPanelItem> GetTopPanelItems()
|
||||
|
|
|
@ -51,6 +51,16 @@ namespace LANCommander.SDK
|
|||
return response.Data;
|
||||
}
|
||||
|
||||
private T PostRequest<T>(string route)
|
||||
{
|
||||
var request = new RestRequest(route)
|
||||
.AddHeader("Authorization", $"Bearer {Token.AccessToken}");
|
||||
|
||||
var response = ApiClient.Post<T>(request);
|
||||
|
||||
return response.Data;
|
||||
}
|
||||
|
||||
private T GetRequest<T>(string route)
|
||||
{
|
||||
var request = new RestRequest(route)
|
||||
|
@ -364,6 +374,20 @@ namespace LANCommander.SDK
|
|||
return alias;
|
||||
}
|
||||
|
||||
public void StartPlaySession(Guid gameId)
|
||||
{
|
||||
Logger?.LogTrace("Starting a game session...");
|
||||
|
||||
PostRequest<object>($"/api/PlaySession/Start/{gameId}");
|
||||
}
|
||||
|
||||
public void EndPlaySession(Guid gameId)
|
||||
{
|
||||
Logger?.LogTrace("Ending a game session...");
|
||||
|
||||
PostRequest<object>($"/api/PlaySession/End/{gameId}");
|
||||
}
|
||||
|
||||
private string GetMacAddress()
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces()
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
using LANCommander.Data.Models;
|
||||
using LANCommander.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LANCommander.Controllers.Api
|
||||
{
|
||||
[Authorize(AuthenticationSchemes = "Bearer")]
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class PlaySessionsController : ControllerBase
|
||||
{
|
||||
private readonly PlaySessionService PlaySessionService;
|
||||
private readonly GameService GameService;
|
||||
private readonly UserManager<User> UserManager;
|
||||
|
||||
public PlaySessionsController(PlaySessionService playSessionService, GameService gameService, UserManager<User> userManager)
|
||||
{
|
||||
PlaySessionService = playSessionService;
|
||||
GameService = gameService;
|
||||
UserManager = userManager;
|
||||
}
|
||||
|
||||
[HttpPost("Start/{id}")]
|
||||
public async Task<IActionResult> Start(Guid id)
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(User.Identity.Name);
|
||||
var game = await GameService.Get(id);
|
||||
|
||||
if (game == null || user == null)
|
||||
return BadRequest();
|
||||
|
||||
await PlaySessionService.StartSession(game.Id, user.Id);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("End/{id}")]
|
||||
public async Task<IActionResult> End(Guid id)
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(User.Identity.Name);
|
||||
var game = await GameService.Get(id);
|
||||
|
||||
if (game == null || user == null)
|
||||
return BadRequest();
|
||||
|
||||
await PlaySessionService.EndSession(game.Id, user.Id);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -107,6 +107,18 @@ namespace LANCommander.Data
|
|||
.IsRequired(true)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.Entity<User>()
|
||||
.HasMany(u => u.PlaySessions)
|
||||
.WithOne(ps => ps.User)
|
||||
.IsRequired(true)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.Entity<Game>()
|
||||
.HasMany(g => g.PlaySessions)
|
||||
.WithOne(ps => ps.Game)
|
||||
.IsRequired(true)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
builder.Entity<Server>()
|
||||
.HasOne(s => s.Game)
|
||||
.WithMany(g => g.Servers)
|
||||
|
@ -152,6 +164,8 @@ namespace LANCommander.Data
|
|||
|
||||
public DbSet<GameSave>? GameSaves { get; set; }
|
||||
|
||||
public DbSet<PlaySession>? PlaySessions { get; set; }
|
||||
|
||||
public DbSet<Server>? Servers { get; set; }
|
||||
|
||||
public DbSet<ServerConsole>? ServerConsoles { get; set; }
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace LANCommander.Data.Models
|
|||
public virtual ICollection<Archive>? Archives { get; set; }
|
||||
public virtual ICollection<Script>? Scripts { get; set; }
|
||||
public virtual ICollection<GameSave>? GameSaves { get; set; }
|
||||
public virtual ICollection<PlaySession>? PlaySessions { get; set; }
|
||||
public virtual ICollection<SavePath>? SavePaths { get; set; }
|
||||
public virtual ICollection<Server>? Servers { get; set; }
|
||||
public virtual ICollection<Redistributable>? Redistributables { get; set; }
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LANCommander.Data.Models
|
||||
{
|
||||
[Table("PlaySessions")]
|
||||
public class PlaySession : BaseModel
|
||||
{
|
||||
public Guid GameId { get; set; }
|
||||
[JsonIgnore]
|
||||
[ForeignKey(nameof(GameId))]
|
||||
[InverseProperty("PlaySessions")]
|
||||
public virtual Game? Game { get; set; }
|
||||
|
||||
public Guid UserId { get; set; }
|
||||
[ForeignKey(nameof(UserId))]
|
||||
[InverseProperty("PlaySessions")]
|
||||
public virtual User? User { get; set; }
|
||||
|
||||
[Display(Name = "Start")]
|
||||
public DateTime? Start { get; set; }
|
||||
|
||||
[Display(Name = "End")]
|
||||
public DateTime? End { get; set; }
|
||||
}
|
||||
}
|
|
@ -46,6 +46,9 @@ namespace LANCommander.Data.Models
|
|||
[JsonIgnore]
|
||||
public virtual ICollection<GameSave>? GameSaves { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<PlaySession>? PlaySessions { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool Approved { get; set; }
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace LANCommander.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddPlaySessions : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PlaySessions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
GameId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
UserId = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
Start = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
End = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
CreatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
CreatedById = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
UpdatedOn = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedById = table.Column<Guid>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PlaySessions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PlaySessions_AspNetUsers_CreatedById",
|
||||
column: x => x.CreatedById,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_PlaySessions_AspNetUsers_UpdatedById",
|
||||
column: x => x.UpdatedById,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_PlaySessions_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_PlaySessions_Games_GameId",
|
||||
column: x => x.GameId,
|
||||
principalTable: "Games",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PlaySessions_CreatedById",
|
||||
table: "PlaySessions",
|
||||
column: "CreatedById");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PlaySessions_GameId",
|
||||
table: "PlaySessions",
|
||||
column: "GameId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PlaySessions_UpdatedById",
|
||||
table: "PlaySessions",
|
||||
column: "UpdatedById");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PlaySessions_UserId",
|
||||
table: "PlaySessions",
|
||||
column: "UserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "PlaySessions");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -570,6 +570,49 @@ namespace LANCommander.Migrations
|
|||
b.ToTable("MultiplayerModes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LANCommander.Data.Models.PlaySession", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("CreatedById")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedOn")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("End")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("GameId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("Start")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid?>("UpdatedById")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedOn")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedById");
|
||||
|
||||
b.HasIndex("GameId");
|
||||
|
||||
b.HasIndex("UpdatedById");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("PlaySessions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
@ -1431,6 +1474,37 @@ namespace LANCommander.Migrations
|
|||
b.Navigation("UpdatedBy");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LANCommander.Data.Models.PlaySession", b =>
|
||||
{
|
||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedById");
|
||||
|
||||
b.HasOne("LANCommander.Data.Models.Game", "Game")
|
||||
.WithMany("PlaySessions")
|
||||
.HasForeignKey("GameId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LANCommander.Data.Models.User", "UpdatedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("UpdatedById");
|
||||
|
||||
b.HasOne("LANCommander.Data.Models.User", "User")
|
||||
.WithMany("PlaySessions")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("CreatedBy");
|
||||
|
||||
b.Navigation("Game");
|
||||
|
||||
b.Navigation("UpdatedBy");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LANCommander.Data.Models.Redistributable", b =>
|
||||
{
|
||||
b.HasOne("LANCommander.Data.Models.User", "CreatedBy")
|
||||
|
@ -1657,6 +1731,8 @@ namespace LANCommander.Migrations
|
|||
|
||||
b.Navigation("MultiplayerModes");
|
||||
|
||||
b.Navigation("PlaySessions");
|
||||
|
||||
b.Navigation("SavePaths");
|
||||
|
||||
b.Navigation("Scripts");
|
||||
|
@ -1681,6 +1757,8 @@ namespace LANCommander.Migrations
|
|||
modelBuilder.Entity("LANCommander.Data.Models.User", b =>
|
||||
{
|
||||
b.Navigation("GameSaves");
|
||||
|
||||
b.Navigation("PlaySessions");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ namespace LANCommander
|
|||
builder.Services.AddScoped<ServerService>();
|
||||
builder.Services.AddScoped<ServerConsoleService>();
|
||||
builder.Services.AddScoped<GameSaveService>();
|
||||
builder.Services.AddScoped<PlaySessionService>();
|
||||
builder.Services.AddScoped<MediaService>();
|
||||
builder.Services.AddScoped<RedistributableService>();
|
||||
builder.Services.AddScoped<IMediaGrabberService, SteamGridDBMediaGrabber>();
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using LANCommander.Data;
|
||||
using LANCommander.Data.Models;
|
||||
using LANCommander.Helpers;
|
||||
using LANCommander.Models;
|
||||
|
||||
namespace LANCommander.Services
|
||||
{
|
||||
public class PlaySessionService : BaseDatabaseService<PlaySession>
|
||||
{
|
||||
public PlaySessionService(DatabaseContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor) { }
|
||||
|
||||
public async Task StartSession(Guid gameId, Guid userId)
|
||||
{
|
||||
var existingSession = Get(ps => ps.GameId == gameId && ps.UserId == userId && ps.End == null).FirstOrDefault();
|
||||
|
||||
if (existingSession != null)
|
||||
await Delete(existingSession);
|
||||
|
||||
var session = new PlaySession()
|
||||
{
|
||||
GameId = gameId,
|
||||
UserId = userId,
|
||||
Start = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await Add(session);
|
||||
}
|
||||
|
||||
public async Task EndSession(Guid gameId, Guid userId)
|
||||
{
|
||||
var existingSession = Get(ps => ps.GameId == gameId && ps.UserId == userId && ps.End == null).FirstOrDefault();
|
||||
|
||||
if (existingSession != null)
|
||||
{
|
||||
existingSession.End = DateTime.UtcNow;
|
||||
|
||||
await Update(existingSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue