diff --git a/AX.WebDrillServer/AX.WebDrillServer.sln b/AX.WebDrillServer/AX.WebDrillServer.sln
index dc60608..4c14b7f 100644
--- a/AX.WebDrillServer/AX.WebDrillServer.sln
+++ b/AX.WebDrillServer/AX.WebDrillServer.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.3.32825.248
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AX.WebDrillServer", "AX.WebDrillServer.csproj", "{B594C541-C030-412E-8B89-D38C24765D2D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestHub", "..\TestHub\TestHub.csproj", "{4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,6 +20,12 @@ Global
{B594C541-C030-412E-8B89-D38C24765D2D}.Release|Any CPU.Build.0 = Release|Any CPU
{B594C541-C030-412E-8B89-D38C24765D2D}.Test|Any CPU.ActiveCfg = Test|Any CPU
{B594C541-C030-412E-8B89-D38C24765D2D}.Test|Any CPU.Build.0 = Test|Any CPU
+ {4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}.Test|Any CPU.ActiveCfg = Debug|Any CPU
+ {4B962EF6-1C2A-4283-B21D-46E6C57DD8D2}.Test|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/AX.WebDrillServer/Controllers/AccountsController.cs b/AX.WebDrillServer/Controllers/AccountsController.cs
index c641126..6a74a58 100644
--- a/AX.WebDrillServer/Controllers/AccountsController.cs
+++ b/AX.WebDrillServer/Controllers/AccountsController.cs
@@ -109,18 +109,16 @@ namespace AX.WebDrillServer.Controllers
}
}
///
- /// 登出
+ /// 登出系统。
///
- ///
///
- [AllowAnonymous]
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
- [HttpPost("[action]")]
- public async Task> SignOut([FromBody] UserForCreateDto dto)
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [HttpPost("SignOut")]
+ public ActionResult AccountSignOut()
{
- throw new NotImplementedException();
+ //TODO: 把 JWT 放入黑名单,其它地方则验证黑名单,将来再处理
+ return Ok();
}
///
/// 刷新令牌。
diff --git a/AX.WebDrillServer/Data/ApplicationDbContextSeed.cs b/AX.WebDrillServer/Data/ApplicationDbContextSeed.cs
index a736b26..4477c7f 100644
--- a/AX.WebDrillServer/Data/ApplicationDbContextSeed.cs
+++ b/AX.WebDrillServer/Data/ApplicationDbContextSeed.cs
@@ -72,15 +72,15 @@ namespace AX.WebDrillServer.Data
var org2 = new Organization()
{
Code = "1-1-1",
- Name = "XXX大队",
- Level = OrganizationLevel.Battalion,
+ Name = "XXX支队",
+ Level = OrganizationLevel.Brigade,
};
context.Organizations.Add(org2);
var org3 = new Organization()
{
Code = "1-1-1-1",
- Name = "XXX支队",
- Level = OrganizationLevel.Brigade,
+ Name = "XXX大队",
+ Level = OrganizationLevel.Battalion,
};
context.Organizations.Add(org3);
var org4 = new Organization()
diff --git a/AX.WebDrillServer/Hubs/FireDeductionHub.cs b/AX.WebDrillServer/Hubs/FireDeductionHub.cs
new file mode 100644
index 0000000..1315797
--- /dev/null
+++ b/AX.WebDrillServer/Hubs/FireDeductionHub.cs
@@ -0,0 +1,176 @@
+using AX.WebDrillServer.Data;
+using AX.WebDrillServer.Extensions;
+using AX.WebDrillServer.Middlewares.Jwts;
+using AX.WebDrillServer.Models;
+using AX.WebDrillServer.Services.FireDeductionHub;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Caching.Memory;
+using System.Collections.Concurrent;
+using System.Security.Claims;
+
+namespace AX.WebDrillServer.Hubs
+{
+ //[Authorize]
+ public class FireDeductionHub : Hub
+ {
+ private readonly RoomManager roomManager;
+
+ private readonly ApplicationDbContext _dbContext;
+
+ private readonly ILogger _logger;
+
+ public FireDeductionHub(
+ ApplicationDbContext dbContext,
+ ILogger logger,
+ RoomManager roomManager)
+ {
+ _dbContext = dbContext;
+ _logger = logger;
+ this.roomManager = roomManager;
+ }
+ public async Task CreateRoom(RoomCreateDto createInfo, FireDeductionUser user)
+ {
+ FireDeductionRoom room = new FireDeductionRoom();
+ room.Owner = createInfo.UserId;
+ room.RoomId = Guid.NewGuid().ToString();
+ room.RoomName = createInfo.RoomName;
+ room.Password = createInfo.RoomPassword;
+ room.Users.Add(user);
+ await Groups.AddToGroupAsync(user.ConnectionId, room.RoomId);
+ return room;
+ }
+ public async Task EnterRoom(string roomId, FireDeductionUser user, string? password = null)
+ {
+ bool result = false;
+
+ var room = roomManager.GetRoom(roomId);
+ if (room != null && room.Password == password)
+ {
+ if (!room.Users.Contains(user))
+ {
+ result = true;
+ }
+ else
+ {
+ throw new NotImplementedException("房间中已经存在该用户!");
+ }
+ }
+ else
+ {
+ throw new NotImplementedException("房间信息有误!");
+ }
+
+
+ return result;
+ }
+
+ public async Task LeaveRoom(string roomId, string userId)
+ {
+ bool result = false;
+ await Task.Run(() =>
+ {
+ var room = roomManager.GetRoom(roomId);
+ if (room != null)
+ {
+ var user = room.Users.FirstOrDefault(u => u.UserId == userId);
+ if (user != null)
+ {
+ room.Users.Remove(user);
+ if (room.Users.Count == 0)
+ {
+ //TODO:保持空房间xx分钟
+ }
+ }
+ else
+ {
+ throw new NotImplementedException("用户信息有误!");
+ }
+ }
+ else
+ {
+ throw new NotImplementedException("房间信息有误!");
+ }
+ });
+
+ return result;
+ }
+ public async Task RoomSendMessage(string RoomId, string Message)
+ {
+ await Clients.Group(RoomId).SendAsync(Message);
+ //TODO:保存数据
+ }
+
+ public async Task SendMessage(string user, string Message)
+ {
+ await Clients.All.SendAsync(Message);
+ //TODO:保存数据
+ }
+
+ public override async Task OnConnectedAsync()
+ {
+ try
+ {
+ var userId = Context.UserIdentifier;
+ var userName = Context.GetNameOfCurrentUser();
+ FireDeductionUser? user = roomManager.GetUser(userId!);
+
+ if (user != null)
+ {
+ user.Online = true;
+ var room = roomManager.GetRoomByUserId(user.UserId);
+ if (room != null)
+ {
+ //断线重连
+ }
+ }
+ else
+ {
+ user = new FireDeductionUser();
+ user.ConnectionId = Context.ConnectionId;
+ user.UserId = userId!;
+ user.UserName = userName!;
+ }
+ _logger.LogInformation("[{userId}][{name}] connected", userId, userName);
+
+ await base.OnConnectedAsync();
+ }
+ catch (Exception)
+ {
+ throw;
+ }
+ }
+
+ public override async Task OnDisconnectedAsync(Exception? exception)
+ {
+ try
+ {
+ var userId = Context.UserIdentifier;
+ var userName = Context.User?.FindFirstValue(JwtClaimTypes.Name);
+ if (userId == null) _logger.LogError("无效的 userId: [{userId}]!", userId);
+
+ if (userId != null)
+ {
+ var user = roomManager.GetUser(userId!);
+ if (user != null)
+ {
+ user.Online = false;
+ var room = roomManager.GetRoomByUserId(user.UserId);
+ if (room != null)
+ {
+ //断线
+ }
+ }
+ }
+
+ await base.OnDisconnectedAsync(exception);
+ _logger.LogInformation("[{userId}][{name}] 断开了连接", userId, userName);
+ }
+ catch (Exception)
+ {
+ throw;
+ }
+ }
+ }
+}
diff --git a/AX.WebDrillServer/Models/Room.cs b/AX.WebDrillServer/Models/Room.cs
deleted file mode 100644
index 4270008..0000000
--- a/AX.WebDrillServer/Models/Room.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace AX.WebDrillServer.Models
-{
- ///
- /// 房间表
- ///
- public class Room : EntityBase
- {
- ///
- /// 密码
- ///
- public string? Password { get; set; }
- ///
- /// 所属
- ///
- public User? Owner { get; set; }
- ///
- /// 用户
- ///
- public ICollection? Users { get; set; }
- }
-}
diff --git a/AX.WebDrillServer/Program.cs b/AX.WebDrillServer/Program.cs
index b7be7c4..1038054 100644
--- a/AX.WebDrillServer/Program.cs
+++ b/AX.WebDrillServer/Program.cs
@@ -5,6 +5,7 @@ using AX.WebDrillServer.Extensions;
using AX.WebDrillServer.Hubs;
using AX.WebDrillServer.Middlewares;
using AX.WebDrillServer.Middlewares.Jwts;
+using AX.WebDrillServer.Services.FireDeductionHub;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Formatters;
@@ -18,7 +19,7 @@ using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
-const string ProductName = "Web服务器";
+const string ProductName = "沙盘推演";
const string ProductVersion = "v1.0";
const string ApiVersion = "v1";
@@ -108,7 +109,7 @@ builder.Services.AddAuthorization();
// Email Service
//builder.Services.AddSingleton();
-
+builder.Services.AddSingleton();
builder.Services.AddMemoryCache();
builder.Services
@@ -271,5 +272,6 @@ app.MapControllers();
//app.MapHub("/hubs/notification");
//app.MapHub("/hubs/taskchat");
+app.MapHub("/hubs/FireDeductionHub");
app.Run();
\ No newline at end of file
diff --git a/AX.WebDrillServer/Services/FireDeductionHub/FireDeductionRoom.cs b/AX.WebDrillServer/Services/FireDeductionHub/FireDeductionRoom.cs
new file mode 100644
index 0000000..64e06c6
--- /dev/null
+++ b/AX.WebDrillServer/Services/FireDeductionHub/FireDeductionRoom.cs
@@ -0,0 +1,35 @@
+using Org.BouncyCastle.Asn1.X509;
+
+namespace AX.WebDrillServer.Services.FireDeductionHub
+{
+ public enum RoomState
+ {
+ 准备 = 0,
+ 进行中,
+ 结束
+ }
+ ///
+ /// 沙盘推演房间
+ ///
+ public class FireDeductionRoom
+ {
+ public string RoomId { get; set; } = null!;
+ public string RoomName { get; set; } = null!;
+ ///
+ /// 房间密码
+ ///
+ public string? Password;
+ public RoomState State { get; set; } = RoomState.准备;
+ ///
+ /// 房间最大人数
+ ///
+ public int MaxPersons = 100;
+ ///
+ /// 房间所属,默认是创建者
+ ///
+ public string Owner { get; set; } = null!;
+ public List Users { get; set; } = new List();
+ public Dictionary? FrameData { get; set; }
+ public Dictionary? EventData { get; set; }
+ }
+}
diff --git a/AX.WebDrillServer/Services/FireDeductionHub/FireDeductionUser.cs b/AX.WebDrillServer/Services/FireDeductionHub/FireDeductionUser.cs
new file mode 100644
index 0000000..2e937ca
--- /dev/null
+++ b/AX.WebDrillServer/Services/FireDeductionHub/FireDeductionUser.cs
@@ -0,0 +1,14 @@
+namespace AX.WebDrillServer.Services.FireDeductionHub
+{
+ ///
+ /// 沙盘推演用户
+ ///
+ public class FireDeductionUser
+ {
+ public string UserId { get; set; } = null!;
+ public string UserName { get; set; } = null!;
+ public bool Online { get; set; } = true;
+ public bool Left { get; set; }
+ public string ConnectionId { get; set; } = null!;
+ }
+}
diff --git a/AX.WebDrillServer/Services/FireDeductionHub/RoomCreateDto.cs b/AX.WebDrillServer/Services/FireDeductionHub/RoomCreateDto.cs
new file mode 100644
index 0000000..4246cf8
--- /dev/null
+++ b/AX.WebDrillServer/Services/FireDeductionHub/RoomCreateDto.cs
@@ -0,0 +1,11 @@
+namespace AX.WebDrillServer.Services.FireDeductionHub
+{
+ public class RoomCreateDto
+ {
+ public string UserId { get; set; } = null!;
+ public string? RoomPassword { get; set; }
+ public string RoomName { get; set; } = null!;
+ public int MaxPerson { get; set; } = 20;
+
+ }
+}
diff --git a/AX.WebDrillServer/Services/FireDeductionHub/RoomManager.cs b/AX.WebDrillServer/Services/FireDeductionHub/RoomManager.cs
new file mode 100644
index 0000000..e6ac7cd
--- /dev/null
+++ b/AX.WebDrillServer/Services/FireDeductionHub/RoomManager.cs
@@ -0,0 +1,79 @@
+namespace AX.WebDrillServer.Services.FireDeductionHub
+{
+ public class RoomManager
+ {
+
+ private List fireDeductionRooms = new List();
+ private List fireDeductionUsers = new List();
+
+
+ public FireDeductionRoom? GetRoom(string roomId)
+ {
+ lock (this)
+ {
+ return fireDeductionRooms.Where(r => r.RoomId == roomId).SingleOrDefault();
+ }
+ }
+ public FireDeductionUser? GetUser(string userId)
+ {
+ lock (this)
+ {
+ return fireDeductionUsers.Where(r => r.UserId == userId).SingleOrDefault();
+ }
+ }
+ public FireDeductionRoom? GetRoomByUserId(string userId)
+ {
+ lock (this)
+ {
+ return fireDeductionRooms.Where(r => r.Users.Where(u => u.UserId == userId).SingleOrDefault() != null).SingleOrDefault();
+ }
+ }
+ public void AddRoom(FireDeductionRoom room)
+ {
+ lock (this)
+ {
+ if (!fireDeductionRooms.Contains(room))
+ {
+ fireDeductionRooms.Add(room);
+ }
+ }
+ }
+ public void RemoveRoom(string roomId)
+ {
+ lock (this)
+ {
+ for (int i = 0; i < fireDeductionRooms.Count; i++)
+ {
+ if (fireDeductionRooms[i].RoomId == roomId)
+ {
+ fireDeductionRooms.RemoveAt(i);
+ }
+ }
+ }
+ }
+
+ public void AddUser(FireDeductionUser user)
+ {
+ lock (this)
+ {
+ if (!fireDeductionUsers.Contains(user))
+ {
+ fireDeductionUsers.Add(user);
+ }
+ }
+ }
+ public void RemoveUser(string userId)
+ {
+ lock (this)
+ {
+ for (int i = 0; i < fireDeductionUsers.Count; i++)
+ {
+ if (fireDeductionUsers[i].UserId == userId)
+ {
+ fireDeductionUsers.RemoveAt(i);
+ }
+ }
+ }
+ }
+ }
+}