From 8e2b00840a6a16a6da1eb4891a8364158884f0a8 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 11 Feb 2017 11:48:26 -0500 Subject: [PATCH] MUD modularization work. --- ShiftOS.Objects/MudAttributes.cs | 43 +++++ ShiftOS.Objects/ShiftOS.Objects.csproj | 1 + ShiftOS.Server/Program.cs | 218 +++++++++++++------------ ShiftOS.Server/RemoteTerminal.cs | 70 ++++++++ ShiftOS.Server/SaveManager.cs | 88 ++++++++++ ShiftOS.Server/ShiftOS.Server.csproj | 2 + 6 files changed, 318 insertions(+), 104 deletions(-) create mode 100644 ShiftOS.Objects/MudAttributes.cs create mode 100644 ShiftOS.Server/RemoteTerminal.cs create mode 100644 ShiftOS.Server/SaveManager.cs diff --git a/ShiftOS.Objects/MudAttributes.cs b/ShiftOS.Objects/MudAttributes.cs new file mode 100644 index 0000000..b3b7380 --- /dev/null +++ b/ShiftOS.Objects/MudAttributes.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using attribute = System.Attribute; + +namespace ShiftOS.Objects +{ + [AttributeUsage(AttributeTargets.Method)] + public class MudRequestAttribute : attribute + { + /// + /// This attribute can be used on a static method to make the multi-user domain server software see this method as a MUD request handler. + /// + /// The header ID of the request this method should handle. + public MudRequestAttribute(string rName) + { + RequestName = rName; + } + + public string RequestName { get; private set; } + } + + [AttributeUsage(AttributeTargets.Method)] + public class MudResponseAttribute : attribute + { + /// + /// Clients will look for static methods marked with this attribute and run them first. If no attribute is found with the given header ID, the client may invoke a delegate with the message information. + /// + /// The header ID of the response that this method will handle. + public MudResponseAttribute(string rName) + { + ResponseName = rName; + } + + public string ResponseName { get; private set; } + } + + +} + diff --git a/ShiftOS.Objects/ShiftOS.Objects.csproj b/ShiftOS.Objects/ShiftOS.Objects.csproj index b82a40a..867c540 100644 --- a/ShiftOS.Objects/ShiftOS.Objects.csproj +++ b/ShiftOS.Objects/ShiftOS.Objects.csproj @@ -47,6 +47,7 @@ + diff --git a/ShiftOS.Server/Program.cs b/ShiftOS.Server/Program.cs index 352214d..b06b9d5 100644 --- a/ShiftOS.Server/Program.cs +++ b/ShiftOS.Server/Program.cs @@ -35,10 +35,19 @@ using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.IO.Compression; +using System.Reflection; namespace ShiftOS.Server { + public class MudException : Exception + { + public MudException(string message) : base(message) + { + + } + } + /// /// Program. /// @@ -187,8 +196,8 @@ namespace ShiftOS.Server server.Start(IPAddress.Loopback, 13370); } - - server.OnStopped += (o, a) => + ClientDispatcher = new Server.MudClientDispatcher(server); + server.OnStopped += (o, a) => { Console.WriteLine("Server stopping."); @@ -262,120 +271,67 @@ namespace ShiftOS.Server try { - Console.WriteLine($@"Message received from {msg.GUID}: {msg.Name} + Console.WriteLine($@"[{DateTime.Now}] Message received from {msg.GUID}: {msg.Name}"); -Contents: -{msg.Contents}"); - - if (!string.IsNullOrWhiteSpace(msg.Contents)) - { - try - { - //It's gotta be JSON. - if (msg.Contents.StartsWith("{")) - { - args = JsonConvert.DeserializeObject>(msg.Contents); - } - } - catch - { - //Damnit, we were wrong. - args = null; - } - } - - switch (msg.Name) - { - case "usr_getcp": - - break; - case "usr_takecp": - if (args["username"] != null && args["password"] != null && args["amount"] != null && args["yourusername"] != null) + foreach (var asmFile in Directory.GetFiles(Environment.CurrentDirectory)) + { + if (asmFile.EndsWith(".exe") || asmFile.EndsWith(".dll")) + { + try { - string userName = args["username"] as string; - string passw = args["password"] as string; - int amount = (int)args["amount"]; - - if (Directory.Exists("saves")) + var asm = Assembly.LoadFile(asmFile); + foreach (var type in asm.GetTypes()) { - foreach (var saveFile in Directory.GetFiles("saves")) + foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static)) { - var saveFileContents = JsonConvert.DeserializeObject(ReadEncFile(saveFile)); - if (saveFileContents.Username == userName && saveFileContents.Password == passw) + foreach (var attrib in method.GetCustomAttributes(false)) { - saveFileContents.Codepoints += amount; - WriteEncFile(saveFile, JsonConvert.SerializeObject(saveFileContents, Formatting.Indented)); - server.DispatchAll(new NetObject("stop_being_drunk_michael", new ServerMessage + if (attrib is MudRequestAttribute) { - Name = "update_your_cp", - GUID = "server", - Contents = $@"{{ - username: ""{userName}"", - amount: -{amount} -}}" - })); - server.DispatchTo(new Guid(msg.GUID), new NetObject("argh", new ServerMessage - { - Name = "update_your_cp", - GUID = "server", - Contents = $@"{{ - username: ""{args["yourusername"]}"", - amount: {amount} -}}" - })); - return; + if ((attrib as MudRequestAttribute).RequestName == msg.Name) + { + try + { + object contents = msg.Contents; + try + { + contents = JsonConvert.DeserializeObject>(msg.Contents); + } + catch + { + + } + + method?.Invoke(null, new[] { msg.GUID, contents }); + } + catch (MudException mEx) + { + ClientDispatcher.DispatchTo("Error", msg.GUID, mEx); + } + catch + { + Console.WriteLine($@"[{DateTime.Now}] {method.Name}: Missing guid and content parameters, request handler NOT RAN."); + } + return; + } + } } } } } - server.DispatchTo(new Guid(msg.GUID), new NetObject("no", new ServerMessage + catch (Exception ex) { - Name = "user_cp_not_found", - GUID = "Server", - })); - break; - case "trm_handshake_accept": - if(args["guid"] != null && args["target"] != null) - { - server.DispatchTo(new Guid(args["target"] as string), new NetObject("hold_it", new ServerMessage - { - Name = "trm_handshake_guid", - GUID = args["guid"] as string - })); + Console.WriteLine($"[{DateTime.Now}] Exception while handling request {msg.Name}: {ex}"); + return; } - break; - case "trm_handshake_request": - if(args["username"] != null && args["password"] != null && args["sysname"] != null) - { - server.DispatchAll(new NetObject("hold_my_hand", new ServerMessage - { - Name = "handshake_from", - GUID = msg.GUID, - Contents = JsonConvert.SerializeObject(args) - })); - } - break; - case "trm_handshake_stop": - if(args["guid"] != null) - { - server.DispatchTo(new Guid(args["guid"] as string), new NetObject("trm_handshake_stop", new ServerMessage - { - Name = "trm_handshake_stop", - GUID = msg.GUID - })); - } - break; - case "write": - if(args["guid"] != null && args["text"] != null) - { - server.DispatchTo(new Guid(args["guid"] as string), new NetObject("pleaseWrite", new ServerMessage - { - Name = "pleasewrite", - GUID = "server", - Contents = args["text"] as string - })); - } - break; + } + } + + ClientDispatcher.DispatchTo("Error", msg.GUID, new MudRequestHandlerNotFoundException()); + + + switch (msg.Name) + { case "trm_invcmd": Console.WriteLine("Before arg check"); args = JsonConvert.DeserializeObject>(msg.Contents); @@ -1388,6 +1344,8 @@ The page you requested at was not found on this multi-user domain." /// public static Dictionary MUDHackPasswords = new Dictionary(); + public static MudClientDispatcher ClientDispatcher { get; private set; } + /// /// Stop this instance. /// @@ -1495,7 +1453,59 @@ The page you requested at was not found on this multi-user domain." } } + public class MudRequestHandlerNotFoundException : MudException + { + public MudRequestHandlerNotFoundException() : base("The request handler for this request couldn't be found.") + { + } + } + + public class MudClientDispatcher + { + public NetObjectServer Server { get; private set; } + + public MudClientDispatcher(NetObjectServer srv) + { + Server = srv; + DispatcherGUID = Guid.NewGuid().ToString(); + Console.WriteLine($"[{DateTime.Now}] Dispatcher started."); + } + + public string DispatcherGUID { get; private set; } + + public void Broadcast(string msgHeader, object contents) + { + Server.DispatchAll(new NetObject + { + Name = "broadcast", + Object = new ServerMessage + { + Name = msgHeader, + GUID = DispatcherGUID, + Contents = JsonConvert.SerializeObject(contents) + } + }); + } + + public void DispatchTo(string msgName, string cGuid, object mContents) + { + if(Server.Clients.Contains(new Guid(cGuid))) + { + Server.DispatchTo(new Guid(cGuid), new NetObject("dispatch", new ServerMessage + { + Name = msgName, + GUID = DispatcherGUID, + Contents = JsonConvert.SerializeObject(mContents) + })); + Console.WriteLine($"[{DateTime.Now}] Dispatching to {cGuid}: {msgName}."); + } + else + { + Console.WriteLine($"[{DateTime.Now}] Client \"{cGuid}\" not found on server. Possibly a connection drop."); + } + } + } } // Uncommenting by Michael \ No newline at end of file diff --git a/ShiftOS.Server/RemoteTerminal.cs b/ShiftOS.Server/RemoteTerminal.cs new file mode 100644 index 0000000..d28cf8a --- /dev/null +++ b/ShiftOS.Server/RemoteTerminal.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftOS.Objects; +using Newtonsoft.Json; +using NetSockets; + +namespace ShiftOS.Server +{ + public static class RemoteTerminal + { + [MudRequest("trm_handshake_accept")] + public static void AcceptHandshake(string guid, object contents) + { + var args = contents as Dictionary; + if (args["guid"] != null && args["target"] != null) + { + + Program.ClientDispatcher.Server.DispatchTo(new Guid(args["target"] as string), new NetObject("hold_it", new ServerMessage + { + Name = "trm_handshake_guid", + GUID = args["guid"] as string + })); + } + } + + [MudRequest("trm_handshake_request")] + public static void RequestHandshake(string guid, object contents) + { + var args = contents as Dictionary; + if (args["username"] != null && args["password"] != null && args["sysname"] != null) + { + Program.ClientDispatcher.Server.DispatchAll(new NetObject("hold_my_hand", new ServerMessage + { + Name = "handshake_from", + GUID = guid, + Contents = JsonConvert.SerializeObject(args) + })); + } + } + + [MudRequest("trm_handshake_stop")] + public static void StopSession(string guid, object contents) + { + var args = contents as Dictionary; + if (args["guid"] != null) + { + Program.ClientDispatcher.Server.DispatchTo(new Guid(args["guid"] as string), new NetObject("trm_handshake_stop", new ServerMessage + { + Name = "trm_handshake_stop", + GUID = guid + })); + } + + } + + [MudRequest("write")] + public static void WriteText(string guid, object contents) + { + var args = contents as Dictionary; + if (args["guid"] != null && args["text"] != null) + { + Program.ClientDispatcher.DispatchTo("pleasewrite", args["guid"] as string, args["text"]); + } + + } + } +} diff --git a/ShiftOS.Server/SaveManager.cs b/ShiftOS.Server/SaveManager.cs new file mode 100644 index 0000000..4bca36d --- /dev/null +++ b/ShiftOS.Server/SaveManager.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ShiftOS.Objects; +using System.IO; +using Newtonsoft.Json; + +namespace ShiftOS.Server +{ + public static class SaveManager + { + [MudRequest("usr_getcp")] + public static void GetCodepoints(string guid, object contents) + { + var args = contents as Dictionary; + if (!args.ContainsKey("username")) + throw new MudException("No 'username' argument supplied."); + + foreach(var savefile in Directory.GetFiles("saves")) + { + var save = ReadSave(savefile); + if(save.Username == args["username"] as string) + { + Program.ClientDispatcher.DispatchTo("usr_codepoints", guid, save.Codepoints); + return; + } + } + + throw new MudException("User " + args["username"] as string + " not found on this multi-user domain."); + + } + + [MudRequest("usr_takecp")] + public static void TakeCodepoints(string guid, object contents) + { + var args = contents as Dictionary; + if (args["username"] != null && args["password"] != null && args["amount"] != null && args["yourusername"] != null) + { + string userName = args["username"] as string; + string passw = args["password"] as string; + int cpAmount = (int)args["amount"]; + + if (Directory.Exists("saves")) + { + foreach (var saveFile in Directory.GetFiles("saves")) + { + var saveFileContents = JsonConvert.DeserializeObject(ReadEncFile(saveFile)); + if (saveFileContents.Username == userName && saveFileContents.Password == passw) + { + saveFileContents.Codepoints += cpAmount; + WriteEncFile(saveFile, JsonConvert.SerializeObject(saveFileContents, Formatting.Indented)); + Program.ClientDispatcher.Broadcast("update_your_cp", new { + username = userName, + amount = -cpAmount + }); + Program.ClientDispatcher.DispatchTo("update_your_cp", guid, new + { + username = args["yourusername"].ToString(), + amount = cpAmount + }); + return; + } + } + } + } + + } + + private static Save ReadSave(string fPath) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(ReadEncFile(fPath)); + } + + + private static string ReadEncFile(string fPath) + { + return Encryption.Decrypt(File.ReadAllText(fPath)); + } + + private static void WriteEncFile(string fPath, string contents) + { + File.WriteAllText(fPath, Encryption.Encrypt(contents)); + } + + } +} diff --git a/ShiftOS.Server/ShiftOS.Server.csproj b/ShiftOS.Server/ShiftOS.Server.csproj index d68aa3e..8654d82 100644 --- a/ShiftOS.Server/ShiftOS.Server.csproj +++ b/ShiftOS.Server/ShiftOS.Server.csproj @@ -60,6 +60,8 @@ True Resources.resx + +