Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Issue 542: Implement CombatPoints, Crystal and CrystalPerPrice Calculation in ProductStateHandler #564

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
12 changes: 12 additions & 0 deletions Lib9c.Models/Extensions/EquipmentExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Bencodex.Types;
using Lib9c.Models.Items;

namespace Lib9c.Models.Extensions;

public static class EquipmentExtensions
{
public static Nekoyume.Model.Item.Equipment ToNekoyumeEquipment(this Equipment equipment)
{
return new Nekoyume.Model.Item.Equipment((Dictionary)equipment.Bencoded);
}
}
1 change: 1 addition & 0 deletions Mimir.Initializer/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class Configuration
public string? MongoDbCAFile { get; init; }
public string ChainStorePath { get; init; }
public string[] TargetAccounts { get; init; }
public RunOptions RunOptions { get; init; }

public Address[] GetTargetAddresses() =>
TargetAccounts.Select(adr => new Address(adr)).ToArray();
Expand Down
24 changes: 24 additions & 0 deletions Mimir.Initializer/ExecuteManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace Mimir.Initializer;

public class ExecuteManager
{
private readonly IEnumerable<IExecutor> _executors;

public ExecuteManager(IEnumerable<IExecutor> executors)
{
_executors = executors;
}

public async Task ExecuteAsync(CancellationToken cancellationToken)
{
foreach (var executor in _executors)
{
if (!executor.ShouldRun())
{
continue;
}

await executor.RunAsync(cancellationToken);
}
}
}
8 changes: 8 additions & 0 deletions Mimir.Initializer/IExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Mimir.Initializer;

public interface IExecutor
{
bool ShouldRun();

Task RunAsync(CancellationToken stoppingToken);
}
18 changes: 11 additions & 7 deletions Mimir.Initializer/Initializer/SnapshotInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Libplanet.Crypto;
using Libplanet.Store;
using Libplanet.Store.Trie;
using Microsoft.Extensions.Options;
using Mimir.Initializer.Util;
using Mimir.MongoDB;
using Mimir.MongoDB.Bson;
Expand All @@ -15,25 +16,28 @@

namespace Mimir.Initializer.Initializer;

public class SnapshotInitializer
public class SnapshotInitializer : IExecutor
{
private readonly MongoDbService _dbService;
private readonly ILogger _logger;
private readonly string _chainStorePath;
private Address[] _targetAccounts;
private readonly bool _shouldRun;
private readonly Address[] _targetAccounts;

public SnapshotInitializer(
MongoDbService dbService,
string chainStorePath,
Address[] targetAccounts
IOptions<Configuration> configuration,
MongoDbService dbService
)
{
_dbService = dbService;
_chainStorePath = chainStorePath;
_targetAccounts = targetAccounts;
_chainStorePath = configuration.Value.ChainStorePath;
_targetAccounts = configuration.Value.GetTargetAddresses();
_shouldRun = configuration.Value.RunOptions.HasFlag(RunOptions.SnapShotInitializer);
_logger = Log.ForContext<SnapshotInitializer>();
}

public bool ShouldRun() => _shouldRun;

public async Task RunAsync(CancellationToken stoppingToken)
{
var started = DateTime.UtcNow;
Expand Down
100 changes: 100 additions & 0 deletions Mimir.Initializer/Migrators/ProductMigrator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Microsoft.Extensions.Options;
using Mimir.MongoDB;
using Mimir.MongoDB.Bson;
using Mimir.Worker.Services;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Nekoyume.Model.Market;
using Serilog;
using ItemProduct = Lib9c.Models.Market.ItemProduct;

namespace Mimir.Initializer.Migrators;

public class ProductMigrator : IExecutor
{
private readonly IOptions<Configuration> _configuration;
private readonly MongoDbService _dbService;
private readonly IItemProductCalculationService _itemProductCalculationService;
private readonly ILogger _logger;

public ProductMigrator(IOptions<Configuration> configuration, MongoDbService dbService,
IItemProductCalculationService itemProductCalculationService, ILogger logger)
{
_configuration = configuration;
_dbService = dbService;
_itemProductCalculationService = itemProductCalculationService;
_logger = logger;
}

public bool ShouldRun()
{
return _configuration.Value.RunOptions.HasFlag(RunOptions.ProductMigrator);
}

public async Task RunAsync(CancellationToken stoppingToken)
{
var collectionName = CollectionNames.GetCollectionName<ProductDocument>();
var collection = _dbService.GetCollection(collectionName);

var builder = new FilterDefinitionBuilder<BsonDocument>();
var filter = builder.Not(builder.Exists(nameof(ProductDocument.Crystal)));
filter |= builder.Not(builder.Exists(nameof(ProductDocument.CombatPoint)));
filter = builder.And(filter, builder.Eq("Object.ProductType", Enum.GetName(ProductType.NonFungible)));

var asyncCursor = await collection.FindAsync(filter, cancellationToken: stoppingToken);
var bsonDocs = await asyncCursor.ToListAsync(cancellationToken: stoppingToken);

var updateDocuments = new List<WriteModel<BsonDocument>>();
_logger.Information("Updating {BsonDocsCount} ProductDocuments with CombatPoints and Crystals", bsonDocs.Count);
for (var index = 0; index < bsonDocs.Count; index++)
{
if (stoppingToken.IsCancellationRequested)
{
return;
}

var productDocument = BsonSerializer.Deserialize<ProductDocument>(bsonDocs[index]);
if (productDocument?.Object is not ItemProduct itemProduct)
{
continue;
}

int? crystal = null;
int? crystalPerPrice = null;
int? combatPoint = null;
try
{
(crystal, crystalPerPrice) = await _itemProductCalculationService.CalculateCrystalMetricsAsync(itemProduct);
}
catch (Exception ex)
{
_logger.Error("Error calculating crystal metrics for itemProduct {ItemProductProductId}: {ExMessage}",
itemProduct.ProductId, ex.Message);
}

try
{
combatPoint = await _itemProductCalculationService.CalculateCombatPointAsync(itemProduct);
}
catch (Exception ex)
{
_logger.Error("Error calculating combat point for itemProduct {ItemProductProductId}: {ExMessage}",
itemProduct.ProductId, ex.Message);
}


var newProductDocument = productDocument with { Crystal = crystal, CrystalPerPrice = crystalPerPrice, CombatPoint = combatPoint };
updateDocuments.Add(newProductDocument.ToUpdateOneModel());

_logger.Debug("\rUpdated of {Index} of {BsonDocsCount}", index + 1, bsonDocs.Count);
}

_logger.Information("Saving changed models to {CollectionName} collection", collectionName);

await _dbService.UpsertStateDataManyAsync(
collectionName,
updateDocuments,
cancellationToken: stoppingToken);
}
}
5 changes: 5 additions & 0 deletions Mimir.Initializer/Mimir.Initializer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@
<ProjectReference Include="..\Mimir.Worker\Mimir.Worker.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
Atralupus marked this conversation as resolved.
Show resolved Hide resolved
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
23 changes: 11 additions & 12 deletions Mimir.Initializer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
using Microsoft.Extensions.Options;
using Mimir.Initializer;
using Mimir.Initializer.Initializer;
using Mimir.Initializer.Migrators;
using Mimir.Worker.Services;
using Serilog;

var builder = Host.CreateDefaultBuilder(args)
var host = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(
(hostingContext, config) =>
{
Expand Down Expand Up @@ -36,14 +37,12 @@
config.MongoDbCAFile
);
});

services.AddTransient<SnapshotInitializer>(serviceProvider =>
{
var config = serviceProvider.GetRequiredService<IOptions<Configuration>>().Value;
var dbService = serviceProvider.GetRequiredService<MongoDbService>();
var targetAccounts = config.GetTargetAddresses();
return new SnapshotInitializer(dbService, config.ChainStorePath, targetAccounts);
});

services.AddSingleton<IItemProductCalculationService, ItemProductCalculationService>();
Atralupus marked this conversation as resolved.
Show resolved Hide resolved

services.AddSingleton<ExecuteManager>();
services.AddSingleton<IExecutor, SnapshotInitializer>();
services.AddSingleton<IExecutor, ProductMigrator>();
}
)
.UseSerilog(
Expand All @@ -54,9 +53,9 @@
)
.Build();

using var scope = builder.Services.CreateScope();
var initializer = scope.ServiceProvider.GetRequiredService<SnapshotInitializer>();
using var scope = host.Services.CreateScope();
var executeManager = scope.ServiceProvider.GetRequiredService<ExecuteManager>();

var stoppingToken = new CancellationTokenSource().Token;

await initializer.RunAsync(stoppingToken);
await executeManager.ExecuteAsync(stoppingToken);
11 changes: 11 additions & 0 deletions Mimir.Initializer/RunOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;

namespace Mimir.Initializer;

[Flags]
[JsonConverter(typeof(JsonStringEnumConverter<RunOptions>))]
public enum RunOptions
{
SnapShotInitializer = 1,
ProductMigrator = 2
}
3 changes: 2 additions & 1 deletion Mimir.Initializer/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"000000000000000000000000000000000000001a",
"000000000000000000000000000000000000001b"
],
"EnableInitializing": true
"EnableInitializing": true,
"RunOptions" : "SnapShotInitializer, ProductMigrator"
}
}
Loading
Loading