Skip to content

Commit

Permalink
Merge pull request #35 from m-riley04/T-6
Browse files Browse the repository at this point in the history
T-6 Create basic waiting room for administrators
  • Loading branch information
m-riley04 authored Jan 16, 2025
2 parents 7b330ad + 70b71dd commit 486ae9a
Show file tree
Hide file tree
Showing 26 changed files with 1,036 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Data;
using System.Data.SqlClient;
using System.Text.Json;
using TWISTServer.Enums;

namespace TWISTServer.DatabaseComponents.DataAccessors
{
Expand Down Expand Up @@ -60,14 +61,14 @@ public virtual void Delete(string code)
);
}

public void UpdateParticipants(int id, IEnumerable<int> participantIds)
public void UpdateRound(int simulationId, RoundEnum round)
{
string sql = @$"UPDATE {TableName} SET participants = @participants WHERE {PrimaryKeyColumn} = @id;";
string sql = @$"UPDATE {TableName} SET round = @round WHERE {PrimaryKeyColumn} = @simulationId;";
Database.NonQuery(
sql,
[
new($"@participants", SqlDbType.NVarChar) { Value = JsonSerializer.Serialize(participantIds) },
new($"@id", SqlDbType.Int) { Value = id },
new($"@round", SqlDbType.Int) { Value = (int)round },
new($"@simulationId", SqlDbType.Int) { Value = simulationId },
]
);
}
Expand Down
4 changes: 2 additions & 2 deletions TWIST.Server/DatabaseComponents/Records/ParticipantRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public static ParticipantRecord FromRow(DataRow row)
{
return new ParticipantRecord(
row.Field<int>("participant_id")
, Convert.ToBoolean(row.Field<int?>("country")) ? (CountryEnum)row.Field<int?>("role") : CountryEnum.None
, Convert.ToBoolean(row.Field<int?>("role")) ? (ParticipantRoleEnum)row.Field<int?>("role") : ParticipantRoleEnum.None
, row.Field<CountryEnum?>("country") ?? CountryEnum.NONE
, row.Field<ParticipantRoleEnum?>("role") ?? ParticipantRoleEnum.NONE
, row.Field<int>("simulation_id")
, row.Field<string>("username") ?? ""
, row.Field<string>("email") ?? ""
Expand Down
43 changes: 18 additions & 25 deletions TWIST.Server/DatabaseComponents/Records/SimulationRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,45 @@
namespace TWISTServer.DatabaseComponents.Records
{
public record SimulationRecord(
[property: JsonPropertyName("simulation_id")] int SimulationId,
[property: JsonPropertyName("simulation_id")] int SimulationId,
string Code,
string Name,
IEnumerable<int> Participants,
[property: JsonPropertyName("start_date")] DateTime StartDate,
[property: JsonPropertyName("end_date")] DateTime? EndDate,
bool Active,
string? Responses,
string? Asks,
string? Concessions,
int Round,
string Code
[property: JsonPropertyName("end_date")] DateTime? EndDate,
[property: JsonPropertyName("modified_date")] DateTime? ModifiedDate,
RoundEnum Round,
SimulationStateEnum State,
bool Active,
[property: JsonPropertyName("instructor_id")] int InstructorId
) : IDatabaseRecord<SimulationRecord>
{
public static Dictionary<string, SqlDbType> Columns { get; } = new Dictionary<string, SqlDbType>()
{
{ "simulation_id", SqlDbType.Int },
{ "code", SqlDbType.NVarChar },
{ "name", SqlDbType.NVarChar },
{ "participants", SqlDbType.NVarChar },
{ "start_date", SqlDbType.DateTime },
{ "end_date", SqlDbType.DateTime },
{ "active", SqlDbType.Bit },
{ "responses", SqlDbType.NVarChar },
{ "asks", SqlDbType.NVarChar },
{ "concessions", SqlDbType.NVarChar },
{ "modified_date", SqlDbType.DateTime },
{ "round", SqlDbType.Int },
{ "code", SqlDbType.NVarChar },
{ "state", SqlDbType.Int },
{ "active", SqlDbType.Bit },
{ "instructor_id", SqlDbType.Int },
};

public static SimulationRecord FromRow(DataRow row)
{
// Deserialize participants list
var participantsJson = row.Field<string>("participants") ?? "[]";
var participants = JsonSerializer.Deserialize<IEnumerable<int>>(participantsJson) ?? [];

return new SimulationRecord(
row.Field<int>("simulation_id")
, row.Field<string>("code") ?? ""
, row.Field<string>("name") ?? ""
, participants
, row.Field<DateTime>("start_date")
, row.Field<DateTime?>("end_date")
, row.Field<DateTime?>("modified_date")
, row.Field<RoundEnum>("round")
, row.Field<SimulationStateEnum>("state")
, row.Field<bool>("active")
, row.Field<string?>("responses")
, row.Field<string?>("asks")
, row.Field<string?>("concessions")
, row.Field<int>("round")
, row.Field<string>("code") ?? ""
, row.Field<int>("instructor_id")
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion TWIST.Server/Enums/CountryEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
public enum CountryEnum
{
None = 0,
NONE = 0,
USA,
PRC
}
Expand Down
2 changes: 1 addition & 1 deletion TWIST.Server/Enums/ParticipantRoleEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
public enum ParticipantRoleEnum
{
None = 0,
NONE = 0,
Protectionist,
ProTrade,
Security
Expand Down
10 changes: 10 additions & 0 deletions TWIST.Server/Enums/RoundEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace TWISTServer.Enums
{
public enum RoundEnum
{
NONE = 0,
DOMESTIC = 1,
INTERNATIONAL = 2,
FINAL_TALLY = 3
}
}
9 changes: 9 additions & 0 deletions TWIST.Server/Enums/SimulationStateEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TWISTServer.Enums
{
public enum SimulationStateEnum
{
NONE = 0,
OPENED = 1,
IN_PROGRESS = 2,
}
}
15 changes: 0 additions & 15 deletions TWIST.Server/Hubs/ChatHub.cs

This file was deleted.

123 changes: 108 additions & 15 deletions TWIST.Server/Hubs/RoomHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,33 @@ namespace TWISTServer.Hubs
{
public interface IRoomClient
{
Task InstructorInitialized();
Task ParticipantJoined(ParticipantRecord record);
Task ParticipantKicked(ParticipantRecord record);
Task ParticipantLeft(ParticipantRecord record);
Task ParticipantDisconnected(ParticipantRecord record);
Task ParticipantUpdated(ParticipantRecord record);
Task SimulationStarted();
Task SimulationStarted(SimulationRecord sim);
Task SimulationStopped();
Task SimulationUpdated(SimulationRecord sim);
Task RolesAssigned(ParticipantRecord[] participants);
Task CountriesAssigned(ParticipantRecord[] participants);
Task RoundUpdated(RoundEnum round);
}

public class RoomHub : Hub<IRoomClient>
{
SimulationsDataAccessor simAccessor = new();
ParticipantsDataAccessor partAccessor = new();

public async Task InstructorInitialize(SimulationRecord sim)
{
// Add the instructor to the main simulation group
await Groups.AddToGroupAsync(Context.ConnectionId, sim.Code);

// Send signal
await Clients.Group(sim.Code).InstructorInitialized();
}
public async Task JoinRoom(SimulationRecord sim, string username, string email) // FYI: Methods like this will SILENTLY FAIL if you do not pass the correct param types
{
// Check if the email address does not already exist in sim
Expand All @@ -31,13 +46,9 @@ public class RoomHub : Hub<IRoomClient>
if (_ == null)
{
// Add the participant to participants table
newParticipant = new ParticipantRecord(0, CountryEnum.None, ParticipantRoleEnum.None, sim.SimulationId, username, email, Context.ConnectionId);
newParticipant = new ParticipantRecord(0, CountryEnum.NONE, ParticipantRoleEnum.NONE, sim.SimulationId, username, email, Context.ConnectionId);
int participantId = partAccessor.InsertAndReturnId(newParticipant);
newParticipant = newParticipant with { ParticipantId = participantId };

// Add participant to simulation record
var newParticipants = sim.Participants.Append(participantId);
simAccessor.UpdateParticipants(sim.SimulationId, newParticipants);
}
else
{
Expand Down Expand Up @@ -87,10 +98,6 @@ public override Task OnDisconnectedAsync(Exception? exception)

public async Task LeaveRoom(SimulationRecord sim, ParticipantRecord participant)
{
// Remove participant from simulation record
var newParticipants = sim.Participants.Where(p => p != participant.ParticipantId);
simAccessor.UpdateParticipants(sim.SimulationId, newParticipants);

// Remove the participant from main group
await Groups.RemoveFromGroupAsync(Context.ConnectionId, sim.Code);

Expand All @@ -107,10 +114,6 @@ public async Task KickParticipant(SimulationRecord sim, ParticipantRecord partic
// Remove the participant from the participants table
partAccessor.Delete(participant.ParticipantId);

// Remove participant from simulation record
var newParticipants = sim.Participants.Where(p => p != participant.ParticipantId);
simAccessor.UpdateParticipants(sim.SimulationId, newParticipants);

// Remove the participant from main group
await Groups.RemoveFromGroupAsync(Context.ConnectionId, sim.Code);

Expand Down Expand Up @@ -148,11 +151,101 @@ public async Task UpdateParticipantCountry(SimulationRecord sim, ParticipantReco
await Clients.Group(sim.Code).ParticipantUpdated(participant);
}

// TODO: Implement these methods
public async Task RandomlyAssignCountries(SimulationRecord sim, ParticipantRecord[] participants)
{
List<ParticipantRecord> newParticipants = [];
foreach (ParticipantRecord participant in participants)
{
// Get all countries
var countries = Enum.GetValues<CountryEnum>().ToList();

// Remove the participant's current country
countries.Remove(participant.Country ?? 0);

// Remove the participant from their current team
string teamName = $"{sim.Code}_{participant.Country}";
await Groups.RemoveFromGroupAsync(Context.ConnectionId, teamName);

// Assign a random country
var random = new Random();
var newCountry = countries[random.Next(countries.Count)];

// Update the participant's country
partAccessor.UpdateParticipantCountry(participant.ParticipantId, newCountry);

// Update participant record
ParticipantRecord newParticipant = participant with { Country = newCountry };

// Add the participant to new team
teamName = $"{sim.Code}_{newCountry}";
await Groups.AddToGroupAsync(Context.ConnectionId, teamName);

// Send signal
await Clients.Group(sim.Code).ParticipantUpdated(participant);

// Add participant to group
newParticipants.Add(newParticipant);
}

// Send finished signal
await Clients.Group(sim.Code).CountriesAssigned(newParticipants.ToArray());
}

// TODO: Implement these methods
public async Task RandomlyAssignRoles(SimulationRecord sim, ParticipantRecord[] participants)
{
List<ParticipantRecord> newParticipants = [];
foreach (ParticipantRecord participant in participants)
{
// Get all roles
var roles = Enum.GetValues<ParticipantRoleEnum>().ToList();

// Remove the participant's current role
roles.Remove(participant.Role ?? 0);

// Assign a random role
var random = new Random();
var newRole = roles[random.Next(roles.Count)];

// Update the participant's role
partAccessor.UpdateParticipantRole(participant.ParticipantId, newRole);

// Update participant record
ParticipantRecord newParticipant = participant with { Role = newRole };

// Send signal
await Clients.Group(sim.Code).ParticipantUpdated(participant);

// Add participant to list
newParticipants.Add(newParticipant);
}

// Send finished signal
await Clients.Group(sim.Code).RolesAssigned(newParticipants.ToArray());
}

public async Task StartSimulation(SimulationRecord sim)
{

// Signal
await Clients.Group(sim.Code).SimulationStarted();
await Clients.Group(sim.Code).SimulationStarted(sim);
}

public async Task StopSimulation(SimulationRecord sim)
{

// Signal
await Clients.Group(sim.Code).SimulationStopped();
}

public async Task UpdateRound(SimulationRecord sim, RoundEnum round)
{
// Update the simulation record
simAccessor.UpdateRound(sim.SimulationId, round);

// Signal
await Clients.Group(sim.Code).RoundUpdated(round);
}
}
}
2 changes: 1 addition & 1 deletion TWIST.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
//app.MapStaticAssets();
app.MapControllers();
app.MapFallbackToFile("/index.html");
app.MapHub<RoomHub>("/roomHub");
app.MapHub<RoomHub>("/room-hub");

// Run the app
app.Run();
1 change: 0 additions & 1 deletion TWIST.Server/TWISTServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
<Folder Include="Helpers\" />
<Folder Include="Services\" />
<Folder Include="DatabaseComponents\" />
<Folder Include="Enums\" />
<Folder Include="Extensions\" />
</ItemGroup>

Expand Down
Loading

0 comments on commit 486ae9a

Please sign in to comment.