Files
RAGECOOP-V/Core/CoreUtils.cs

601 lines
20 KiB
C#
Raw Normal View History

2022-10-23 19:02:39 +08:00
using System;
2022-05-22 15:55:26 +08:00
using System.Collections.Generic;
2022-09-08 12:41:56 -07:00
using System.IO;
2022-05-22 15:55:26 +08:00
using System.Linq;
2022-06-03 16:28:02 +08:00
using System.Net;
2022-08-12 20:40:50 +08:00
using System.Net.Http;
2022-09-08 12:41:56 -07:00
using System.Net.NetworkInformation;
2022-08-08 17:03:41 +08:00
using System.Net.Sockets;
2022-10-15 18:14:35 +08:00
using System.Reflection;
2022-07-01 12:22:31 +08:00
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
2022-09-08 12:41:56 -07:00
using System.Security.Cryptography;
using System.Text;
2022-11-16 17:37:31 +08:00
using System.Xml;
2022-10-23 19:02:39 +08:00
using GTA;
using GTA.Math;
using Lidgren.Network;
using Newtonsoft.Json;
using RageCoop.Core.Scripting;
2022-07-01 12:22:31 +08:00
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
2022-08-20 15:20:25 +08:00
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
[assembly: InternalsVisibleTo("DataDumper")]
[assembly: InternalsVisibleTo("UnitTest")]
2022-08-23 16:29:43 +08:00
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
2022-10-23 19:02:39 +08:00
2022-05-22 15:55:26 +08:00
namespace RageCoop.Core
{
2022-07-29 19:11:31 +08:00
internal static class CoreUtils
2022-05-22 15:55:26 +08:00
{
2022-10-23 19:02:39 +08:00
private static readonly Random random = new Random();
private static readonly HashSet<string> ToIgnore = new HashSet<string>
{
"RageCoop.Client",
"RageCoop.Client.Loader",
"RageCoop.Client.Installer",
"RageCoop.Core",
"RageCoop.Server",
"ScriptHookVDotNet2",
"ScriptHookVDotNet3",
"ScriptHookVDotNet"
};
2022-11-16 17:37:31 +08:00
public static string FormatToSharpStyle(string input, int offset)
2022-10-19 19:07:46 +08:00
{
var ss = input.Substring(offset).Split("_".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
// Replace first character with upper case
2022-10-23 19:02:39 +08:00
for (var i = 0; i < ss.Length; i++)
2022-10-19 19:07:46 +08:00
{
var sec = ss[i].ToLower();
var head = sec[0];
ss[i] = head.ToString().ToUpper() + sec.Remove(0, 1);
}
2022-10-23 19:02:39 +08:00
2022-10-19 19:07:46 +08:00
return string.Join("", ss);
}
2022-10-23 19:02:39 +08:00
2022-10-19 19:07:46 +08:00
public static string ToHex(this int value)
{
2022-10-23 19:02:39 +08:00
return string.Format("0x{0:X}", value);
2022-10-19 19:07:46 +08:00
}
2022-10-23 19:02:39 +08:00
2022-10-19 19:07:46 +08:00
public static string ToHex(this uint value)
{
2022-10-23 19:02:39 +08:00
return string.Format("0x{0:X}", value);
2022-10-19 19:07:46 +08:00
}
2022-10-23 19:02:39 +08:00
public static int RandInt(int start, int end)
2022-10-19 19:07:46 +08:00
{
return random.Next(start, end);
}
2022-10-23 19:02:39 +08:00
2022-10-19 19:07:46 +08:00
public static string GetTempDirectory(string dir = null)
{
dir = dir ?? Path.GetTempPath();
string path;
do
{
path = Path.Combine(dir, RandomString(10));
} while (Directory.Exists(path) || File.Exists(path));
return path;
}
2022-10-23 19:02:39 +08:00
2022-10-19 19:07:46 +08:00
public static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
2022-10-23 19:02:39 +08:00
2022-10-15 15:54:46 +08:00
public static Version GetLatestVersion(string branch = "dev-nightly")
{
2022-10-23 19:02:39 +08:00
var url =
$"https://raw.githubusercontent.com/RAGECOOP/RAGECOOP-V/{branch}/RageCoop.Server/Properties/AssemblyInfo.cs";
var versionLine = HttpHelper.DownloadString(url)
.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Where(x => x.Contains("[assembly: AssemblyVersion(")).First();
2022-10-15 15:54:46 +08:00
var start = versionLine.IndexOf('\"') + 1;
var end = versionLine.LastIndexOf('\"');
return Version.Parse(versionLine.Substring(start, end - start));
}
2022-10-23 19:02:39 +08:00
2022-07-29 19:11:31 +08:00
public static bool CanBeIgnored(this string name)
{
2022-10-08 12:43:24 +08:00
return ToIgnore.Contains(Path.GetFileNameWithoutExtension(name));
2022-07-29 19:11:31 +08:00
}
2022-10-23 19:02:39 +08:00
2022-10-09 23:35:30 +08:00
public static string ToFullPath(this string path)
{
return Path.GetFullPath(path);
}
2022-10-23 19:02:39 +08:00
2022-09-08 12:41:56 -07:00
public static void GetBytesFromObject(object obj, NetOutgoingMessage m)
2022-05-22 15:55:26 +08:00
{
switch (obj)
{
2022-08-27 14:23:28 +08:00
case byte value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x01);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case short value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x02);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case ushort value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x03);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case int value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x04);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case uint value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x05);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case long value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x06);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case ulong value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x07);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case float value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x08);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case bool value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x09);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case string value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x10);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case Vector3 value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x11);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case Quaternion value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x12);
m.Write(value);
break;
case Model value:
m.Write((byte)0x13);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case Vector2 value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x14);
m.Write(value);
break;
2022-08-27 14:23:28 +08:00
case byte[] value:
2022-10-23 19:02:39 +08:00
m.Write((byte)0x15);
m.WriteByteArray(value);
break;
case Tuple<byte, byte[]> value:
2022-10-23 19:02:39 +08:00
m.Write(value.Item1);
m.Write(value.Item2);
break;
2022-05-22 15:55:26 +08:00
default:
throw new Exception("Unsupported object type: " + obj.GetType());
2022-05-22 15:55:26 +08:00
}
}
2022-10-23 19:02:39 +08:00
2022-08-06 11:40:38 +08:00
public static IPEndPoint StringToEndPoint(string endpointstring)
{
return StringToEndPoint(endpointstring, -1);
}
2022-10-23 19:02:39 +08:00
2022-08-06 11:40:38 +08:00
public static IPEndPoint StringToEndPoint(string endpointstring, int defaultport)
{
if (string.IsNullOrEmpty(endpointstring)
|| endpointstring.Trim().Length == 0)
throw new ArgumentException("Endpoint descriptor may not be empty.");
if (defaultport != -1 &&
(defaultport < IPEndPoint.MinPort
2022-10-23 19:02:39 +08:00
|| defaultport > IPEndPoint.MaxPort))
2022-08-06 11:40:38 +08:00
throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport));
2022-10-23 19:02:39 +08:00
var values = endpointstring.Split(':');
2022-08-06 11:40:38 +08:00
IPAddress ipaddy;
2022-10-23 19:02:39 +08:00
var port = -1;
2022-08-06 11:40:38 +08:00
//check if we have an IPv6 or ports
if (values.Length <= 2) // ipv4 or hostname
{
if (values.Length == 1)
//no port is specified, default
port = defaultport;
else
port = getPort(values[1]);
//try to use the address as IPv4, otherwise get hostname
if (!IPAddress.TryParse(values[0], out ipaddy))
2022-08-08 17:03:41 +08:00
ipaddy = GetIPfromHost(values[0]);
2022-08-06 11:40:38 +08:00
}
else if (values.Length > 2) //ipv6
{
//could [a:b:c]:d
if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]"))
{
2022-10-23 19:02:39 +08:00
var ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray());
2022-08-06 11:40:38 +08:00
ipaddy = IPAddress.Parse(ipaddressstring);
port = getPort(values[values.Length - 1]);
}
else //[a:b:c] or a:b:c
{
ipaddy = IPAddress.Parse(endpointstring);
port = defaultport;
}
}
else
{
throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring));
}
if (port == -1)
throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring));
return new IPEndPoint(ipaddy, port);
}
private static int getPort(string p)
{
2022-10-23 19:02:39 +08:00
if (!int.TryParse(p, out var port)
|| port < IPEndPoint.MinPort
|| port > IPEndPoint.MaxPort)
2022-08-06 11:40:38 +08:00
throw new FormatException(string.Format("Invalid end point port '{0}'", p));
return port;
}
2022-10-23 19:02:39 +08:00
2022-09-08 12:41:56 -07:00
public static IPAddress GetLocalAddress(string target = "8.8.8.8")
2022-08-08 17:03:41 +08:00
{
2022-10-23 19:02:39 +08:00
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
2022-08-08 17:03:41 +08:00
{
socket.Connect(target, 65530);
2022-10-23 19:02:39 +08:00
var endPoint = socket.LocalEndPoint as IPEndPoint;
2022-08-08 17:03:41 +08:00
return endPoint.Address;
}
}
2022-10-23 19:02:39 +08:00
2022-08-12 20:40:50 +08:00
public static IPAddress GetIPfromHost(string p)
2022-08-06 11:40:38 +08:00
{
var hosts = Dns.GetHostAddresses(p);
if (hosts == null || hosts.Length == 0)
throw new ArgumentException(string.Format("Host not found: {0}", p));
return hosts[0];
}
2022-10-23 19:02:39 +08:00
2022-08-12 20:40:50 +08:00
public static IpInfo GetIPInfo()
{
// TLS only
ServicePointManager.Expect100Continue = true;
2022-10-23 19:02:39 +08:00
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
2022-08-12 20:40:50 +08:00
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
var httpClient = new HttpClient();
2022-10-23 19:02:39 +08:00
var response = httpClient.GetAsync("https://ipinfo.io/json").GetAwaiter().GetResult();
2022-08-12 20:40:50 +08:00
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception($"IPv4 request failed! [{(int)response.StatusCode}/{response.ReasonPhrase}]");
2022-10-23 19:02:39 +08:00
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
2022-08-12 20:40:50 +08:00
return JsonConvert.DeserializeObject<IpInfo>(content);
}
public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
{
2022-10-23 19:02:39 +08:00
foreach (var dir in source.GetDirectories())
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
2022-10-23 19:02:39 +08:00
foreach (var file in source.GetFiles())
file.CopyTo(Path.Combine(target.FullName, file.Name), true);
}
2022-10-23 19:02:39 +08:00
public static string GetInvariantRID()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return "win-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
2022-09-05 13:02:09 +02:00
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return "linux-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
2022-09-05 13:02:09 +02:00
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return "osx-" + RuntimeInformation.OSArchitecture.ToString().ToLower();
return "unknown";
}
2022-08-12 20:40:50 +08:00
/// <summary>
2022-10-23 19:02:39 +08:00
/// Get local ip addresses on all network interfaces
/// </summary>
/// <returns></returns>
public static List<IPAddress> GetLocalAddress()
{
var addresses = new List<IPAddress>();
2022-10-23 19:02:39 +08:00
foreach (var netInterface in NetworkInterface.GetAllNetworkInterfaces())
{
2022-10-23 19:02:39 +08:00
var ipProps = netInterface.GetIPProperties();
foreach (var addr in ipProps.UnicastAddresses) addresses.Add(addr.Address);
}
2022-10-23 19:02:39 +08:00
return addresses;
}
2022-10-23 19:02:39 +08:00
public static StreamWriter OpenWriter(string path, FileMode mode = FileMode.Create,
FileAccess access = FileAccess.Write, FileShare share = FileShare.ReadWrite)
{
return new StreamWriter(File.Open(path, mode, access, share));
}
2022-11-16 17:37:31 +08:00
public static float GetFloat(this XmlNode n)
{
return float.Parse(n.Attributes["value"].Value);
}
/// <summary>
2022-11-16 17:40:07 +08:00
/// Generate jenkins one-at-a-time hash from specified string (lower)
2022-11-16 17:37:31 +08:00
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static uint JoaatHash(string key)
{
var i = 0;
uint hash = 0;
while (i != key.Length)
{
hash += char.ToLowerInvariant(key[i++]);
hash += hash << 10;
hash ^= hash >> 6;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
2022-08-12 20:40:50 +08:00
}
2022-10-23 19:02:39 +08:00
internal class IpInfo
2022-08-12 20:40:50 +08:00
{
2022-10-23 19:02:39 +08:00
[JsonProperty("ip")] public string Address { get; set; }
2022-06-03 16:28:02 +08:00
2022-10-23 19:02:39 +08:00
[JsonProperty("country")] public string Country { get; set; }
2022-05-22 15:55:26 +08:00
}
2022-10-23 19:02:39 +08:00
2022-07-01 14:39:43 +08:00
internal static class Extensions
2022-05-22 15:55:26 +08:00
{
public static byte[] GetBytes(this string s)
2022-05-22 15:55:26 +08:00
{
return Encoding.UTF8.GetBytes(s);
2022-05-22 15:55:26 +08:00
}
2022-10-23 19:02:39 +08:00
public static string GetString(this byte[] data)
2022-05-22 15:55:26 +08:00
{
return Encoding.UTF8.GetString(data);
2022-05-22 15:55:26 +08:00
}
2022-10-23 19:02:39 +08:00
2022-07-02 17:14:56 +08:00
public static byte[] GetBytes(this Vector3 vec)
{
// 12 bytes
2022-10-23 19:02:39 +08:00
return new List<byte[]>
{ BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y), BitConverter.GetBytes(vec.Z) }.Join(4);
2022-07-02 17:14:56 +08:00
}
2022-07-03 15:28:28 +08:00
public static byte[] GetBytes(this Vector2 vec)
{
// 8 bytes
2022-10-23 19:02:39 +08:00
return new List<byte[]> { BitConverter.GetBytes(vec.X), BitConverter.GetBytes(vec.Y) }.Join(4);
2022-07-03 15:28:28 +08:00
}
2022-07-02 17:14:56 +08:00
/// <summary>
/// </summary>
/// <param name="qua"></param>
/// <returns>An array of bytes with length 16</returns>
public static byte[] GetBytes(this Quaternion qua)
{
// 16 bytes
2022-10-23 19:02:39 +08:00
return new List<byte[]>
{
BitConverter.GetBytes(qua.X), BitConverter.GetBytes(qua.Y), BitConverter.GetBytes(qua.Z),
BitConverter.GetBytes(qua.W)
}.Join(4);
2022-07-02 17:14:56 +08:00
}
2022-10-23 19:02:39 +08:00
2022-09-08 12:41:56 -07:00
public static T GetPacket<T>(this NetIncomingMessage msg) where T : Packet, new()
2022-08-10 20:42:47 +08:00
{
var p = new T();
p.Deserialize(msg);
2022-08-10 20:42:47 +08:00
return p;
}
2022-10-23 19:02:39 +08:00
public static bool HasPedFlag(this PedDataFlags flags, PedDataFlags flag)
2022-06-21 18:13:30 +08:00
{
return (flags & flag) != 0;
2022-06-21 18:13:30 +08:00
}
2022-10-23 19:02:39 +08:00
public static bool HasProjDataFlag(this ProjectileDataFlags flags, ProjectileDataFlags flag)
2022-08-14 17:08:43 +08:00
{
return (flags & flag) != 0;
2022-08-14 17:08:43 +08:00
}
2022-06-21 18:13:30 +08:00
public static bool HasVehFlag(this VehicleDataFlags flags, VehicleDataFlags flag)
2022-06-21 18:13:30 +08:00
{
return (flags & flag) != 0;
2022-06-21 18:13:30 +08:00
}
2022-10-23 19:02:39 +08:00
public static bool HasConfigFlag(this PlayerConfigFlags flags, PlayerConfigFlags flag)
2022-06-22 14:18:20 +08:00
{
return (flags & flag) != 0;
}
2022-10-23 19:02:39 +08:00
2022-10-08 23:49:48 +08:00
public static bool HasEventFlag(this CustomEventFlags flags, CustomEventFlags flag)
{
return (flags & flag) != 0;
2022-06-22 14:18:20 +08:00
}
2022-10-23 19:02:39 +08:00
2022-06-23 09:46:38 +08:00
public static Type GetActualType(this TypeCode code)
{
switch (code)
{
case TypeCode.Boolean:
return typeof(bool);
case TypeCode.Byte:
return typeof(byte);
case TypeCode.Char:
return typeof(char);
case TypeCode.DateTime:
return typeof(DateTime);
case TypeCode.DBNull:
return typeof(DBNull);
case TypeCode.Decimal:
return typeof(decimal);
case TypeCode.Double:
return typeof(double);
case TypeCode.Empty:
return null;
case TypeCode.Int16:
return typeof(short);
case TypeCode.Int32:
return typeof(int);
case TypeCode.Int64:
return typeof(long);
case TypeCode.Object:
return typeof(object);
case TypeCode.SByte:
return typeof(sbyte);
case TypeCode.Single:
2022-10-23 19:02:39 +08:00
return typeof(float);
2022-06-23 09:46:38 +08:00
case TypeCode.String:
return typeof(string);
case TypeCode.UInt16:
2022-10-23 19:02:39 +08:00
return typeof(ushort);
2022-06-23 09:46:38 +08:00
case TypeCode.UInt32:
2022-10-23 19:02:39 +08:00
return typeof(uint);
2022-06-23 09:46:38 +08:00
case TypeCode.UInt64:
2022-10-23 19:02:39 +08:00
return typeof(ulong);
2022-06-23 09:46:38 +08:00
}
return null;
}
2022-10-23 19:02:39 +08:00
2022-06-23 09:46:38 +08:00
public static string DumpWithType(this IEnumerable<object> objects)
{
2022-10-23 19:02:39 +08:00
var sb = new StringBuilder();
foreach (var obj in objects) sb.Append(obj.GetType() + ":" + obj + "\n");
2022-06-23 09:46:38 +08:00
return sb.ToString();
}
2022-10-23 19:02:39 +08:00
2022-06-23 09:46:38 +08:00
public static string Dump<T>(this IEnumerable<T> objects)
{
2022-09-05 13:02:09 +02:00
return $"{{{string.Join(",", objects)}}}";
2022-06-23 09:46:38 +08:00
}
2022-10-23 19:02:39 +08:00
2022-09-08 12:41:56 -07:00
public static void ForEach<T>(this IEnumerable<T> objects, Action<T> action)
2022-06-23 09:46:38 +08:00
{
2022-10-23 19:02:39 +08:00
foreach (var obj in objects) action(obj);
2022-06-23 09:46:38 +08:00
}
2022-10-23 19:02:39 +08:00
2022-06-24 10:33:36 +08:00
public static byte[] ReadToEnd(this Stream stream)
{
if (stream is MemoryStream)
return ((MemoryStream)stream).ToArray();
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
2022-10-23 19:02:39 +08:00
2022-08-23 12:21:17 +08:00
public static MemoryStream ToMemStream(this Stream stream)
{
var memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream;
}
2022-10-23 19:02:39 +08:00
2022-09-08 12:41:56 -07:00
public static byte[] Join(this List<byte[]> arrays, int lengthPerArray = -1)
2022-06-24 10:33:36 +08:00
{
2022-10-23 19:02:39 +08:00
if (arrays.Count == 1) return arrays[0];
var output = lengthPerArray == -1
? new byte[arrays.Sum(arr => arr.Length)]
: new byte[arrays.Count * lengthPerArray];
var writeIdx = 0;
2022-06-24 10:33:36 +08:00
foreach (var byteArr in arrays)
{
byteArr.CopyTo(output, writeIdx);
writeIdx += byteArr.Length;
}
2022-10-23 19:02:39 +08:00
2022-06-24 10:33:36 +08:00
return output;
}
2022-07-01 12:22:31 +08:00
2022-10-15 17:06:19 +08:00
public static bool IsScript(this Type type, Type scriptType)
2022-07-01 12:22:31 +08:00
{
return !type.IsAbstract && type.IsSubclassOf(scriptType);
2022-07-01 12:22:31 +08:00
}
2022-05-22 15:55:26 +08:00
}
/// <summary>
2022-10-23 19:02:39 +08:00
/// Some extension methods provided by RageCoop
/// </summary>
public static class PublicExtensions
{
/// <summary>
2022-10-23 19:02:39 +08:00
/// Get a SHA256 hashed byte array of the input string, internally used to hash password at client side.
/// </summary>
/// <param name="inputString"></param>
/// <returns></returns>
public static byte[] GetSHA256Hash(this string inputString)
{
using (HashAlgorithm algorithm = SHA256.Create())
2022-10-23 19:02:39 +08:00
{
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
2022-10-23 19:02:39 +08:00
}
}
/// <summary>
2022-10-23 19:02:39 +08:00
/// Convert a byte array to hex-encoded string, internally used to trigger handshake event
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static string ToHexString(this byte[] data)
{
2022-10-23 19:02:39 +08:00
return BitConverter.ToString(data).Replace("-", string.Empty);
}
2022-08-12 18:02:43 +08:00
/// <summary>
2022-10-23 19:02:39 +08:00
/// Convert a string to IP address
2022-08-12 18:02:43 +08:00
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public static IPAddress ToIP(this string ip)
{
return IPAddress.Parse(ip);
}
}
2022-10-23 19:02:39 +08:00
}