Changed all locks to SemaphoreSlims, Slight musicbuffer changes.
This commit is contained in:
		| @@ -6,6 +6,8 @@ using System.Collections.ObjectModel; | ||||
| using System.ComponentModel; | ||||
| using System.IO; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Classes | ||||
| { | ||||
| @@ -27,9 +29,12 @@ namespace NadekoBot.Classes | ||||
|                 { | ||||
|                     configs = JsonConvert | ||||
|                         .DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>( | ||||
|                             File.ReadAllText(filePath), new JsonSerializerSettings() { | ||||
|                                 Error = (s,e) => { | ||||
|                                     if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") { | ||||
|                             File.ReadAllText(filePath), new JsonSerializerSettings() | ||||
|                             { | ||||
|                                 Error = (s, e) => | ||||
|                                 { | ||||
|                                     if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") | ||||
|                                     { | ||||
|                                         e.ErrorContext.Handled = true; | ||||
|                                     } | ||||
|                                 } | ||||
| @@ -52,14 +57,19 @@ namespace NadekoBot.Classes | ||||
|         public ServerSpecificConfig Of(ulong id) => | ||||
|             configs.GetOrAdd(id, _ => new ServerSpecificConfig()); | ||||
|  | ||||
|         private readonly object saveLock = new object(); | ||||
|         private readonly SemaphoreSlim saveLock = new SemaphoreSlim(1, 1); | ||||
|  | ||||
|         public void Save() | ||||
|         public async Task Save() | ||||
|         { | ||||
|             lock (saveLock) | ||||
|             await saveLock.WaitAsync(); | ||||
|             try | ||||
|             { | ||||
|                 File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented)); | ||||
|             } | ||||
|             finally | ||||
|             { | ||||
|                 saveLock.Release(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -245,7 +255,7 @@ namespace NadekoBot.Classes | ||||
|             LogserverIgnoreChannels = new ObservableCollection<ulong>(); | ||||
|         } | ||||
|  | ||||
|         public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); }; | ||||
|         public event PropertyChangedEventHandler PropertyChanged = async delegate { await SpecificConfigurations.Default.Save().ConfigureAwait(false); }; | ||||
|  | ||||
|         private void OnPropertyChanged([CallerMemberName] string propertyName = null) | ||||
|         { | ||||
|   | ||||
| @@ -70,7 +70,7 @@ namespace NadekoBot.Modules.Administration | ||||
|                     { | ||||
|                         var conf = SpecificConfigurations.Default.Of(e.Server.Id); | ||||
|                         conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand; | ||||
|                         Classes.JSONModels.ConfigHandler.SaveConfig(); | ||||
|                         await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                         if (conf.AutoDeleteMessagesOnCommand) | ||||
|                             await e.Channel.SendMessage("❗`Now automatically deleting successfull command invokations.`"); | ||||
|                         else | ||||
|   | ||||
| @@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                         NadekoBot.Config.CustomReactions[name].Add(message); | ||||
|                     else | ||||
|                         NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List<string>() { message }); | ||||
|                     await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false); | ||||
|                     await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                     await e.Channel.SendMessage($"Added {name} : {message}").ConfigureAwait(false); | ||||
|  | ||||
|                 }); | ||||
| @@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                     index = index - 1; | ||||
|                     NadekoBot.Config.CustomReactions[name][index] = msg; | ||||
|  | ||||
|                     await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false); | ||||
|                     await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                     await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false); | ||||
|                 }); | ||||
|  | ||||
| @@ -183,7 +183,7 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                         NadekoBot.Config.CustomReactions.Remove(name); | ||||
|                         message = $"Deleted custom reaction: `{name}`"; | ||||
|                     } | ||||
|                     await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false); | ||||
|                     await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                     await e.Channel.SendMessage(message).ConfigureAwait(false); | ||||
|                 }); | ||||
|         } | ||||
|   | ||||
| @@ -7,8 +7,10 @@ using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using System.Timers; | ||||
| using Timer = System.Timers.Timer; | ||||
|  | ||||
| namespace NadekoBot.Modules.Administration.Commands | ||||
| { | ||||
| @@ -36,7 +38,7 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                 {"%trivia%", () => Games.Commands.TriviaCommands.RunningTrivias.Count.ToString()} | ||||
|             }; | ||||
|  | ||||
|         private readonly object playingPlaceholderLock = new object(); | ||||
|         private readonly SemaphoreSlim playingPlaceholderLock = new SemaphoreSlim(1,1); | ||||
|  | ||||
|         public PlayingRotate(DiscordModule module) : base(module) | ||||
|         { | ||||
| @@ -47,7 +49,9 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                 { | ||||
|                     i++; | ||||
|                     var status = ""; | ||||
|                     lock (playingPlaceholderLock) | ||||
|                     //wtf am i doing, just use a queue ffs | ||||
|                     await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); | ||||
|                     try | ||||
|                     { | ||||
|                         if (PlayingPlaceholders.Count == 0 | ||||
|                             || NadekoBot.Config.RotatingStatuses.Count == 0 | ||||
| @@ -59,6 +63,7 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                         status = PlayingPlaceholders.Aggregate(status, | ||||
|                             (current, kvp) => current.Replace(kvp.Key, kvp.Value())); | ||||
|                     } | ||||
|                     finally { playingPlaceholderLock.Release(); } | ||||
|                     if (string.IsNullOrWhiteSpace(status)) | ||||
|                         return; | ||||
|                     await Task.Run(() => { NadekoBot.Client.SetGame(status); }); | ||||
| @@ -71,14 +76,18 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|  | ||||
|         public Func<CommandEventArgs, Task> DoFunc() => async e => | ||||
|         { | ||||
|             lock (playingPlaceholderLock) | ||||
|             await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); | ||||
|             try | ||||
|             { | ||||
|                 if (timer.Enabled) | ||||
|                     timer.Stop(); | ||||
|                 else | ||||
|                     timer.Start(); | ||||
|                 NadekoBot.Config.IsRotatingStatus = timer.Enabled; | ||||
|                 ConfigHandler.SaveConfig(); | ||||
|                 await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|             } | ||||
|             finally { | ||||
|                 playingPlaceholderLock.Release(); | ||||
|             } | ||||
|             await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`").ConfigureAwait(false); | ||||
|         }; | ||||
| @@ -102,10 +111,15 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                     var arg = e.GetArg("text"); | ||||
|                     if (string.IsNullOrWhiteSpace(arg)) | ||||
|                         return; | ||||
|                     lock (playingPlaceholderLock) | ||||
|                     await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); | ||||
|                     try | ||||
|                     { | ||||
|                         NadekoBot.Config.RotatingStatuses.Add(arg); | ||||
|                         ConfigHandler.SaveConfig(); | ||||
|                         await ConfigHandler.SaveConfig(); | ||||
|                     } | ||||
|                     finally | ||||
|                     { | ||||
|                         playingPlaceholderLock.Release(); | ||||
|                     } | ||||
|                     await e.Channel.SendMessage("🆗 `Added a new playing string.`").ConfigureAwait(false); | ||||
|                 }); | ||||
| @@ -137,14 +151,15 @@ namespace NadekoBot.Modules.Administration.Commands | ||||
|                     var arg = e.GetArg("number"); | ||||
|                     int num; | ||||
|                     string str; | ||||
|                     lock (playingPlaceholderLock) | ||||
|                     { | ||||
|                     await playingPlaceholderLock.WaitAsync().ConfigureAwait(false); | ||||
|                     try { | ||||
|                         if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count) | ||||
|                             return; | ||||
|                         str = NadekoBot.Config.RotatingStatuses[num - 1]; | ||||
|                         NadekoBot.Config.RotatingStatuses.RemoveAt(num - 1); | ||||
|                         ConfigHandler.SaveConfig(); | ||||
|                         await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                     } | ||||
|                     finally { playingPlaceholderLock.Release(); } | ||||
|                     await e.Channel.SendMessage($"🆗 `Removed playing string #{num}`({str})").ConfigureAwait(false); | ||||
|                 }); | ||||
|         } | ||||
|   | ||||
| @@ -7,6 +7,7 @@ using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| using NadekoBot.Modules.Permissions.Classes; | ||||
| using System.Threading; | ||||
|  | ||||
| namespace NadekoBot.Modules.ClashOfClans | ||||
| { | ||||
| @@ -16,8 +17,6 @@ namespace NadekoBot.Modules.ClashOfClans | ||||
|  | ||||
|         public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; } = new ConcurrentDictionary<ulong, List<ClashWar>>(); | ||||
|  | ||||
|         private readonly object writeLock = new object(); | ||||
|  | ||||
|         public override void Install(ModuleManager manager) | ||||
|         { | ||||
|             manager.CreateCommands("", cgb => | ||||
|   | ||||
| @@ -9,6 +9,7 @@ using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Security.Cryptography; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Modules.Games.Commands | ||||
| @@ -59,7 +60,7 @@ namespace NadekoBot.Modules.Games.Commands | ||||
|         //channelid/messageid pair | ||||
|         ConcurrentDictionary<ulong, IEnumerable<Message>> plantedFlowerChannels = new ConcurrentDictionary<ulong, IEnumerable<Message>>(); | ||||
|  | ||||
|         private object locker = new object(); | ||||
|         private SemaphoreSlim locker = new SemaphoreSlim(1,1); | ||||
|  | ||||
|         internal override void Init(CommandGroupBuilder cgb) | ||||
|         { | ||||
| @@ -84,32 +85,34 @@ namespace NadekoBot.Modules.Games.Commands | ||||
|  | ||||
|             cgb.CreateCommand(Module.Prefix + "plant") | ||||
|                 .Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)") | ||||
|                 .Do(e => | ||||
|                 .Do(async e => | ||||
|                 { | ||||
|                     lock (locker) | ||||
|                     await locker.WaitAsync().ConfigureAwait(false); | ||||
|                     try | ||||
|                     { | ||||
|                         if (plantedFlowerChannels.ContainsKey(e.Channel.Id)) | ||||
|                         { | ||||
|                             e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel."); | ||||
|                             await e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.").ConfigureAwait(false); | ||||
|                             return; | ||||
|                         } | ||||
|                         var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).GetAwaiter().GetResult(); | ||||
|                         var removed = await FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).ConfigureAwait(false); | ||||
|                         if (!removed) | ||||
|                         { | ||||
|                             e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait(); | ||||
|                             await e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").ConfigureAwait(false); | ||||
|                             return; | ||||
|                         } | ||||
|  | ||||
|                         var file = GetRandomCurrencyImagePath(); | ||||
|                         Message msg; | ||||
|                         if (file == null) | ||||
|                             msg = e.Channel.SendMessage(NadekoBot.Config.CurrencySign).GetAwaiter().GetResult(); | ||||
|                             msg = await e.Channel.SendMessage(NadekoBot.Config.CurrencySign).ConfigureAwait(false); | ||||
|                         else | ||||
|                             msg = e.Channel.SendFile(file).GetAwaiter().GetResult(); | ||||
|                             msg = await e.Channel.SendFile(file).ConfigureAwait(false); | ||||
|                         var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]); | ||||
|                         var msg2 = e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").GetAwaiter().GetResult(); | ||||
|                         var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false); | ||||
|                         plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 }); | ||||
|                     } | ||||
|                     finally { locker.Release();  } | ||||
|                 }); | ||||
|  | ||||
|             cgb.CreateCommand(Prefix + "gencurrency") | ||||
| @@ -129,12 +132,12 @@ namespace NadekoBot.Modules.Games.Commands | ||||
|                     int throwaway; | ||||
|                     if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway)) | ||||
|                     { | ||||
|                         await e.Channel.SendMessage("`Currency generation disabled on this channel.`"); | ||||
|                         await e.Channel.SendMessage("`Currency generation disabled on this channel.`").ConfigureAwait(false); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd)) | ||||
|                             await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`"); | ||||
|                             await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`").ConfigureAwait(false); | ||||
|                     } | ||||
|                 }); | ||||
|         } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
| { | ||||
|     internal class TriviaGame | ||||
|     { | ||||
|         private readonly object _guessLock = new object(); | ||||
|         private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1,1); | ||||
|  | ||||
|         private Server server { get; } | ||||
|         private Channel channel { get; } | ||||
| @@ -113,7 +113,8 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|                 if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return; | ||||
|  | ||||
|                 var guess = false; | ||||
|                 lock (_guessLock) | ||||
|                 await _guessLock.WaitAsync().ConfigureAwait(false); | ||||
|                 try | ||||
|                 { | ||||
|                     if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested) | ||||
|                     { | ||||
| @@ -122,6 +123,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia | ||||
|                         guess = true; | ||||
|                     } | ||||
|                 } | ||||
|                 catch { _guessLock.Release(); } | ||||
|                 if (!guess) return; | ||||
|                 triviaCancelSource.Cancel(); | ||||
|                 await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); | ||||
|   | ||||
| @@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Music.Classes | ||||
|  | ||||
|         public int BufferSize { get; } | ||||
|  | ||||
|         private readonly object readWriteLock = new object(); | ||||
|         private readonly SemaphoreSlim readWriteLock = new SemaphoreSlim(1, 1); | ||||
|  | ||||
|         public PoopyBuffer(int size) | ||||
|         { | ||||
| @@ -32,51 +32,57 @@ namespace NadekoBot.Modules.Music.Classes | ||||
|             ringBuffer = new byte[size]; | ||||
|         } | ||||
|  | ||||
|         public int Read(byte[] buffer, int count) | ||||
|         public Task<int> ReadAsync(byte[] buffer, int count) | ||||
|         { | ||||
|             if (buffer.Length < count) | ||||
|                 throw new ArgumentException(); | ||||
|             //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***"); | ||||
|             lock (readWriteLock) | ||||
|             return Task.Run(async () => | ||||
|             { | ||||
|                 //read as much as you can if you're reading too much | ||||
|                 if (count > ContentLength) | ||||
|                     count = ContentLength; | ||||
|                 //if nothing to read, return 0 | ||||
|                 if (WritePosition == ReadPosition) | ||||
|                     return 0; | ||||
|                 // if buffer is in the "normal" state, just read | ||||
|                 if (WritePosition > ReadPosition) | ||||
|                 if (buffer.Length < count) | ||||
|                     throw new ArgumentException(); | ||||
|                 //Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***"); | ||||
|                 await readWriteLock.WaitAsync().ConfigureAwait(false); | ||||
|                 try | ||||
|                 { | ||||
|                     Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); | ||||
|                     ReadPosition += count; | ||||
|                     //Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]"); | ||||
|                     //read as much as you can if you're reading too much | ||||
|                     if (count > ContentLength) | ||||
|                         count = ContentLength; | ||||
|                     //if nothing to read, return 0 | ||||
|                     if (WritePosition == ReadPosition) | ||||
|                         return 0; | ||||
|                     // if buffer is in the "normal" state, just read | ||||
|                     if (WritePosition > ReadPosition) | ||||
|                     { | ||||
|                         Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); | ||||
|                         ReadPosition += count; | ||||
|                         //Console.WriteLine($"Read only normally1 {count}[{ReadPosition - count} to {ReadPosition}]"); | ||||
|                         return count; | ||||
|                     } | ||||
|                     //else ReadPos <Writepos | ||||
|                     // buffer is in its inverted state | ||||
|                     // A: if i can read as much as possible without hitting the buffer.length, read that | ||||
|  | ||||
|                     if (count + ReadPosition <= BufferSize) | ||||
|                     { | ||||
|                         Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); | ||||
|                         ReadPosition += count; | ||||
|                         //Console.WriteLine($"Read only normally2 {count}[{ReadPosition - count} to {ReadPosition}]"); | ||||
|                         return count; | ||||
|                     } | ||||
|                     // B: if i can't read as much, read to the end, | ||||
|                     var readNormaly = BufferSize - ReadPosition; | ||||
|                     Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, readNormaly); | ||||
|  | ||||
|                     //Console.WriteLine($"Read normaly {count}[{ReadPosition} to {ReadPosition + readNormaly}]"); | ||||
|                     //then read the remaining amount from the start | ||||
|  | ||||
|                     var readFromStart = count - readNormaly; | ||||
|                     Buffer.BlockCopy(ringBuffer, 0, buffer, readNormaly, readFromStart); | ||||
|                     //Console.WriteLine($"Read From start {readFromStart}[{0} to {readFromStart}]"); | ||||
|                     ReadPosition = readFromStart; | ||||
|                     return count; | ||||
|                 } | ||||
|                 //else ReadPos <Writepos | ||||
|                 // buffer is in its inverted state | ||||
|                 // A: if i can read as much as possible without hitting the buffer.length, read that | ||||
|                 finally { readWriteLock.Release(); } | ||||
|             }); | ||||
|  | ||||
|                 if (count + ReadPosition <= BufferSize) | ||||
|                 { | ||||
|                     Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, count); | ||||
|                     ReadPosition += count; | ||||
|                     //Console.WriteLine($"Read only normally2 {count}[{ReadPosition - count} to {ReadPosition}]"); | ||||
|                     return count; | ||||
|                 } | ||||
|                 // B: if i can't read as much, read to the end, | ||||
|                 var readNormaly = BufferSize - ReadPosition; | ||||
|                 Buffer.BlockCopy(ringBuffer, ReadPosition, buffer, 0, readNormaly); | ||||
|  | ||||
|                 //Console.WriteLine($"Read normaly {count}[{ReadPosition} to {ReadPosition + readNormaly}]"); | ||||
|                 //then read the remaining amount from the start | ||||
|  | ||||
|                 var readFromStart = count - readNormaly; | ||||
|                 Buffer.BlockCopy(ringBuffer, 0, buffer, readNormaly, readFromStart); | ||||
|                 //Console.WriteLine($"Read From start {readFromStart}[{0} to {readFromStart}]"); | ||||
|                 ReadPosition = readFromStart; | ||||
|                 return count; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken) | ||||
| @@ -89,32 +95,37 @@ namespace NadekoBot.Modules.Music.Classes | ||||
|                 if (cancelToken.IsCancellationRequested) | ||||
|                     return; | ||||
|             } | ||||
|             //the while above assures that i cannot write past readposition with my write, so i don't have to check | ||||
|             // *unless its multithreaded or task is not awaited | ||||
|             lock (readWriteLock) | ||||
|             await Task.Run(async () => | ||||
|             { | ||||
|                 // if i can just write without hitting buffer.length, do it | ||||
|                 if (WritePosition + count < BufferSize) | ||||
|                 //the while above assures that i cannot write past readposition with my write, so i don't have to check | ||||
|                 // *unless its multithreaded or task is not awaited | ||||
|                 await readWriteLock.WaitAsync().ConfigureAwait(false); | ||||
|                 try | ||||
|                 { | ||||
|                     Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count); | ||||
|                     WritePosition += count; | ||||
|                     //Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]"); | ||||
|                     return; | ||||
|                     // if i can just write without hitting buffer.length, do it | ||||
|                     if (WritePosition + count < BufferSize) | ||||
|                     { | ||||
|                         Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, count); | ||||
|                         WritePosition += count; | ||||
|                         //Console.WriteLine($"Wrote only normally {count}[{WritePosition - count} to {WritePosition}]"); | ||||
|                         return; | ||||
|                     } | ||||
|                     // otherwise, i have to write to the end, then write the rest from the start | ||||
|  | ||||
|                     var wroteNormaly = BufferSize - WritePosition; | ||||
|                     Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly); | ||||
|  | ||||
|                     //Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]"); | ||||
|  | ||||
|                     var wroteFromStart = count - wroteNormaly; | ||||
|                     Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart); | ||||
|  | ||||
|                     //Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}"); | ||||
|  | ||||
|                     WritePosition = wroteFromStart; | ||||
|                 } | ||||
|                 // otherwise, i have to write to the end, then write the rest from the start | ||||
|  | ||||
|                 var wroteNormaly = BufferSize - WritePosition; | ||||
|                 Buffer.BlockCopy(buffer, 0, ringBuffer, WritePosition, wroteNormaly); | ||||
|  | ||||
|                 //Console.WriteLine($"Wrote normally {wroteNormaly}[{WritePosition} to {BufferSize}]"); | ||||
|  | ||||
|                 var wroteFromStart = count - wroteNormaly; | ||||
|                 Buffer.BlockCopy(buffer, wroteNormaly, ringBuffer, 0, wroteFromStart); | ||||
|  | ||||
|                 //Console.WriteLine($"and from start {wroteFromStart} [0 to {wroteFromStart}"); | ||||
|  | ||||
|                 WritePosition = wroteFromStart; | ||||
|             } | ||||
|                 finally { readWriteLock.Release(); } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -155,7 +155,7 @@ namespace NadekoBot.Modules.Music.Classes | ||||
|             { | ||||
|                 //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); | ||||
|                 byte[] buffer = new byte[blockSize]; | ||||
|                 var read = songBuffer.Read(buffer, blockSize); | ||||
|                 var read = await songBuffer.ReadAsync(buffer, blockSize).ConfigureAwait(false); | ||||
|                 unchecked | ||||
|                 { | ||||
|                     bytesSent += (ulong)read; | ||||
|   | ||||
| @@ -689,7 +689,7 @@ namespace NadekoBot.Modules.Permissions | ||||
|                             if (!e.Message.MentionedUsers.Any()) return; | ||||
|                             var usr = e.Message.MentionedUsers.First(); | ||||
|                             NadekoBot.Config.UserBlacklist.Add(usr.Id); | ||||
|                             ConfigHandler.SaveConfig(); | ||||
|                             await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                             await e.Channel.SendMessage($"`Sucessfully blacklisted user {usr.Name}`").ConfigureAwait(false); | ||||
|                         }).ConfigureAwait(false); | ||||
|                     }); | ||||
| @@ -707,7 +707,7 @@ namespace NadekoBot.Modules.Permissions | ||||
|                            if (NadekoBot.Config.UserBlacklist.Contains(usr.Id)) | ||||
|                            { | ||||
|                                NadekoBot.Config.UserBlacklist.Remove(usr.Id); | ||||
|                                ConfigHandler.SaveConfig(); | ||||
|                                await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                                await e.Channel.SendMessage($"`Sucessfully unblacklisted user {usr.Name}`").ConfigureAwait(false); | ||||
|                            } | ||||
|                            else | ||||
| @@ -727,7 +727,7 @@ namespace NadekoBot.Modules.Permissions | ||||
|                             if (!e.Message.MentionedChannels.Any()) return; | ||||
|                             var ch = e.Message.MentionedChannels.First(); | ||||
|                             NadekoBot.Config.UserBlacklist.Add(ch.Id); | ||||
|                             ConfigHandler.SaveConfig(); | ||||
|                             await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                             await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false); | ||||
|                         }).ConfigureAwait(false); | ||||
|                     }); | ||||
| @@ -742,7 +742,7 @@ namespace NadekoBot.Modules.Permissions | ||||
|                             if (!e.Message.MentionedChannels.Any()) return; | ||||
|                             var ch = e.Message.MentionedChannels.First(); | ||||
|                             NadekoBot.Config.UserBlacklist.Remove(ch.Id); | ||||
|                             ConfigHandler.SaveConfig(); | ||||
|                             await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                             await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false); | ||||
|                         }).ConfigureAwait(false); | ||||
|                     }); | ||||
| @@ -767,7 +767,7 @@ namespace NadekoBot.Modules.Permissions | ||||
|                             } | ||||
|                             var serverId = server.Id; | ||||
|                             NadekoBot.Config.ServerBlacklist.Add(serverId); | ||||
|                             ConfigHandler.SaveConfig(); | ||||
|                             await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                             //cleanup trivias and typeracing | ||||
|                             Modules.Games.Commands.Trivia.TriviaGame trivia; | ||||
|                             TriviaCommands.RunningTrivias.TryRemove(serverId, out trivia); | ||||
|   | ||||
| @@ -30,8 +30,6 @@ namespace NadekoBot.Modules.Searches.Commands | ||||
|         } | ||||
|  | ||||
|         private static Dictionary<string, CachedChampion> CachedChampionImages = new Dictionary<string, CachedChampion>(); | ||||
|         private readonly object cacheLock = new object(); | ||||
|  | ||||
|  | ||||
|         private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer(); | ||||
|         public LoLCommands(DiscordModule module) : base(module) | ||||
| @@ -42,7 +40,6 @@ namespace NadekoBot.Modules.Searches.Commands | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     lock (cacheLock) | ||||
|                         CachedChampionImages = CachedChampionImages | ||||
|                             .Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0)) | ||||
|                             .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); | ||||
| @@ -87,16 +84,14 @@ namespace NadekoBot.Modules.Searches.Commands | ||||
|                           var resolvedRole = role; | ||||
|                           var name = e.GetArg("champ").Replace(" ", "").ToLower(); | ||||
|                           CachedChampion champ = null; | ||||
|                           lock (cacheLock) | ||||
|                           { | ||||
|                               CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); | ||||
|                           } | ||||
|                           if (champ != null) | ||||
|                           { | ||||
|                               champ.ImageStream.Position = 0; | ||||
|                               await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); | ||||
|                               return; | ||||
|                           } | ||||
|  | ||||
|                           if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ)) | ||||
|                               if (champ != null) | ||||
|                               { | ||||
|                                   champ.ImageStream.Position = 0; | ||||
|                                   await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); | ||||
|                                   return; | ||||
|                               } | ||||
|                           var allData = JArray.Parse(await Classes.SearchHelper.GetResponseStringAsync($"http://api.champion.gg/champion/{name}?api_key={NadekoBot.Creds.LOLAPIKey}").ConfigureAwait(false)); | ||||
|                           JToken data = null; | ||||
|                           if (role != null) | ||||
| @@ -121,17 +116,13 @@ namespace NadekoBot.Modules.Searches.Commands | ||||
|                               role = allData[0]["role"].ToString(); | ||||
|                               resolvedRole = ResolvePos(role); | ||||
|                           } | ||||
|                           lock (cacheLock) | ||||
|                           { | ||||
|                               CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ); | ||||
|                           } | ||||
|                           if (champ != null) | ||||
|                           { | ||||
|                               Console.WriteLine("Sending lol image from cache."); | ||||
|                               champ.ImageStream.Position = 0; | ||||
|                               await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); | ||||
|                               return; | ||||
|                           } | ||||
|                           if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ)) | ||||
|                               if (champ != null) | ||||
|                               { | ||||
|                                   champ.ImageStream.Position = 0; | ||||
|                                   await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false); | ||||
|                                   return; | ||||
|                               } | ||||
|                           //name = data["title"].ToString(); | ||||
|                           // get all possible roles, and "select" the shown one | ||||
|                           var roles = new string[allData.Count]; | ||||
|   | ||||
| @@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Searches.Commands | ||||
|                     } | ||||
|                 } | ||||
|                 catch { } | ||||
|                 ConfigHandler.SaveConfig(); | ||||
|                 await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|             }; | ||||
|             checkTimer.Start(); | ||||
|         } | ||||
| @@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Searches.Commands | ||||
|                     } | ||||
|  | ||||
|                     config.ObservingStreams.Remove(toRemove); | ||||
|                     ConfigHandler.SaveConfig(); | ||||
|                     await ConfigHandler.SaveConfig().ConfigureAwait(false); | ||||
|                     await e.Channel.SendMessage($":ok: Removed `{toRemove.Username}`'s stream from notifications.").ConfigureAwait(false); | ||||
|                 }); | ||||
|  | ||||
|   | ||||
| @@ -197,7 +197,7 @@ namespace NadekoBot | ||||
|                     return; | ||||
|                 } | ||||
| #if NADEKO_RELEASE | ||||
|                 await Task.Delay(90000).ConfigureAwait(false); | ||||
|                 await Task.Delay(100000).ConfigureAwait(false); | ||||
| #else | ||||
|                 await Task.Delay(1000).ConfigureAwait(false); | ||||
| #endif | ||||
|   | ||||
| @@ -78,13 +78,14 @@ | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> | ||||
|     <DebugSymbols>true</DebugSymbols> | ||||
|     <OutputPath>bin\x64\Debug\</OutputPath> | ||||
|     <OutputPath>bin\Debug\</OutputPath> | ||||
|     <DefineConstants>TRACE;DEBUG</DefineConstants> | ||||
|     <DebugType>full</DebugType> | ||||
|     <PlatformTarget>x64</PlatformTarget> | ||||
|     <ErrorReport>prompt</ErrorReport> | ||||
|     <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> | ||||
|     <Prefer32Bit>true</Prefer32Bit> | ||||
|     <Optimize>false</Optimize> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> | ||||
|     <OutputPath>bin\x64\Release\</OutputPath> | ||||
|   | ||||
| @@ -4,6 +4,8 @@ using Newtonsoft.Json; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Runtime.Serialization; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace NadekoBot.Classes.JSONModels | ||||
| { | ||||
| @@ -187,13 +189,17 @@ Nadeko Support Server: <https://discord.gg/0ehQwTK2RBjAxzEY>"; | ||||
|  | ||||
|     public static class ConfigHandler | ||||
|     { | ||||
|         private static readonly object configLock = new object(); | ||||
|         public static void SaveConfig() | ||||
|         private static readonly SemaphoreSlim configLock = new SemaphoreSlim(1, 1); | ||||
|         public static async Task SaveConfig() | ||||
|         { | ||||
|             lock (configLock) | ||||
|             await configLock.WaitAsync(); | ||||
|             try | ||||
|             { | ||||
|                 File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented)); | ||||
|             } | ||||
|             finally { | ||||
|                 configLock.Release(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static bool IsBlackListed(MessageEventArgs evArgs) => IsUserBlacklisted(evArgs.User.Id) || | ||||
|   | ||||
		Reference in New Issue
	
	Block a user