Skip to content
This repository was archived by the owner on Oct 16, 2022. It is now read-only.

Commit 9dfbd70

Browse files
committed
Fixed /shop migrate sometimes failing due to existing database entries
1 parent 4b79e1d commit 9dfbd70

File tree

5 files changed

+102
-12
lines changed

5 files changed

+102
-12
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using OpenMod.API.Commands;
2+
using OpenMod.API.Ioc;
3+
4+
namespace ShopsUI.API.Migrations
5+
{
6+
[Service]
7+
public interface IMigrationVerifier
8+
{
9+
bool CheckShouldContinueMigration(ICommandActor commandActor);
10+
}
11+
}

ShopsUI - OpenMod/Commands/CShopMigrate.cs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
extern alias MySqlConnectorAnnotations;
22
using Cysharp.Threading.Tasks;
3+
using Microsoft.EntityFrameworkCore;
34
using MySqlConnectorAnnotations::MySql.Data.MySqlClient;
45
using OpenMod.API.Commands;
56
using OpenMod.API.Prioritization;
67
using OpenMod.Core.Commands;
78
using OpenMod.Unturned.Commands;
89
using SDG.Unturned;
10+
using ShopsUI.API.Migrations;
911
using ShopsUI.Commands.Items;
1012
using ShopsUI.Database;
1113
using ShopsUI.Database.Models;
@@ -52,11 +54,14 @@ public class ZaupShopConfiguration
5254
}
5355

5456
private readonly ShopsDbContext _dbContext;
57+
private readonly IMigrationVerifier _migrationVerifier;
5558

5659
public CShopMigrate(ShopsDbContext dbContext,
60+
IMigrationVerifier migrationVerifier,
5761
IServiceProvider serviceProvider) : base(serviceProvider)
5862
{
5963
_dbContext = dbContext;
64+
_migrationVerifier = migrationVerifier;
6065
}
6166

6267
private async Task<T> GetPluginConfig<T>(string path) where T : class, new()
@@ -88,6 +93,19 @@ public CShopMigrate(ShopsDbContext dbContext,
8893
}
8994
}
9095

96+
private async Task ClearExistingDatabase()
97+
{
98+
async Task ClearSet<T>(DbSet<T> set) where T : class
99+
{
100+
set.RemoveRange(await set.ToListAsync());
101+
}
102+
103+
await ClearSet(_dbContext.ItemGroups);
104+
await ClearSet(_dbContext.VehicleGroups);
105+
await ClearSet(_dbContext.ItemShops);
106+
await ClearSet(_dbContext.VehicleShops);
107+
}
108+
91109
private async Task MigrateItemShops(MySqlConnection connection, ZaupShopConfiguration config)
92110
{
93111
var query = $"SELECT `id`,`cost`,`buyback` FROM `{config.ItemShopTableName}`;";
@@ -140,9 +158,9 @@ private async Task MigrateGroups(MySqlConnection connection, ZaupShopConfigurati
140158

141159
var tables = new List<(string Name, bool Whitelist)>();
142160

143-
using (var command = new MySqlCommand(mainGroupQuery, connection))
161+
await using (var command = new MySqlCommand(mainGroupQuery, connection))
144162
{
145-
using var reader = command.ExecuteReader();
163+
await using var reader = await command.ExecuteReaderAsync();
146164

147165
while (await reader.ReadAsync())
148166
{
@@ -158,9 +176,9 @@ private async Task MigrateGroups(MySqlConnection connection, ZaupShopConfigurati
158176
{
159177
var groupTableQuery = $"SELECT `assetid`,`vehicle` FROM `{name}`;";
160178

161-
using var command = new MySqlCommand(groupTableQuery, connection);
179+
await using var command = new MySqlCommand(groupTableQuery, connection);
162180

163-
using var reader = command.ExecuteReader();
181+
await using var reader = await command.ExecuteReaderAsync();
164182

165183
while (await reader.ReadAsync())
166184
{
@@ -191,6 +209,14 @@ await _dbContext.ItemGroups.AddAsync(new ItemGroupModel
191209

192210
protected override async UniTask OnExecuteAsync()
193211
{
212+
if (!_migrationVerifier.CheckShouldContinueMigration(Context.Actor))
213+
{
214+
await PrintAsync("By using this migration command, you will erase all existing ShopsUI shops. " +
215+
"If you wish to continue, please run the command again.");
216+
217+
return;
218+
}
219+
194220
await UniTask.SwitchToThreadPool();
195221

196222
await PrintAsync("Beginning shop migration. This may take a while.");
@@ -209,7 +235,9 @@ protected override async UniTask OnExecuteAsync()
209235
$"User={uconomyConfig.DatabaseUsername};" +
210236
$"Password={uconomyConfig.DatabasePassword}";
211237

212-
using var connection = new MySqlConnection(connectionString);
238+
await ClearExistingDatabase();
239+
240+
await using var connection = new MySqlConnection(connectionString);
213241

214242
await connection.OpenAsync();
215243

@@ -224,9 +252,12 @@ protected override async UniTask OnExecuteAsync()
224252

225253
await connection.CloseAsync();
226254

227-
var entries = await _dbContext.SaveChangesAsync();
255+
await _dbContext.SaveChangesAsync();
256+
257+
var itemShops = await _dbContext.ItemShops.CountAsync();
258+
var vehicleShops = await _dbContext.VehicleShops.CountAsync();
228259

229-
await PrintAsync($"Successfully migrated and written {entries} new entries to the database.");
260+
await PrintAsync($"Successfully migrated {itemShops} item shops and {vehicleShops} vehicle shops.");
230261

231262
if (migrateGroups)
232263
{

ShopsUI - OpenMod/Commands/Vehicles/CVShop.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Cysharp.Threading.Tasks;
22
using OpenMod.API;
3-
using OpenMod.API.Commands;
43
using OpenMod.API.Prioritization;
54
using OpenMod.Core.Commands;
65
using OpenMod.Unturned.Commands;

ShopsUI - OpenMod/PluginContainerConfigurator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
namespace ShopsUI
66
{
77
public class PluginContainerConfigurator : IPluginContainerConfigurator
8-
{
9-
public void ConfigureContainer(IPluginServiceConfigurationContext context)
108
{
11-
context.ContainerBuilder.AddMySqlDbContext<ShopsDbContext>();
9+
public void ConfigureContainer(IPluginServiceConfigurationContext context)
10+
{
11+
context.ContainerBuilder.AddMySqlDbContext<ShopsDbContext>();
12+
}
1213
}
1314
}
14-
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using OpenMod.API.Commands;
3+
using OpenMod.API.Ioc;
4+
using OpenMod.API.Permissions;
5+
using OpenMod.API.Prioritization;
6+
using ShopsUI.API.Migrations;
7+
using System;
8+
using System.Collections.Concurrent;
9+
10+
namespace ShopsUI.ZaupShopMigrations
11+
{
12+
[ServiceImplementation(Lifetime = ServiceLifetime.Singleton, Priority = Priority.Lowest)]
13+
public class MigrationVerifier : IMigrationVerifier
14+
{
15+
private readonly struct UserIdentifier
16+
{
17+
private string UserId { get; }
18+
19+
private string UserType { get; }
20+
21+
public UserIdentifier(IPermissionActor actor)
22+
{
23+
UserId = actor.Id;
24+
UserType = actor.Type;
25+
}
26+
}
27+
28+
private readonly ConcurrentDictionary<UserIdentifier, DateTime> _lastChecked = new();
29+
30+
public const float MaxConfirmationTime = 30; // seconds
31+
32+
public bool CheckShouldContinueMigration(ICommandActor commandActor)
33+
{
34+
var userId = new UserIdentifier(commandActor);
35+
36+
if (_lastChecked.TryGetValue(userId, out var lastChecked))
37+
{
38+
if ((DateTime.Now - lastChecked).TotalSeconds < MaxConfirmationTime)
39+
{
40+
return true;
41+
}
42+
}
43+
44+
_lastChecked.AddOrUpdate(userId, DateTime.Now, (_, _) => DateTime.Now);
45+
46+
return false;
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)