diff --git a/v2rayN/v2rayN/Base/StringEx.cs b/v2rayN/v2rayN/Base/StringEx.cs
index 1e150a48..98fed4d8 100644
--- a/v2rayN/v2rayN/Base/StringEx.cs
+++ b/v2rayN/v2rayN/Base/StringEx.cs
@@ -46,5 +46,29 @@ namespace v2rayN.Base
{
return value == null ? string.Empty : value.Trim();
}
+
+ public static string RemovePrefix(this string value, char prefix)
+ {
+ if (value.StartsWith(prefix))
+ {
+ return value.Substring(1);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+ public static string RemovePrefix(this string value, string prefix)
+ {
+ if (value.StartsWith(prefix))
+ {
+ return value.Substring(prefix.Length);
+ }
+ else
+ {
+ return value;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/v2rayN/v2rayN/Handler/UpdateHandle.cs b/v2rayN/v2rayN/Handler/UpdateHandle.cs
index 7e90e6ca..f9de0b39 100644
--- a/v2rayN/v2rayN/Handler/UpdateHandle.cs
+++ b/v2rayN/v2rayN/Handler/UpdateHandle.cs
@@ -9,6 +9,7 @@ using System.Windows;
using v2rayN.Base;
using v2rayN.Mode;
using v2rayN.Resx;
+using v2rayN.Tool;
namespace v2rayN.Handler
{
@@ -331,7 +332,7 @@ namespace v2rayN.Handler
///
/// 获取V2RayCore版本
///
- private string getCoreVersion(ECoreType type)
+ private SemanticVersion getCoreVersion(ECoreType type)
{
try
{
@@ -352,7 +353,7 @@ namespace v2rayN.Handler
{
string msg = string.Format(ResUI.NotFoundCore, @"", "", "");
//ShowMsg(true, msg);
- return "";
+ return new SemanticVersion("");
}
using Process p = new();
@@ -385,13 +386,13 @@ namespace v2rayN.Handler
version = Regex.Match(echo, $"([0-9.]+)").Groups[1].Value;
break;
}
- return version;
+ return new SemanticVersion(version);
}
catch (Exception ex)
{
Utils.SaveLog(ex.Message, ex);
_updateFunc(false, ex.Message);
- return "";
+ return new SemanticVersion("");
}
}
@@ -400,18 +401,18 @@ namespace v2rayN.Handler
try
{
var gitHubReleases = Utils.FromJson>(gitHubReleaseApi);
- string version;
+ SemanticVersion version;
if (preRelease)
{
- version = gitHubReleases!.First().TagName;
+ version = new SemanticVersion(gitHubReleases!.First().TagName);
}
else
{
- version = gitHubReleases!.First(r => r.Prerelease == false).TagName;
+ version = new SemanticVersion(gitHubReleases!.First(r => r.Prerelease == false).TagName);
}
var coreInfo = LazyConfig.Instance.GetCoreInfo(type);
- string curVersion;
+ SemanticVersion curVersion;
string message;
string url;
switch (type)
@@ -421,8 +422,8 @@ namespace v2rayN.Handler
case ECoreType.Xray:
case ECoreType.v2fly_v5:
{
- curVersion = "v" + getCoreVersion(type);
- message = string.Format(ResUI.IsLatestCore, curVersion);
+ curVersion = getCoreVersion(type);
+ message = string.Format(ResUI.IsLatestCore, curVersion.ToVersionString("v"));
string osBit = "64";
switch (RuntimeInformation.ProcessArchitecture)
{
@@ -439,7 +440,7 @@ namespace v2rayN.Handler
break;
}
- url = string.Format(coreInfo.coreDownloadUrl64, version, osBit);
+ url = string.Format(coreInfo.coreDownloadUrl64, version.ToVersionString("v"), osBit);
break;
}
case ECoreType.clash:
@@ -466,8 +467,8 @@ namespace v2rayN.Handler
}
case ECoreType.sing_box:
{
- curVersion = "v" + getCoreVersion(type);
- message = string.Format(ResUI.IsLatestCore, curVersion);
+ curVersion = getCoreVersion(type);
+ message = string.Format(ResUI.IsLatestCore, curVersion.ToVersionString("v"));
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.Arm64:
@@ -482,12 +483,12 @@ namespace v2rayN.Handler
url = coreInfo.coreDownloadUrl64;
break;
}
- url = string.Format(url, version, version.Replace("v", ""));
+ url = string.Format(url, version.ToVersionString("v"), version);
break;
}
case ECoreType.v2rayN:
{
- curVersion = FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString();
+ curVersion = new SemanticVersion(FileVersionInfo.GetVersionInfo(Utils.GetExePath()).FileVersion.ToString());
message = string.Format(ResUI.IsLatestN, curVersion);
switch (RuntimeInformation.ProcessArchitecture)
{
@@ -511,16 +512,15 @@ namespace v2rayN.Handler
if (type == ECoreType.v2rayN)
{
- decimal.TryParse(curVersion, out decimal decCur);
- decimal.TryParse(version, out decimal dec);
+ decimal.TryParse(curVersion.ToString(), out decimal decCur);
+ decimal.TryParse(version.ToString(), out decimal dec);
if (decCur >= dec)
{
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
return;
}
}
-
- if (curVersion == version)
+ if (curVersion >= version)
{
AbsoluteCompleted?.Invoke(this, new ResultEventArgs(false, message));
return;
diff --git a/v2rayN/v2rayN/Tool/SemanticVersion.cs b/v2rayN/v2rayN/Tool/SemanticVersion.cs
new file mode 100644
index 00000000..a79a3fbc
--- /dev/null
+++ b/v2rayN/v2rayN/Tool/SemanticVersion.cs
@@ -0,0 +1,173 @@
+using v2rayN.Base;
+
+namespace v2rayN.Tool
+{
+ public class SemanticVersion
+ {
+ private int major;
+ private int minor;
+ private int patch;
+ private string version;
+
+ public SemanticVersion(int major, int minor, int patch)
+ {
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ this.version = $"{major}.{minor}.{patch}";
+ }
+
+ public SemanticVersion(string version)
+ {
+ this.version = version.RemovePrefix('v');
+ try
+ {
+ string[] parts = this.version.Split('.');
+ if (parts.Length == 2)
+ {
+ this.major = int.Parse(parts[0]);
+ this.minor = int.Parse(parts[1]);
+ this.patch = 0;
+ }
+ else if (parts.Length == 3)
+ {
+ this.major = int.Parse(parts[0]);
+ this.minor = int.Parse(parts[1]);
+ this.patch = int.Parse(parts[2]);
+ }
+ else
+ {
+ throw new ArgumentException("Invalid version string");
+ }
+ }
+ catch
+ {
+ this.major = 0;
+ this.minor = 0;
+ this.patch = 0;
+ this.version = "0.0.0";
+ }
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (obj is SemanticVersion other)
+ {
+ return this.major == other.major && this.minor == other.minor && this.patch == other.patch;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return this.major.GetHashCode() ^ this.minor.GetHashCode() ^ this.patch.GetHashCode();
+ }
+
+ ///
+ /// Use ToVersionString(string? prefix) instead if possible.
+ ///
+ /// major.minor.patch
+ public override string ToString()
+ {
+ return this.version;
+ }
+
+ public string ToVersionString(string? prefix = null)
+ {
+ if (prefix == null)
+ {
+ return this.version;
+ }
+ else
+ {
+ return $"{prefix}{this.version}";
+ }
+ }
+
+ public static bool operator ==(SemanticVersion v1, SemanticVersion v2) { return v1.Equals(v2); }
+ public static bool operator !=(SemanticVersion v1, SemanticVersion v2) { return !v1.Equals(v2); }
+ public static bool operator >=(SemanticVersion v1, SemanticVersion v2) { return v1.GreaterEquals(v2); }
+ public static bool operator <=(SemanticVersion v1, SemanticVersion v2) { return v1.LessEquals(v2); }
+
+ #region Private
+ private bool GreaterEquals(SemanticVersion other)
+ {
+ if (this.major < other.major)
+ {
+ return false;
+ }
+ else if (this.major > other.major)
+ {
+ return true;
+ }
+ else
+ {
+ if (this.minor < other.minor)
+ {
+ return false;
+ }
+ else if (this.minor > other.minor)
+ {
+ return true;
+ }
+ else
+ {
+ if (this.patch < other.patch)
+ {
+ return false;
+ }
+ else if (this.patch > other.patch)
+ {
+ return true;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ private bool LessEquals(SemanticVersion other)
+ {
+ if (this.major < other.major)
+ {
+ return true;
+ }
+ else if (this.major > other.major)
+ {
+ return false;
+ }
+ else
+ {
+ if (this.minor < other.minor)
+ {
+ return true;
+ }
+ else if (this.minor > other.minor)
+ {
+ return false;
+ }
+ else
+ {
+ if (this.patch < other.patch)
+ {
+ return true;
+ }
+ else if (this.patch > other.patch)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ }
+ #endregion Private
+ }
+}