Reenabled converter commands. Improved rewards reload on bots with multiple shards.

This commit is contained in:
Master Kwoth 2017-06-24 01:41:24 +02:00
parent 741538a982
commit a8f2ca60c2
7 changed files with 200 additions and 174 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
#Manually added files #Manually added files
patreon_rewards.json
command_errors*.txt command_errors*.txt
src/NadekoBot/Command Errors*.txt src/NadekoBot/Command Errors*.txt

View File

@ -1,94 +1,93 @@
//using Discord; using Discord;
//using Discord.Commands; using Discord.Commands;
//using NadekoBot.Attributes; using NadekoBot.Attributes;
//using NadekoBot.Extensions; using NadekoBot.Extensions;
//using NadekoBot.Services.Utility; using NadekoBot.Services.Utility;
//using System; using System;
//using System.Linq; using System.Linq;
//using System.Threading.Tasks; using System.Threading.Tasks;
////todo Rewrite namespace NadekoBot.Modules.Utility
//namespace NadekoBot.Modules.Utility {
//{ public partial class Utility
// public partial class Utility {
// { [Group]
// [Group] public class UnitConverterCommands : NadekoSubmodule
// public class UnitConverterCommands : NadekoSubmodule {
// { private readonly ConverterService _service;
// private readonly ConverterService _service;
// public UnitConverterCommands(ConverterService service) public UnitConverterCommands(ConverterService service)
// { {
// _service = service; _service = service;
// } }
// [NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
// public async Task ConvertList() public async Task ConvertList()
// { {
// var res = _service.Units.GroupBy(x => x.UnitType) var res = _service.Units.GroupBy(x => x.UnitType)
// .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist"))
// .WithColor(NadekoBot.OkColor), .WithColor(NadekoBot.OkColor),
// (embed, g) => embed.AddField(efb => (embed, g) => embed.AddField(efb =>
// efb.WithName(g.Key.ToTitleCase()) efb.WithName(g.Key.ToTitleCase())
// .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault())
// .OrderBy(x => x))))); .OrderBy(x => x)))));
// await Context.Channel.EmbedAsync(res); await Context.Channel.EmbedAsync(res);
// } }
// [NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
// public async Task Convert(string origin, string target, decimal value) public async Task Convert(string origin, string target, decimal value)
// { {
// var originUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant())); var originUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant()));
// var targetUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); var targetUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant()));
// if (originUnit == null || targetUnit == null) if (originUnit == null || targetUnit == null)
// { {
// await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false);
// return; return;
// } }
// if (originUnit.UnitType != targetUnit.UnitType) if (originUnit.UnitType != targetUnit.UnitType)
// { {
// await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false);
// return; return;
// } }
// decimal res; decimal res;
// if (originUnit.Triggers == targetUnit.Triggers) res = value; if (originUnit.Triggers == targetUnit.Triggers) res = value;
// else if (originUnit.UnitType == "temperature") else if (originUnit.UnitType == "temperature")
// { {
// //don't really care too much about efficiency, so just convert to Kelvin, then to target //don't really care too much about efficiency, so just convert to Kelvin, then to target
// switch (originUnit.Triggers.First().ToUpperInvariant()) switch (originUnit.Triggers.First().ToUpperInvariant())
// { {
// case "C": case "C":
// res = value + 273.15m; //celcius! res = value + 273.15m; //celcius!
// break; break;
// case "F": case "F":
// res = (value + 459.67m) * (5m / 9m); res = (value + 459.67m) * (5m / 9m);
// break; break;
// default: default:
// res = value; res = value;
// break; break;
// } }
// //from Kelvin to target //from Kelvin to target
// switch (targetUnit.Triggers.First().ToUpperInvariant()) switch (targetUnit.Triggers.First().ToUpperInvariant())
// { {
// case "C": case "C":
// res = res - 273.15m; //celcius! res = res - 273.15m; //celcius!
// break; break;
// case "F": case "F":
// res = res * (9m / 5m) - 459.67m; res = res * (9m / 5m) - 459.67m;
// break; break;
// } }
// } }
// else else
// { {
// if (originUnit.UnitType == "currency") if (originUnit.UnitType == "currency")
// { {
// res = (value * targetUnit.Modifier) / originUnit.Modifier; res = (value * targetUnit.Modifier) / originUnit.Modifier;
// } }
// else else
// res = (value * originUnit.Modifier) / targetUnit.Modifier; res = (value * originUnit.Modifier) / targetUnit.Modifier;
// } }
// res = Math.Round(res, 4); res = Math.Round(res, 4);
// await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2)));
// } }
// } }
// } }
//} }

View File

@ -290,7 +290,10 @@ namespace NadekoBot
Task SetClientReady() Task SetClientReady()
{ {
clientReady.TrySetResult(true); var _ = Task.Run(() =>
{
clientReady.TrySetResult(true);
});
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@ -90,5 +90,6 @@
<ItemGroup> <ItemGroup>
<Folder Include="Modules\Music\Classes\" /> <Folder Include="Modules\Music\Classes\" />
<Folder Include="Utility\Services\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -126,7 +126,6 @@ namespace NadekoBot.Services.Impl
return Task.CompletedTask; return Task.CompletedTask;
}; };
//todo carbonitex update
if (sc != null) if (sc != null)
{ {
_carbonitexTimer = new Timer(async (state) => _carbonitexTimer = new Timer(async (state) =>

View File

@ -1,4 +1,6 @@
using NadekoBot.Services.Database.Models; using Discord.WebSocket;
using NadekoBot.Services;
using NadekoBot.Services.Database.Models;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
using System; using System;
@ -11,27 +13,29 @@ using System.Threading.Tasks;
namespace NadekoBot.Services.Utility namespace NadekoBot.Services.Utility
{ {
//todo periodically load from the database, update only on shard 0
public class ConverterService public class ConverterService
{ {
public List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>(); public List<ConvertUnit> Units { get; } = new List<ConvertUnit>();
private readonly Logger _log; private readonly Logger _log;
private Timer _timer; private readonly Timer _currencyUpdater;
private readonly Timer _currencyLoader;
private readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0); private readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0);
private readonly DbService _db; private readonly DbService _db;
public ConverterService(DbService db) public ConverterService(DiscordSocketClient client, DbService db)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;
try try
{ {
var data = JsonConvert.DeserializeObject<List<MeasurementUnit>>(File.ReadAllText("data/units.json")).Select(u => new ConvertUnit() var data = JsonConvert.DeserializeObject<List<MeasurementUnit>>(
{ File.ReadAllText("data/units.json"))
Modifier = u.Modifier, .Select(u => new ConvertUnit()
UnitType = u.UnitType, {
InternalTrigger = string.Join("|", u.Triggers) Modifier = u.Modifier,
}).ToArray(); UnitType = u.UnitType,
InternalTrigger = string.Join("|", u.Triggers)
}).ToArray();
using (var uow = _db.UnitOfWork) using (var uow = _db.UnitOfWork)
{ {
@ -48,10 +52,10 @@ namespace NadekoBot.Services.Utility
_log.Warn("Could not load units: " + ex.Message); _log.Warn("Could not load units: " + ex.Message);
} }
_timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval); _currencyUpdater = new Timer(async (shouldLoad) => await UpdateCurrency((bool)shouldLoad), client.ShardId == 0, _updateInterval, _updateInterval);
} }
public static async Task<Rates> UpdateCurrencyRates() private async Task<Rates> GetCurrencyRates()
{ {
using (var http = new HttpClient()) using (var http = new HttpClient())
{ {
@ -60,38 +64,48 @@ namespace NadekoBot.Services.Utility
} }
} }
public async Task UpdateCurrency() private async Task UpdateCurrency(bool shouldLoad)
{ {
try try
{ {
var currencyRates = await UpdateCurrencyRates();
var unitTypeString = "currency"; var unitTypeString = "currency";
var range = currencyRates.ConversionRates.Select(u => new ConvertUnit() if (shouldLoad)
{ {
InternalTrigger = u.Key, var currencyRates = await GetCurrencyRates();
Modifier = u.Value, var baseType = new ConvertUnit()
UnitType = unitTypeString {
}).ToArray(); Triggers = new[] { currencyRates.Base },
var baseType = new ConvertUnit() Modifier = decimal.One,
{ UnitType = unitTypeString
Triggers = new[] { currencyRates.Base }, };
Modifier = decimal.One, var range = currencyRates.ConversionRates.Select(u => new ConvertUnit()
UnitType = unitTypeString {
}; InternalTrigger = u.Key,
var toRemove = Units.Where(u => u.UnitType == unitTypeString); Modifier = u.Value,
UnitType = unitTypeString
}).ToArray();
var toRemove = Units.Where(u => u.UnitType == unitTypeString);
using (var uow = _db.UnitOfWork) using (var uow = _db.UnitOfWork)
{ {
uow.ConverterUnits.RemoveRange(toRemove.ToArray()); uow.ConverterUnits.RemoveRange(toRemove.ToArray());
uow.ConverterUnits.Add(baseType); uow.ConverterUnits.Add(baseType);
uow.ConverterUnits.AddRange(range); uow.ConverterUnits.AddRange(range);
await uow.CompleteAsync().ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false);
}
Units.RemoveAll(u => u.UnitType == unitTypeString);
Units.Add(baseType);
Units.AddRange(range);
}
else
{
using (var uow = _db.UnitOfWork)
{
Units.RemoveAll(u => u.UnitType == unitTypeString);
Units.AddRange(uow.ConverterUnits.GetAll().ToArray());
}
} }
Units.RemoveAll(u => u.UnitType == unitTypeString);
Units.Add(baseType);
Units.AddRange(range);
_log.Info("Updated Currency");
} }
catch catch
{ {

View File

@ -1,12 +1,15 @@
using NadekoBot.Services.Database.Models; using Discord.WebSocket;
using NadekoBot.Services.Database.Models;
using NadekoBot.Services.Utility.Patreon; using NadekoBot.Services.Utility.Patreon;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -24,12 +27,13 @@ namespace NadekoBot.Services.Utility
private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1);
private readonly Logger _log; private readonly Logger _log;
public readonly TimeSpan Interval = TimeSpan.FromMinutes(15); public readonly TimeSpan Interval = TimeSpan.FromMinutes(3);
private IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly DbService _db; private readonly DbService _db;
private readonly CurrencyService _currency; private readonly CurrencyService _currency;
public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency) public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency,
DiscordSocketClient client)
{ {
_creds = creds; _creds = creds;
_db = db; _db = db;
@ -37,58 +41,63 @@ namespace NadekoBot.Services.Utility
if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken)) if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken))
return; return;
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
Updater = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval); Updater = new Timer(async (load) => await RefreshPledges((bool)load), client.ShardId == 0, TimeSpan.Zero, Interval);
} }
public async Task LoadPledges() public async Task RefreshPledges(bool shouldLoad)
{ {
LastUpdate = DateTime.UtcNow; if (shouldLoad)
await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false);
try
{ {
var rewards = new List<PatreonPledge>(); LastUpdate = DateTime.UtcNow;
var users = new List<PatreonUser>(); await getPledgesLocker.WaitAsync().ConfigureAwait(false);
using (var http = new HttpClient()) try
{ {
http.DefaultRequestHeaders.Clear(); var rewards = new List<PatreonPledge>();
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken); var users = new List<PatreonUser>();
var data = new PatreonData() using (var http = new HttpClient())
{ {
Links = new PatreonDataLinks() http.DefaultRequestHeaders.Clear();
http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken);
var data = new PatreonData()
{ {
next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" Links = new PatreonDataLinks()
} {
}; next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges"
do }
};
do
{
var res = await http.GetStringAsync(data.Links.next)
.ConfigureAwait(false);
data = JsonConvert.DeserializeObject<PatreonData>(res);
var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge");
rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject<PatreonPledge>(x.ToString()))
.Where(x => x.attributes.declined_since == null));
users.AddRange(data.Included
.Where(x => x["type"].ToString() == "user")
.Select(x => JsonConvert.DeserializeObject<PatreonUser>(x.ToString())));
} while (!string.IsNullOrWhiteSpace(data.Links.next));
}
Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward()
{ {
var res = await http.GetStringAsync(data.Links.next) User = y,
.ConfigureAwait(false); Reward = x,
data = JsonConvert.DeserializeObject<PatreonData>(res); }).ToImmutableArray();
var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); File.WriteAllText("./patreon_rewards.json", JsonConvert.SerializeObject(Pledges));
rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject<PatreonPledge>(x.ToString()))
.Where(x => x.attributes.declined_since == null));
users.AddRange(data.Included
.Where(x => x["type"].ToString() == "user")
.Select(x => JsonConvert.DeserializeObject<PatreonUser>(x.ToString())));
} while (!string.IsNullOrWhiteSpace(data.Links.next));
} }
Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() catch (Exception ex)
{ {
User = y, _log.Warn(ex);
Reward = x, }
}).ToImmutableArray(); finally
}
catch (Exception ex)
{
_log.Warn(ex);
}
finally
{
var _ = Task.Run(async () =>
{ {
await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false);
getPledgesLocker.Release(); getPledgesLocker.Release();
}); }
}
else
{
Pledges = JsonConvert.DeserializeObject<PatreonUserAndReward[]>(File.ReadAllText("./patreon_rewards.json"))
.ToImmutableArray();
} }
} }