Skip to content

Commit

Permalink
Faster Serialization. Remove Newtonsoft.
Browse files Browse the repository at this point in the history
  • Loading branch information
HarryCordewener committed Jan 2, 2024
1 parent b39a797 commit 337845c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 65 deletions.
4 changes: 2 additions & 2 deletions TelnetNegotiationCore.TestClient/MockClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public MockClient(string ip, int port, ILogger? logger = null)
{
Console.OutputEncoding = Encoding.UTF8;
_Logger = logger ?? Log.Logger.ForContext<MockClient>();
IPAddress localAddr = IPAddress.Parse(ip);
client = new TcpClient(localAddr.ToString(), port);
IPAddress localAddress = IPAddress.Parse(ip);
client = new TcpClient(localAddress.ToString(), port);
Handle(client);
}

Expand Down
22 changes: 11 additions & 11 deletions TelnetNegotiationCore/Interpreters/TelnetCharsetInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public partial class TelnetInterpreter
/// </summary>
private int _acceptedCharsetByteIndex = 0;

private bool charsetoffered = false;
private bool charsetOffered = false;

private Func<IEnumerable<EncodingInfo>, IOrderedEnumerable<Encoding>> _charsetorder = (x) => x.Select(y => y.GetEncoding()).OrderBy(z => z.EncodingName);
private Func<IEnumerable<EncodingInfo>, IOrderedEnumerable<Encoding>> _charsetOrder = (x) => x.Select(y => y.GetEncoding()).OrderBy(z => z.EncodingName);

public Lazy<byte[]> SupportedCharacterSets { get; }

Expand All @@ -53,7 +53,7 @@ public IEnumerable<Encoding> CharsetOrder
init
{
var ordered = value.Reverse().ToList();
_charsetorder = (x) => x.Select(x => x.GetEncoding()).OrderByDescending(z => ordered.IndexOf(z));
_charsetOrder = (x) => x.Select(x => x.GetEncoding()).OrderByDescending(z => ordered.IndexOf(z));
}
}

Expand Down Expand Up @@ -194,7 +194,7 @@ private void CaptureAcceptedCharset(OneOf<byte, Trigger> b)
/// <param name="_">Ignored</param>
private async Task CompleteCharsetAsync(StateMachine<State, Trigger>.Transition _)
{
if (charsetoffered && Mode == TelnetMode.Server)
if (charsetOffered && Mode == TelnetMode.Server)
{
await CallbackNegotiation(new byte[] { (byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.CHARSET, (byte)Trigger.REJECTED, (byte)Trigger.IAC, (byte)Trigger.SE });
return;
Expand All @@ -207,7 +207,7 @@ private async Task CompleteCharsetAsync(StateMachine<State, Trigger>.Transition

var encodingDict = Encoding.GetEncodings().ToDictionary(x => x.GetEncoding().WebName);
var offeredEncodingInfo = charsetsOffered.Select(x => { try { return encodingDict[Encoding.GetEncoding(x).WebName]; } catch { return null; } }).Where(x => x != null);
var preferredEncoding = _charsetorder(offeredEncodingInfo);
var preferredEncoding = _charsetOrder(offeredEncodingInfo);
var chosenEncoding = preferredEncoding.FirstOrDefault();

if (chosenEncoding == null)
Expand Down Expand Up @@ -246,7 +246,7 @@ private async Task CompleteAcceptedCharsetAsync(StateMachine<State, Trigger>.Tra
await CallbackNegotiation(new byte[] { (byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.CHARSET, (byte)Trigger.REJECTED, (byte)Trigger.IAC, (byte)Trigger.SE });
}
_Logger.Information("Connection: Accepted Charset Negotiation for: {charset}", CurrentEncoding.WebName);
charsetoffered = false;
charsetOffered = false;
}

/// <summary>
Expand All @@ -256,7 +256,7 @@ private async Task OnWillingCharsetAsync(StateMachine<State, Trigger>.Transition
{
_Logger.Debug("Connection: {connectionStatus}", "Request charset negotiation from Client");
await CallbackNegotiation(new byte[] { (byte)Trigger.IAC, (byte)Trigger.DO, (byte)Trigger.CHARSET });
charsetoffered = false;
charsetOffered = false;
}

/// <summary>
Expand All @@ -273,9 +273,9 @@ private async Task WillingCharsetAsync()
/// </summary>
private async Task OnDoCharsetAsync(StateMachine<State, Trigger>.Transition _)
{
_Logger.Debug("Charsets String: {charsetlist}", ";" + string.Join(";", _charsetorder(Encoding.GetEncodings()).Select(x => x.WebName)));
_Logger.Debug("Charsets String: {charsetlist}", ";" + string.Join(";", _charsetOrder(Encoding.GetEncodings()).Select(x => x.WebName)));
await CallbackNegotiation(SupportedCharacterSets.Value);
charsetoffered = true;
charsetOffered = true;
}

/// <summary>
Expand All @@ -286,8 +286,8 @@ private byte[] CharacterSets()
{
byte[] pre = new byte[] { (byte)Trigger.IAC, (byte)Trigger.SB, (byte)Trigger.CHARSET, (byte)Trigger.REQUEST };
byte[] post = new byte[] { (byte)Trigger.IAC, (byte)Trigger.SE };
byte[] defaultcharsets = ascii.GetBytes($";{string.Join(";", _charsetorder(Encoding.GetEncodings()).Select(x => x.WebName))}");
return pre.Concat(defaultcharsets).Concat(post).ToArray();
byte[] defaultCharsets = ascii.GetBytes($";{string.Join(";", _charsetOrder(Encoding.GetEncodings()).Select(x => x.WebName))}");
return pre.Concat(defaultCharsets).Concat(post).ToArray();
}
}
}
6 changes: 4 additions & 2 deletions TelnetNegotiationCore/Interpreters/TelnetMSSPInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using MoreLinq;
using Newtonsoft.Json;
using OneOf;
using Stateless;
using TelnetNegotiationCore.Models;
Expand All @@ -27,6 +27,8 @@ public partial class TelnetInterpreter
.Where(x => x.Attribute != null)
.ToImmutableDictionary(x => x.Attribute.Name.ToUpper());

private JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() { IncludeFields = true };

/// <summary>
/// Mud Server Status Protocol will provide information to the requestee about the server's contents.
/// </summary>
Expand Down Expand Up @@ -144,7 +146,7 @@ private async Task ReadMSSPValues()
StoreClientMSSPDetails(group.Key, group.Select(x => CurrentEncoding.GetString(x.Second.ToArray())));
}

_Logger.Debug("Registering MSSP: {$msspConfig}", JsonConvert.SerializeObject(_msspConfig()));
_Logger.Debug("Registering MSSP: {@msspConfig}", JsonSerializer.Serialize<MSSPConfig>(_msspConfig(), _serializerOptions));

await Task.CompletedTask;
}
Expand Down
96 changes: 47 additions & 49 deletions TelnetNegotiationCore/Models/MSSPConfig.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;

Expand Down Expand Up @@ -40,75 +38,75 @@ public OfficialAttribute(bool official)
public class MSSPConfig
{
/// <summary>NAME: Name of the MUD.</summary>
[Name("NAME"), Official(true), JsonProperty]
[Name("NAME"), Official(true)]
public string Name;

/// <summary>PLAYERS: Current number of logged in players.</summary>
[Name("PLAYERS"), Official(true), JsonProperty]
[Name("PLAYERS"), Official(true)]
public int Players;

/// <summary>UPTIME: Unix time value of the startup time of the MUD.</summary>
[Name("UPTIME"), Official(true), JsonProperty]
[Name("UPTIME"), Official(true)]
public int Uptime;

/// <summary>CODEBASE: Name of the codebase, eg Merc 2.1. You can report multiple codebases using the array format, make sure to report the current codebase last.</summary>
[Name("CODEBASE"), Official(true), JsonProperty]
[Name("CODEBASE"), Official(true)]
public IEnumerable<string> Codebase;

/// <summary>CONTACT: Email address for contacting the MUD.</summary>
[Name("CONTACT"), Official(true), JsonProperty]
[Name("CONTACT"), Official(true)]
public string Contact;

/// <summary>CRAWL DELAY: Preferred minimum number of hours between crawls. Send -1 to use the crawler's default.</summary>
[Name("CRAWL DELAY"), Official(true), JsonProperty]
[Name("CRAWL DELAY"), Official(true)]
public int Crawl_Delay;

/// <summary>CREATED: Year the MUD was created.</summary>
[Name("CREATED"), Official(true), JsonProperty]
[Name("CREATED"), Official(true)]
public string Created;

/// <summary>HOSTNAME: Current or new hostname.</summary>
[Name("HOSTNAME"), Official(true), JsonProperty]
[Name("HOSTNAME"), Official(true)]
public string Hostname;

/// <summary>ICON: URL to a square image in bmp, png, jpg, or gif format. The icon should be equal or larger than 64x64 pixels, with a filesize no larger than 256KB.</summary>
[Name("ICON"), Official(true), JsonProperty]
[Name("ICON"), Official(true)]
public string Icon;

/// <summary>IP: Current or new IP address.</summary>
[Name("IP"), Official(true), JsonProperty]
[Name("IP"), Official(true)]
public string IP;

/// <summary>IPV6: Current or new IPv6 address.</summary>
[Name("IPV6"), Official(true), JsonProperty]
[Name("IPV6"), Official(true)]
public string IPV6;

/// <summary>LANGUAGE: English name of the language used, eg German or English</summary>
[Name("LANGUAGE"), Official(true), JsonProperty]
[Name("LANGUAGE"), Official(true)]
public string Language;

/// <summary>LOCATION: English short name of the country where the server is located, using ISO 3166.</summary>
[Name("LOCATION"), Official(true), JsonProperty]
[Name("LOCATION"), Official(true)]
public string Location;

/// <summary>MINIMUM AGE: Current minimum age requirement, omit if not applicable.</summary>
[Name("MINIMUM AGE"), Official(true), JsonProperty]
[Name("MINIMUM AGE"), Official(true)]
public string Minimum_Age;

/// <summary>PORT: Current or new port number. Can be used multiple times, most important port last.</summary>
[Name("PORT"), Official(true), JsonProperty]
[Name("PORT"), Official(true)]
public int Port;

/// <summary>REFERRAL: A list of other MSSP enabled MUDs for the crawler to check using the host port format and array notation. Adding referrals is important to make MSSP decentralized. Make sure to separate the host and port with a space rather than : because IPv6 addresses contain colons.</summary>
[Name("REFERRAL"), Official(true), JsonProperty]
[Name("REFERRAL"), Official(true)]
public IEnumerable<string> Referral;

/// <summary>The port number for a SSL (Secure Socket Layer) encrypted connection.</summary>
[Name("SSL"), Official(true), JsonProperty]
[Name("SSL"), Official(true)]
public string Ssl;

/// <summary>WEBSITE: URL to MUD website, this should include the http:// or https:// prefix.</summary>
[Name("WEBSITE"), Official(true), JsonProperty]
[Name("WEBSITE"), Official(true)]
public string Website;

/// <summary>FAMILY: AberMUD, CoffeeMUD, DikuMUD, Evennia, LPMud, MajorMUD, MOO, Mordor, SocketMud, TinyMUD, TinyMUCK, TinyMUSH, Custom.
Expand All @@ -117,28 +115,28 @@ public class MSSPConfig
/// You can report multiple generic codebases using the array format, make sure to report the most distant codebase (aka the family) last.
///
/// Check the MUD family tree for naming and capitalization.</summary>
[Name("FAMILY"), Official(true), JsonProperty]
[Name("FAMILY"), Official(true)]
public IEnumerable<string> Family;

/// <summary>GENRE: Adult, Fantasy, Historical, Horror, Modern, Mystery, None, Romance, Science Fiction, Spiritual</summary>
[Name("GENRE"), Official(true), JsonProperty]
[Name("GENRE"), Official(true)]
public string Genre;

/// <summary>GAMEPLAY: Adventure, Educational, Hack and Slash, None, Player versus Player, Player versus Environment, Questing, Roleplaying, Simulation, Social, Strategy</summary>
[Name("GAMEPLAY"), Official(true), JsonProperty]
[Name("GAMEPLAY"), Official(true)]
public IEnumerable<string> Gameplay;


/// <summary>STATUS: Alpha, Closed Beta, Open Beta, Live</summary>
[Name("STATUS"), Official(true), JsonProperty]
[Name("STATUS"), Official(true)]
public string Status;

/// <summary>GAMESYSTEM: D&D, d20 System, World of Darkness, Etc. Use Custom if using a custom game system. Use None if not available.</summary>
[Name("GAMESYSTEM"), Official(true), JsonProperty]
[Name("GAMESYSTEM"), Official(true)]
public string Gamesystem;

/// <summary>INTERMUD: AberChat, I3, IMC2, MudNet, Etc. Can be used multiple times if you support several protocols, most important protocol last. Leave empty or omit if no Intermud protocol is supported.</summary>
[Name("INTERMUD"), Official(true), JsonProperty]
[Name("INTERMUD"), Official(true)]
public IEnumerable<string> Intermud;

/// <summary>SUBGENRE: Alternate History, Anime, Cyberpunk, Detective, Discworld, Dragonlance, Christian Fiction, Classical Fantasy,
Expand All @@ -147,95 +145,95 @@ public class MSSPConfig
/// Mythology, Pulp, Star Wars, Steampunk, Suspense, Time Travel, Weird Fiction, World War II, Urban Fantasy, Etc.
///
/// Use None if not applicable.</summary>
[Name("SUBGENRE"), Official(true), JsonProperty]
[Name("SUBGENRE"), Official(true)]
public string Subgenre;

/// <summary>AREAS: Current number of areas.</summary>
[Name("AREAS"), Official(true), JsonProperty]
[Name("AREAS"), Official(true)]
public int Areas;

/// <summary>HELPFILES: Current number of help files.</summary>
[Name("HELPFILES"), Official(true), JsonProperty]
[Name("HELPFILES"), Official(true)]
public int Helpfiles;

/// <summary>MOBILES: Current number of unique mobiles.</summary>
[Name("MOBILES"), Official(true), JsonProperty]
[Name("MOBILES"), Official(true)]
public int Mobiles;

/// <summary>OBJECTS: Current number of unique objects.</summary>
[Name("OBJECTS"), Official(true), JsonProperty]
[Name("OBJECTS"), Official(true)]
public int Objects;

/// <summary>ROOMS: Current number of unique rooms, use 0 if roomless.</summary>
[Name("ROOMS"), Official(true), JsonProperty]
[Name("ROOMS"), Official(true)]
public int Rooms;

/// <summary>CLASSES: Number of player classes, use 0 if classless.</summary>
[Name("CLASSES"), Official(true), JsonProperty]
[Name("CLASSES"), Official(true)]
public int Classes;

/// <summary>LEVELS: Number of player levels, use 0 if level-less.</summary>
[Name("LEVELS"), Official(true), JsonProperty]
[Name("LEVELS"), Official(true)]
public int Levels;

/// <summary>RACES: Number of player races, use 0 if raceless.</summary>
[Name("RACES"), Official(true), JsonProperty]
[Name("RACES"), Official(true)]
public int Races;

/// <summary>SKILLS: Number of player skills, use 0 if skill-less.</summary>
[Name("SKILLS"), Official(true), JsonProperty]
[Name("SKILLS"), Official(true)]
public int Skills;

/// <summary>ANSI: Supports ANSI colors ? 1 or 0</summary>
[Name("ANSI"), Official(true), JsonProperty]
[Name("ANSI"), Official(true)]
public bool Ansi;

/// <summary>PUEBLO: Supports Pueblo ? 1 or 0</summary>
[Name("PUEBLO"), Official(false), JsonProperty]
[Name("PUEBLO"), Official(false)]
public bool Pueblo;

/// <summary>MSP: Supports MSP ? 1 or 0</summary>
[Name("MSP"), Official(true), JsonProperty]
[Name("MSP"), Official(true)]
public bool MSP;

/// <summary>UTF-8: Supports UTF-8 ? 1 or 0</summary>
[Name("UTF-8"), Official(true), JsonProperty]
[Name("UTF-8"), Official(true)]
public bool UTF_8;

/// <summary>VT100: Supports VT100 interface ? 1 or 0</summary>
[Name("VT100"), Official(true), JsonProperty]
[Name("VT100"), Official(true)]
public bool VT100;

/// <summary>XTERM: 256 COLORS Supports xterm 256 colors ? 1 or 0</summary>
[Name("XTERM 256 COLORS"), Official(true), JsonProperty]
[Name("XTERM 256 COLORS"), Official(true)]
public bool XTerm_256_Colors;

/// <summary>XTERM: TRUE COLORS Supports xterm 24 bit colors ? 1 or 0</summary>
[Name("XTERM TRUE COLORS"), Official(true), JsonProperty]
[Name("XTERM TRUE COLORS"), Official(true)]
public bool XTerm_True_Colors;

/// <summary>PAY: TO PLAY Pay to play ? 1 or 0</summary>
[Name("PAY TO PLAY"), Official(true), JsonProperty]
[Name("PAY TO PLAY"), Official(true)]
public bool Pay_To_Play;

/// <summary>PAY: FOR PERKS Pay for perks ? 1 or 0</summary>
[Name("PAY FOR PERKS"), Official(true), JsonProperty]
[Name("PAY FOR PERKS"), Official(true)]
public bool Pay_For_Perks;

/// <summary>HIRING: BUILDERS Game is hiring builders ? 1 or 0</summary>
[Name("HIRING BUILDERS"), Official(true), JsonProperty]
[Name("HIRING BUILDERS"), Official(true)]
public bool Hiring_Builders;

/// <summary>HIRING: CODERS Game is hiring coders ? 1 or 0</summary>
[Name("HIRING CODERS"), Official(true), JsonProperty]
[Name("HIRING CODERS"), Official(true)]
public bool Hiring_Coders;

/// <summary>Additional information.
/// Dictionary Key serves as the MSSP Key
/// Dictionary Value.obj serves as the MSSP Value
/// Dictionary Value.type serves as the MSSP Value Type for unboxing
/// We only support IEnumerable<string>, bool, int and string at this time</summary>
[Official(false), JsonProperty]
[Official(false)]
public Dictionary<string, dynamic> Extended = new();
}
}
1 change: 0 additions & 1 deletion TelnetNegotiationCore/TelnetNegotiationCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

<ItemGroup>
<PackageReference Include="morelinq" Version="3.4.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="OneOf" Version="3.0.255" />
<PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
Expand Down

0 comments on commit 337845c

Please sign in to comment.