Move more stuff into namespaces.

This commit is contained in:
UnknownShadow200 2017-05-10 13:22:56 +10:00
parent 77caf24b28
commit bfd4042f84
19 changed files with 340 additions and 325 deletions

View File

@ -1,73 +1,74 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Text;
namespace MCGalaxy.Commands.Chatting {
public sealed class Cmd8Ball : Command {
public override string name { get { return "8ball"; } }
public override string shortcut { get { return ""; } }
public override string type { get { return CommandTypes.Chat; } }
public override bool museumUsable { get { return true; } }
public override LevelPermission defaultRank { get { return LevelPermission.Guest; } }
public Cmd8Ball() { }
static string[] messages = new string[] { "Not likely." , "Very likely." , "Impossible!" ,
"No." , "Yes." , "Definitely!" , "Do some more thinking." };
DateTime nextUse;
static TimeSpan delay = TimeSpan.FromSeconds(2);
public override void Use(Player p, string message) {
if (Player.IsSuper(p)) { MessageInGameOnly(p); return; }
if (!MessageCmd.CanSpeak(p, name)) return;
if (message == "") { Help(p); return; }
TimeSpan delta = nextUse - DateTime.UtcNow;
if (delta.TotalSeconds > 0) {
Player.Message(p, "The 8-ball is still recharging, wait another {0} seconds.",
(int)Math.Ceiling(delta.TotalSeconds));
return;
}
nextUse = DateTime.UtcNow.AddSeconds(10 + 2);
StringBuilder builder = new StringBuilder(message.Length);
foreach (char c in message) {
if (Char.IsLetterOrDigit(c)) builder.Append(c);
}
string final = builder.ToString();
Chat.MessageWhere("{0} %Sasked the &b8-Ball: &f{1}", Sees8Ball, p.ColoredName, message);
Server.MainScheduler.QueueOnce(EightBallCallback, final, delay);
}
static void EightBallCallback(SchedulerTask task) {
string final = (string)task.State;
Random random = new Random(final.ToLower().GetHashCode());
Chat.MessageWhere("The &b8-Ball %Ssays: &f{0}", Sees8Ball, messages[random.Next(messages.Length)]);
}
static bool Sees8Ball(Player p) {
return !p.ignoreAll && !p.ignore8ball && p.level.worldChat && p.Chatroom == null;
}
public override void Help(Player p) {
Player.Message(p, "%T/8ball [yes or no question]");
Player.Message(p, "%HGet an answer from the all-knowing 8-Ball!");
}
}
}
using System.Text;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Chatting {
public sealed class Cmd8Ball : Command {
public override string name { get { return "8ball"; } }
public override string shortcut { get { return ""; } }
public override string type { get { return CommandTypes.Chat; } }
public override bool museumUsable { get { return true; } }
public override LevelPermission defaultRank { get { return LevelPermission.Guest; } }
public Cmd8Ball() { }
static string[] messages = new string[] { "Not likely." , "Very likely." , "Impossible!" ,
"No." , "Yes." , "Definitely!" , "Do some more thinking." };
DateTime nextUse;
static TimeSpan delay = TimeSpan.FromSeconds(2);
public override void Use(Player p, string message) {
if (Player.IsSuper(p)) { MessageInGameOnly(p); return; }
if (!MessageCmd.CanSpeak(p, name)) return;
if (message == "") { Help(p); return; }
TimeSpan delta = nextUse - DateTime.UtcNow;
if (delta.TotalSeconds > 0) {
Player.Message(p, "The 8-ball is still recharging, wait another {0} seconds.",
(int)Math.Ceiling(delta.TotalSeconds));
return;
}
nextUse = DateTime.UtcNow.AddSeconds(10 + 2);
StringBuilder builder = new StringBuilder(message.Length);
foreach (char c in message) {
if (Char.IsLetterOrDigit(c)) builder.Append(c);
}
string final = builder.ToString();
Chat.MessageWhere("{0} %Sasked the &b8-Ball: &f{1}", Sees8Ball, p.ColoredName, message);
Server.MainScheduler.QueueOnce(EightBallCallback, final, delay);
}
static void EightBallCallback(SchedulerTask task) {
string final = (string)task.State;
Random random = new Random(final.ToLower().GetHashCode());
Chat.MessageWhere("The &b8-Ball %Ssays: &f{0}", Sees8Ball, messages[random.Next(messages.Length)]);
}
static bool Sees8Ball(Player p) {
return !p.ignoreAll && !p.ignore8ball && p.level.worldChat && p.Chatroom == null;
}
public override void Help(Player p) {
Player.Message(p, "%T/8ball [yes or no question]");
Player.Message(p, "%HGet an answer from the all-knowing 8-Ball!");
}
}
}

View File

@ -16,6 +16,7 @@
permissions and limitations under the Licenses.
*/
using System;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Chatting {
public sealed class CmdVote : Command {

View File

@ -20,6 +20,7 @@
using System;
using System.IO;
using System.Threading;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Maintenance {
public sealed class CmdShutdown : Command {

View File

@ -17,6 +17,7 @@
*/
using System;
using MCGalaxy.Commands.Chatting;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Moderation {
public sealed class CmdVoteKick : Command {

View File

@ -16,6 +16,7 @@
permissions and limitations under the Licenses.
*/
using System;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.World {
public sealed class CmdPause : Command {

View File

@ -20,6 +20,7 @@
*/
using System;
using MCGalaxy.Commands.Moderation;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Misc {

View File

@ -16,6 +16,7 @@
permissions and limitations under the Licenses.
*/
using System;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Misc {
public sealed class CmdTimer : Command {

View File

@ -19,6 +19,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using MCGalaxy.Events;
using MCGalaxy.Tasks;
namespace MCGalaxy.Core {

View File

@ -17,6 +17,7 @@
*/
using System;
using System.Collections.Generic;
using MCGalaxy.Tasks;
namespace MCGalaxy.Core {

View File

@ -18,9 +18,8 @@
using System;
using System.Data;
using System.IO;
using MCGalaxy.SQL;
namespace MCGalaxy {
namespace MCGalaxy.SQL {
public sealed class TableDumper {
bool gottenRows;

View File

@ -1,82 +1,83 @@
/*
Copyright 2011 MCForge
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using MCGalaxy.Network;
namespace MCGalaxy {
public static class BlockQueue {
public static int time = 100;
public static int blockupdates = 250;
static BufferedBlockSender bulkSender = new BufferedBlockSender();
public static void Loop(SchedulerTask task) {
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
lock (lvl.queueLock)
ProcessLevelBlocks(lvl);
}
bulkSender.level = null;
task.Delay = TimeSpan.FromMilliseconds(time);
}
public static void Addblock(Player p, int index, byte type, byte extType = 0) {
if (index == -1) return;
// Bit packing format
// 32-63: index
// 9-31: session ID
// 8: is ext block or not
// 0-7: raw type
ulong flags = (ulong)index << 32;
flags |= (ulong)p.SessionID << 9;
flags |= (type == Block.custom_block ? 0x100UL : 0x000UL);
flags |= (type == Block.custom_block ? extType : type);
lock (p.level.queueLock)
p.level.blockqueue.Add(flags);
}
static void ProcessLevelBlocks(Level lvl) {
try {
if (lvl.blockqueue.Count == 0) return;
if (!lvl.HasPlayers()) { lvl.blockqueue.Clear(); return; }
bulkSender.level = lvl;
int count = blockupdates;
if (lvl.blockqueue.Count < blockupdates)
count = lvl.blockqueue.Count;
for (int i = 0; i < count; i++) {
ulong flags = lvl.blockqueue[i];
int index = (int)(flags >> 32);
byte block = (flags & 0x100) != 0 ? Block.custom_block : (byte)flags;
byte extBlock = (flags & 0x100) != 0 ? (byte)flags : Block.air;
bulkSender.Add(index, block, extBlock);
}
bulkSender.Send(true);
lvl.blockqueue.RemoveRange(0, count);
} catch (Exception e) {
Server.s.ErrorCase("error:" + e);
Server.s.Log(String.Format("Block cache failed for map: {0}. {1} lost.", lvl.name, lvl.blockqueue.Count));
lvl.blockqueue.Clear();
}
}
}
}
/*
Copyright 2011 MCForge
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using MCGalaxy.Network;
using MCGalaxy.Tasks;
namespace MCGalaxy {
public static class BlockQueue {
public static int time = 100;
public static int blockupdates = 250;
static BufferedBlockSender bulkSender = new BufferedBlockSender();
public static void Loop(SchedulerTask task) {
Level[] loaded = LevelInfo.Loaded.Items;
foreach (Level lvl in loaded) {
lock (lvl.queueLock)
ProcessLevelBlocks(lvl);
}
bulkSender.level = null;
task.Delay = TimeSpan.FromMilliseconds(time);
}
public static void Addblock(Player p, int index, byte type, byte extType = 0) {
if (index == -1) return;
// Bit packing format
// 32-63: index
// 9-31: session ID
// 8: is ext block or not
// 0-7: raw type
ulong flags = (ulong)index << 32;
flags |= (ulong)p.SessionID << 9;
flags |= (type == Block.custom_block ? 0x100UL : 0x000UL);
flags |= (type == Block.custom_block ? extType : type);
lock (p.level.queueLock)
p.level.blockqueue.Add(flags);
}
static void ProcessLevelBlocks(Level lvl) {
try {
if (lvl.blockqueue.Count == 0) return;
if (!lvl.HasPlayers()) { lvl.blockqueue.Clear(); return; }
bulkSender.level = lvl;
int count = blockupdates;
if (lvl.blockqueue.Count < blockupdates)
count = lvl.blockqueue.Count;
for (int i = 0; i < count; i++) {
ulong flags = lvl.blockqueue[i];
int index = (int)(flags >> 32);
byte block = (flags & 0x100) != 0 ? Block.custom_block : (byte)flags;
byte extBlock = (flags & 0x100) != 0 ? (byte)flags : Block.air;
bulkSender.Add(index, block, extBlock);
}
bulkSender.Send(true);
lvl.blockqueue.RemoveRange(0, count);
} catch (Exception e) {
Server.s.ErrorCase("error:" + e);
Server.s.Log(String.Format("Block cache failed for map: {0}. {1} lost.", lvl.name, lvl.blockqueue.Count));
lvl.blockqueue.Clear();
}
}
}
}

View File

@ -413,6 +413,7 @@
<Compile Include="Database\ParameterisedQuery.cs" />
<Compile Include="Database\PlayerData.cs" />
<Compile Include="Database\Stats\TopStat.cs" />
<Compile Include="Database\TableDumper.cs" />
<Compile Include="Drawing\Brushes\Brush.cs" />
<Compile Include="Drawing\Brushes\CloudyBrush.cs" />
<Compile Include="Drawing\Brushes\PasteBrush.cs" />
@ -613,7 +614,6 @@
<Compile Include="Server\Server.DB.cs" />
<Compile Include="Server\Server.Fields.cs" />
<Compile Include="Server\Server.Init.cs" />
<Compile Include="Server\TableDumper.cs" />
<Compile Include="Server\Tasks\InitTasks.cs" />
<Compile Include="Server\Tasks\ServerTasks.cs" />
<Compile Include="Server\Tasks\UpgradeTasks.cs" />

View File

@ -22,6 +22,7 @@ using MCGalaxy.Events;
using MCGalaxy.Games;
using MCGalaxy.Network;
using MCGalaxy.SQL;
using MCGalaxy.Tasks;
namespace MCGalaxy {
public sealed partial class Player : IDisposable {

View File

@ -23,6 +23,7 @@ using MCGalaxy.Events;
using MCGalaxy.Games;
using MCGalaxy.SQL;
using MCGalaxy.Network;
using MCGalaxy.Tasks;
namespace MCGalaxy {
public class ChatMessage {

View File

@ -1,97 +1,98 @@
/*
Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
namespace MCGalaxy {
internal sealed class SpamChecker {
public SpamChecker(Player p) {
this.p = p;
blockLog = new List<DateTime>(Server.BlockSpamCount);
chatLog = new List<DateTime>(Server.spamcounter);
cmdLog = new List<DateTime>(Server.CmdSpamCount);
}
Player p;
readonly object chatLock = new object(), cmdLock = new object();
readonly List<DateTime> blockLog, chatLog, cmdLog;
public void Clear() {
blockLog.Clear();
lock (chatLock)
chatLog.Clear();
lock (cmdLock)
cmdLog.Clear();
}
public bool CheckBlockSpam() {
if (p.ignoreGrief || !Server.BlockSpamCheck) return false;
if (blockLog.AddSpamEntry(Server.BlockSpamCount, Server.BlockSpamInterval))
return false;
TimeSpan oldestDelta = DateTime.UtcNow - blockLog[0];
Chat.MessageOps(p.ColoredName + " &cwas kicked for suspected griefing.");
Server.s.Log(p.name + " was kicked for block spam (" + blockLog.Count
+ " blocks in " + oldestDelta + " seconds)");
p.Kick("You were kicked by antigrief system. Slow down.");
return true;
}
public bool CheckChatSpam() {
Player.lastMSG = p.name;
if (!Server.checkspam || Player.IsSuper(p)) return false;
lock (chatLock) {
if (chatLog.AddSpamEntry(Server.spamcounter, Server.spamcountreset))
return false;
Command.all.Find("mute").Use(null, p.name);
Chat.MessageGlobal("{0} %Shas been &0muted %Sfor spamming!", p.ColoredName);
Server.MainScheduler.QueueOnce(UnmuteTask, p.name,
TimeSpan.FromSeconds(Server.mutespamtime));
return true;
}
}
public bool CheckCommandSpam() {
if (!Server.CmdSpamCheck || Player.IsSuper(p)) return false;
lock (cmdLock) {
if (cmdLog.AddSpamEntry(Server.CmdSpamCount, Server.CmdSpamInterval))
return false;
Player.Message(p, "You have been blocked from using commands for " +
Server.CmdSpamBlockTime + " seconds due to spamming");
p.cmdUnblocked = DateTime.UtcNow.AddSeconds(Server.CmdSpamBlockTime);
return true;
}
}
static void UnmuteTask(SchedulerTask task) {
string name = (string)task.State;
Player who = PlayerInfo.FindExact(name);
if (who != null) {
if (who.muted) Command.all.Find("mute").Use(null, who.name);
Player.Message(who, "Remember, no &cspamming %Snext time!");
} else {
Server.muted.Remove(name);
Server.muted.Save();
}
}
}
}
/*
Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using MCGalaxy.Tasks;
namespace MCGalaxy {
internal sealed class SpamChecker {
public SpamChecker(Player p) {
this.p = p;
blockLog = new List<DateTime>(Server.BlockSpamCount);
chatLog = new List<DateTime>(Server.spamcounter);
cmdLog = new List<DateTime>(Server.CmdSpamCount);
}
Player p;
readonly object chatLock = new object(), cmdLock = new object();
readonly List<DateTime> blockLog, chatLog, cmdLog;
public void Clear() {
blockLog.Clear();
lock (chatLock)
chatLog.Clear();
lock (cmdLock)
cmdLog.Clear();
}
public bool CheckBlockSpam() {
if (p.ignoreGrief || !Server.BlockSpamCheck) return false;
if (blockLog.AddSpamEntry(Server.BlockSpamCount, Server.BlockSpamInterval))
return false;
TimeSpan oldestDelta = DateTime.UtcNow - blockLog[0];
Chat.MessageOps(p.ColoredName + " &cwas kicked for suspected griefing.");
Server.s.Log(p.name + " was kicked for block spam (" + blockLog.Count
+ " blocks in " + oldestDelta + " seconds)");
p.Kick("You were kicked by antigrief system. Slow down.");
return true;
}
public bool CheckChatSpam() {
Player.lastMSG = p.name;
if (!Server.checkspam || Player.IsSuper(p)) return false;
lock (chatLock) {
if (chatLog.AddSpamEntry(Server.spamcounter, Server.spamcountreset))
return false;
Command.all.Find("mute").Use(null, p.name);
Chat.MessageGlobal("{0} %Shas been &0muted %Sfor spamming!", p.ColoredName);
Server.MainScheduler.QueueOnce(UnmuteTask, p.name,
TimeSpan.FromSeconds(Server.mutespamtime));
return true;
}
}
public bool CheckCommandSpam() {
if (!Server.CmdSpamCheck || Player.IsSuper(p)) return false;
lock (cmdLock) {
if (cmdLog.AddSpamEntry(Server.CmdSpamCount, Server.CmdSpamInterval))
return false;
Player.Message(p, "You have been blocked from using commands for " +
Server.CmdSpamBlockTime + " seconds due to spamming");
p.cmdUnblocked = DateTime.UtcNow.AddSeconds(Server.CmdSpamBlockTime);
return true;
}
}
static void UnmuteTask(SchedulerTask task) {
string name = (string)task.State;
Player who = PlayerInfo.FindExact(name);
if (who != null) {
if (who.muted) Command.all.Find("mute").Use(null, who.name);
Player.Message(who, "Remember, no &cspamming %Snext time!");
} else {
Server.muted.Remove(name);
Server.muted.Save();
}
}
}
}

View File

@ -23,6 +23,7 @@ using System.Net.Sockets;
using System.Threading;
using MCGalaxy.Config;
using MCGalaxy.Games;
using MCGalaxy.Tasks;
namespace MCGalaxy {
public sealed partial class Server {

View File

@ -21,7 +21,7 @@ using System.IO;
using System.Net;
using System.Reflection;
using System.Windows.Forms;
using MCGalaxy;
using MCGalaxy.Tasks;
namespace MCGalaxy {
public static class Updater {

View File

@ -19,7 +19,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
namespace MCGalaxy {
namespace MCGalaxy.Tasks {
public sealed partial class Scheduler {
readonly List<SchedulerTask> tasks = new List<SchedulerTask>();
@ -33,6 +33,7 @@ namespace MCGalaxy {
thread.IsBackground = true;
thread.Start();
}
/// <summary> Queues an action that is asynchronously executed one time, as soon as possible. </summary>
public SchedulerTask QueueOnce(Action callback) {

View File

@ -1,69 +1,70 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
namespace MCGalaxy.Util {
public sealed class ThreadSafeCache {
public static ThreadSafeCache DBCache = new ThreadSafeCache(key => new object());
readonly object locker = new object();
readonly Dictionary<string, object> items = new Dictionary<string, object>();
readonly Dictionary<string, DateTime> access = new Dictionary<string, DateTime>();
readonly Func<string, object> constructor;
public ThreadSafeCache(Func<string, object> constructor) {
this.constructor = constructor;
}
public object Get(string key) {
lock (locker) {
object value;
if (!items.TryGetValue(key, out value)) {
value = constructor(key);
items[key] = value;
}
access[key] = DateTime.UtcNow;
return value;
}
}
public void CleanupTask(SchedulerTask task) {
List<string> free = null;
DateTime now = DateTime.UtcNow;
lock (locker) {
foreach (var kvp in access) {
// Has the cached item last been accessed in 5 minutes?
if ((now - kvp.Value).TotalMinutes <= 5) continue;
if (free == null) free = new List<string>();
free.Add(kvp.Key);
}
if (free == null) return;
foreach (string key in free) {
items.Remove(key);
access.Remove(key);
}
}
}
}
}
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using MCGalaxy.Tasks;
namespace MCGalaxy.Util {
public sealed class ThreadSafeCache {
public static ThreadSafeCache DBCache = new ThreadSafeCache(key => new object());
readonly object locker = new object();
readonly Dictionary<string, object> items = new Dictionary<string, object>();
readonly Dictionary<string, DateTime> access = new Dictionary<string, DateTime>();
readonly Func<string, object> constructor;
public ThreadSafeCache(Func<string, object> constructor) {
this.constructor = constructor;
}
public object Get(string key) {
lock (locker) {
object value;
if (!items.TryGetValue(key, out value)) {
value = constructor(key);
items[key] = value;
}
access[key] = DateTime.UtcNow;
return value;
}
}
public void CleanupTask(SchedulerTask task) {
List<string> free = null;
DateTime now = DateTime.UtcNow;
lock (locker) {
foreach (var kvp in access) {
// Has the cached item last been accessed in 5 minutes?
if ((now - kvp.Value).TotalMinutes <= 5) continue;
if (free == null) free = new List<string>();
free.Add(kvp.Key);
}
if (free == null) return;
foreach (string key in free) {
items.Remove(key);
access.Remove(key);
}
}
}
}
}