Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

编码与连接优化 #7

Merged
merged 13 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# NectarRcon Config
config.json
servers.json
passwords.json

# User-specific files
*.rsuser
*.suo
Expand Down
26 changes: 20 additions & 6 deletions NectarRCON.Adapter.Minecraft/MinecraftRconClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using NectarRCON.Export.Client;
using NectarRCON.Export.Interfaces;
using System.ComponentModel;
using System.Text;

namespace NectarRCON.Adapter.Minecraft
{
Expand All @@ -11,8 +12,13 @@ public class MinecraftRconClient : BaseTcpClient, IRconAdapter
private static readonly int MaxMessageSize = 4110;

private readonly MemoryStream _buffer = new();
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
private int lastId = 0;
private readonly SemaphoreSlim _semaphore = new(1);
private int _lastId;
/// <summary>
/// 编码
/// 默认编码 UTF8
/// </summary>
private new Encoding _encoding = Encoding.UTF8;

public void Disconnect()
{
Expand Down Expand Up @@ -56,6 +62,14 @@ public string Run(string command)
}
}

public Encoding GetEncoding()
=> _encoding;

public void SetEncoding(Encoding encoding)
{
_encoding = encoding;
}

public bool Connect(string address, int port)
{
_semaphore.Wait();
Expand All @@ -76,7 +90,7 @@ public bool Authenticate(string password)
try
{
Packet packet = Send(new Packet(PacketType.Authenticate, password));
return packet.Id == lastId;
return packet.Id == _lastId;
}
finally
{
Expand All @@ -86,9 +100,9 @@ public bool Authenticate(string password)

private Packet Send(Packet packet)
{
Interlocked.Increment(ref lastId);
packet.SetId(lastId);
return PacketEncoder.Decode(Send(packet.Encode()));
Interlocked.Increment(ref _lastId);
packet.SetId(_lastId);
return PacketEncoder.Decode(Send(packet.Encode(_encoding)), _encoding);
}
}
}
4 changes: 2 additions & 2 deletions NectarRCON.Adapter.Minecraft/Packet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ public void SetId(int id)
Id = id;
}

public byte[] Encode()
public byte[] Encode(Encoding? encoding = null)
{
List<byte> bytes = new List<byte>();
var data = Encoding.UTF8.GetBytes(Body);
var data = (encoding?? Encoding.UTF8).GetBytes(Body);
bytes.AddRange(BitConverter.GetBytes(PacketEncoder.HeaderLength + data.Length));
bytes.AddRange(BitConverter.GetBytes(Id));
bytes.AddRange(BitConverter.GetBytes((int)Type));
Expand Down
10 changes: 5 additions & 5 deletions NectarRCON.Adapter.Minecraft/PacketEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ public enum PacketType : int
Authenticate // 3: Login
}

public class PacketEncoder
public abstract class PacketEncoder
{
public const int HeaderLength = 10;

public static byte[] Encode(Packet msg)
public static byte[] Encode(Packet msg, Encoding? encoding = null)
{
List<byte> bytes = new List<byte>();

bytes.AddRange(BitConverter.GetBytes(msg.Length));
bytes.AddRange(BitConverter.GetBytes(msg.Id));
bytes.AddRange(BitConverter.GetBytes((int)msg.Type));
bytes.AddRange(Encoding.UTF8.GetBytes(msg.Body));
bytes.AddRange((encoding??Encoding.UTF8).GetBytes(msg.Body));
bytes.AddRange(new byte[] { 0, 0 });

return bytes.ToArray();
}

public static Packet Decode(byte[] bytes)
public static Packet Decode(byte[] bytes, Encoding? encoding = null)
{
if (bytes.Length < HeaderLength) { throw new ArgumentException("packet length too short"); }
int len = BitConverter.ToInt32(bytes, 0);
Expand All @@ -37,7 +37,7 @@ public static Packet Decode(byte[] bytes)
string body = string.Empty;
if (bodyLen > 0)
{
body = Encoding.UTF8.GetString(bytes, 12, bodyLen);
body = (encoding??Encoding.UTF8).GetString(bytes, 12, bodyLen);
}
return new Packet(len, id, (PacketType)type, body);
}
Expand Down
7 changes: 6 additions & 1 deletion NectarRCON.Export/Interfaces/IRconAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace NectarRCON.Export.Interfaces;
using System.Text;

namespace NectarRCON.Export.Interfaces;
/// <summary>
/// Rcon协议兼容接口
/// </summary>
Expand Down Expand Up @@ -30,4 +32,7 @@ public interface IRconAdapter : IDisposable
/// </summary>

string Run(string command);

Encoding GetEncoding();
void SetEncoding(Encoding encoding);
}
6 changes: 5 additions & 1 deletion NectarRCON.Export/NectarRCON.Export.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net7.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\NectarRCON.Updater\NectarRCON.Updater.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions NectarRCON.Tests/NectarRCON.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ProjectReference Include="..\NectarRCON.Adapter.Minecraft\NectarRCON.Adapter.Minecraft.csproj" />
<ProjectReference Include="..\NectarRCON.Core\NectarRCON.Core.csproj" />
<ProjectReference Include="..\NectarRCON.Export\NectarRCON.Export.csproj" />
<ProjectReference Include="..\NectarRCON.Updater\NectarRCON.Updater.csproj" />
<ProjectReference Include="..\NectarRCON\NectarRCON.csproj" />
</ItemGroup>

Expand Down
40 changes: 40 additions & 0 deletions NectarRCON.Tests/UpdaterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using NectarRCON.Updater;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NectarRCON.Tests
{
[TestClass]
public class UpdaterTests
{
[TestMethod]
public void Github()
{
IUpdater updater = new GithubUpdater();
updater.SetVersion("NectarRcon-x86-1.0.0");
updater.IsLatestVersion();
}

[TestMethod]
public void AppVersionTest()
{
AppVersion versionA = AppVersion.ParseVersion("TestApp-x64-1.0.0-beta1");
AppVersion versionB = AppVersion.ParseVersion("TestApp-x64-1.0.0-beta2");

Assert.IsTrue(versionA.Equals(versionA));
Assert.IsFalse(versionA.Equals(versionB));

#pragma warning disable CS1718 // 对同一变量进行了比较
Assert.IsTrue(versionA == versionA);
Assert.IsFalse(versionA != versionA);
Assert.IsFalse(versionA > versionA);
#pragma warning restore CS1718 // 对同一变量进行了比较

Assert.IsTrue(versionB > versionA);
Assert.IsFalse(versionB < versionA);
}
}
}
105 changes: 105 additions & 0 deletions NectarRCON.Updater/AppVersion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;

namespace NectarRCON.Updater
{
public class AppVersion
{
public string AppName { get; set; } = string.Empty;
public int Version { get; set; }
public int Major { get;set; }
public int Minor { get;set; }
public int Patch { get;set; }
public int? Build { get; set; }
public string PreReleaseType { get; set; } = string.Empty;
public string Platform { get; set; } = string.Empty;
public bool IsPreRelease
=> !string.IsNullOrEmpty(PreReleaseType);

public override string ToString()
{
return $"{AppName}-{Platform}-{Major}.{Minor}.{Patch}" + (IsPreRelease ? $"-{PreReleaseType}{Build}" : string.Empty);
}

public override bool Equals(object? obj)
{
return obj?.ToString() == ToString();
}

public static bool operator <(AppVersion a, AppVersion b)
{
return a.Version < b.Version || (a.Build ?? 0) < (b.Build ?? 0);
}

public static bool operator >(AppVersion a, AppVersion b)
{
return a.Version > b.Version || (a.Build ?? 0) > (b.Build ?? 0);
}

public static bool operator ==(AppVersion a, AppVersion b)
{
return a.Version == b.Version && (a.Build ?? 0) == (b.Build ?? 0);
}

public static bool operator !=(AppVersion a, AppVersion b)
{
return a.Version != b.Version || (a.Build ?? 0) != (b.Build ?? 0);
}

private AppVersion() { }

public static AppVersion ParseVersion(string version)
{
string[] versionParts = version.Split("-");
if (versionParts.Length > 2)
{
AppVersion result = new();
string name = versionParts[0];
string platform = versionParts[1];
string ver = versionParts[2];
string preRelease = string.Empty;

if (versionParts.Length > 3)
{
preRelease = versionParts[3];
}

Regex versionRegex = new(@"(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)");
Match versionMatch = versionRegex.Match(ver);

if (versionMatch.Success)
{
result.Version = int.Parse(versionMatch.Groups["major"].Value + versionMatch.Groups["minor"].Value + versionMatch.Groups["patch"].Value);
result.Major = int.Parse(versionMatch.Groups["major"].Value);
result.Minor = int.Parse(versionMatch.Groups["minor"].Value);
result.Patch = int.Parse(versionMatch.Groups["patch"].Value);
}

Regex preReleaseRegex = new(@"(?<preRelease>[a-zA-Z]+)(?<build>\d+)");
Match preReleaseMatch = preReleaseRegex.Match(preRelease);

if (preReleaseMatch.Success)
{
if (preReleaseMatch.Groups["build"].Success)
{
result.Build = int.Parse(preReleaseMatch.Groups["build"].Value);
}
if (preReleaseMatch.Groups["preRelease"].Success)
{
result.PreReleaseType = preReleaseMatch.Groups["preRelease"].Value;
}
}

result.Platform = platform;
result.AppName = name;
return result;
}
throw new InvalidOperationException("Invalid version format");
}

public override int GetHashCode()
{
return RuntimeHelpers.GetHashCode(ToString());
}
}
}
Loading