MUD modularization work.

This commit is contained in:
Michael 2017-02-11 11:48:26 -05:00
parent f8a37dd101
commit 8e2b00840a
6 changed files with 318 additions and 104 deletions

View file

@ -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
{
/// <summary>
/// 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.
/// </summary>
/// <param name="rName">The header ID of the request this method should handle.</param>
public MudRequestAttribute(string rName)
{
RequestName = rName;
}
public string RequestName { get; private set; }
}
[AttributeUsage(AttributeTargets.Method)]
public class MudResponseAttribute : attribute
{
/// <summary>
/// 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.
/// </summary>
/// <param name="rName">The header ID of the response that this method will handle.</param>
public MudResponseAttribute(string rName)
{
ResponseName = rName;
}
public string ResponseName { get; private set; }
}
}

View file

@ -47,6 +47,7 @@
<Compile Include="ClientSave.cs" />
<Compile Include="Job.cs" />
<Compile Include="Legion.cs" />
<Compile Include="MudAttributes.cs" />
<Compile Include="Objects.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Save.cs" />

View file

@ -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)
{
}
}
/// <summary>
/// Program.
/// </summary>
@ -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<Dictionary<string, object>>(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<Save>(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<Dictionary<string, object>>(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<Dictionary<string, object>>(msg.Contents);
@ -1388,6 +1344,8 @@ The page you requested at was not found on this multi-user domain."
/// </summary>
public static Dictionary<string, string> MUDHackPasswords = new Dictionary<string, string>();
public static MudClientDispatcher ClientDispatcher { get; private set; }
/// <summary>
/// Stop this instance.
/// </summary>
@ -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}] <ClientDispatcher> 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}] <ClientDispatcher> Dispatching to {cGuid}: {msgName}.");
}
else
{
Console.WriteLine($"[{DateTime.Now}] <ClientDispatcher> Client \"{cGuid}\" not found on server. Possibly a connection drop.");
}
}
}
}
// Uncommenting by Michael

View file

@ -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<string, object>;
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<string, object>;
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<string, object>;
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<string, object>;
if (args["guid"] != null && args["text"] != null)
{
Program.ClientDispatcher.DispatchTo("pleasewrite", args["guid"] as string, args["text"]);
}
}
}
}

View file

@ -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<string, object>;
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<string, object>;
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<Save>(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<Save>(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));
}
}
}

View file

@ -60,6 +60,8 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="RemoteTerminal.cs" />
<Compile Include="SaveManager.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />