diff --git a/.gitignore b/.gitignore
index 5a6192030..7cf87e782 100644
--- a/.gitignore
+++ b/.gitignore
@@ -237,3 +237,4 @@ launchSettings.json
**/Master/env_master
/GameLogServer/log_env
**/*.css
+/Master/master/persistence
diff --git a/Application/API/Master/ApiInstance.cs b/Application/API/Master/ApiInstance.cs
index 846adb744..f2f0332ca 100644
--- a/Application/API/Master/ApiInstance.cs
+++ b/Application/API/Master/ApiInstance.cs
@@ -1,19 +1,36 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Collections.Generic;
using Newtonsoft.Json;
-using RestEase;
+using SharedLibraryCore.Helpers;
namespace IW4MAdmin.Application.API.Master
{
+ ///
+ /// Defines the structure of the IW4MAdmin instance for the master API
+ ///
public class ApiInstance
{
+ ///
+ /// Unique ID of the instance
+ ///
[JsonProperty("id")]
public string Id { get; set; }
+
+ ///
+ /// Indicates how long the instance has been running
+ ///
[JsonProperty("uptime")]
public int Uptime { get; set; }
+
+ ///
+ /// Specifices the version of the instance
+ ///
[JsonProperty("version")]
- public float Version { get; set; }
+ [JsonConverter(typeof(BuildNumberJsonConverter))]
+ public BuildNumber Version { get; set; }
+
+ ///
+ /// List of servers the instance is monitoring
+ ///
[JsonProperty("servers")]
public List Servers { get; set; }
}
diff --git a/Application/API/Master/Heartbeat.cs b/Application/API/Master/Heartbeat.cs
index 16e34a076..cab6a81cc 100644
--- a/Application/API/Master/Heartbeat.cs
+++ b/Application/API/Master/Heartbeat.cs
@@ -1,22 +1,21 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading;
using System.Threading.Tasks;
using RestEase;
-using SharedLibraryCore;
namespace IW4MAdmin.Application.API.Master
{
- public class HeartbeatState
- {
- public bool Connected { get; set; }
- public CancellationToken Token { get; set; }
- }
-
+ ///
+ /// Defines the heartbeat functionality for IW4MAdmin
+ ///
public class Heartbeat
{
+ ///
+ /// Sends heartbeat to master server
+ ///
+ ///
+ ///
+ ///
public static async Task Send(ApplicationManager mgr, bool firstHeartbeat = false)
{
var api = Endpoint.Get();
@@ -35,7 +34,7 @@ namespace IW4MAdmin.Application.API.Master
{
Id = mgr.GetApplicationSettings().Configuration().Id,
Uptime = (int)(DateTime.UtcNow - mgr.StartTime).TotalSeconds,
- Version = (float)Program.Version,
+ Version = Program.Version,
Servers = mgr.Servers.Select(s =>
new ApiServer()
{
@@ -52,14 +51,21 @@ namespace IW4MAdmin.Application.API.Master
}).ToList()
};
+ Response response = null;
+
if (firstHeartbeat)
{
- var message = await api.AddInstance(instance);
+ response = await api.AddInstance(instance);
}
else
{
- var message = await api.UpdateInstance(instance.Id, instance);
+ response = await api.UpdateInstance(instance.Id, instance);
+ }
+
+ if (response.ResponseMessage.StatusCode != System.Net.HttpStatusCode.OK)
+ {
+ mgr.Logger.WriteWarning($"Response code from master is {response.ResponseMessage.StatusCode}, message is {response.StringContent}");
}
}
}
diff --git a/Application/API/Master/IMasterApi.cs b/Application/API/Master/IMasterApi.cs
index ea09511d7..d31c22e82 100644
--- a/Application/API/Master/IMasterApi.cs
+++ b/Application/API/Master/IMasterApi.cs
@@ -4,6 +4,7 @@ using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RestEase;
+using SharedLibraryCore.Helpers;
namespace IW4MAdmin.Application.API.Master
{
@@ -22,9 +23,12 @@ namespace IW4MAdmin.Application.API.Master
public class VersionInfo
{
[JsonProperty("current-version-stable")]
- public float CurrentVersionStable { get; set; }
+ [JsonConverter(typeof(BuildNumberJsonConverter))]
+ public BuildNumber CurrentVersionStable { get; set; }
+
[JsonProperty("current-version-prerelease")]
- public float CurrentVersionPrerelease { get; set; }
+ [JsonConverter(typeof(BuildNumberJsonConverter))]
+ public BuildNumber CurrentVersionPrerelease { get; set; }
}
public class ResultMessage
@@ -38,11 +42,14 @@ namespace IW4MAdmin.Application.API.Master
#if !DEBUG
private static readonly IMasterApi api = RestClient.For("http://api.raidmax.org:5000");
#else
- private static IMasterApi api = RestClient.For("http://127.0.0.1");
+ private static readonly IMasterApi api = RestClient.For("http://127.0.0.1");
#endif
public static IMasterApi Get() => api;
}
+ ///
+ /// Defines the capabilities of the master API
+ ///
[Header("User-Agent", "IW4MAdmin-RestEase")]
public interface IMasterApi
{
@@ -53,13 +60,15 @@ namespace IW4MAdmin.Application.API.Master
Task Authenticate([Body] AuthenticationId Id);
[Post("instance/")]
- Task AddInstance([Body] ApiInstance instance);
+ [AllowAnyStatusCode]
+ Task> AddInstance([Body] ApiInstance instance);
[Put("instance/{id}")]
- Task UpdateInstance([Path] string id, [Body] ApiInstance instance);
+ [AllowAnyStatusCode]
+ Task> UpdateInstance([Path] string id, [Body] ApiInstance instance);
- [Get("version")]
- Task GetVersion();
+ [Get("version/{apiVersion}")]
+ Task GetVersion([Path] int apiVersion);
[Get("localization")]
Task> GetLocalization();
diff --git a/Application/BuildScripts/PostBuild.bat b/Application/BuildScripts/PostBuild.bat
index db0ed34ae..6433f9de2 100644
--- a/Application/BuildScripts/PostBuild.bat
+++ b/Application/BuildScripts/PostBuild.bat
@@ -24,11 +24,4 @@ xcopy /Y "%SolutionDir%BUILD\Plugins" "%SolutionDir%Publish\WindowsPrerelease\Pl
echo Copying script plugins for publish
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\Windows\Plugins\"
-xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\WindowsPrerelease\Plugins\"
-
-echo Copying GSC files for publish
-xcopy /Y "%SolutionDir%_customcallbacks.gsc" "%SolutionDir%Publish\Windows\userraw\scripts\"
-xcopy /Y "%SolutionDir%_customcallbacks.gsc" "%SolutionDir%Publish\WindowsPrerelease\userraw\scripts\"
-
-xcopy /Y "%SolutionDir%_commands.gsc" "%SolutionDir%Publish\Windows\userraw\scripts\"
-xcopy /Y "%SolutionDir%_commands.gsc" "%SolutionDir%Publish\WindowsPrerelease\userraw\scripts\"
\ No newline at end of file
+xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\WindowsPrerelease\Plugins\"
\ No newline at end of file
diff --git a/Application/BuildScripts/PostPublish.bat b/Application/BuildScripts/PostPublish.bat
index aa0064bd7..b3e398306 100644
--- a/Application/BuildScripts/PostPublish.bat
+++ b/Application/BuildScripts/PostPublish.bat
@@ -17,7 +17,7 @@ echo deleting misc files
if exist "%PublishDir%\web.config" del "%PublishDir%\web.config"
if exist "%PublishDir%\libman.json" del "%PublishDir%\libman.json"
del "%PublishDir%\*.exe"
-REM del "%PublishDir%\*.pdb"
+del "%PublishDir%\*.pdb"
echo setting up default folders
if not exist "%PublishDir%\Configuration" md "%PublishDir%\Configuration"
diff --git a/Application/Main.cs b/Application/Main.cs
index f0381394f..d94358b8c 100644
--- a/Application/Main.cs
+++ b/Application/Main.cs
@@ -1,6 +1,7 @@
using IW4MAdmin.Application.Migration;
using Microsoft.Extensions.DependencyInjection;
using SharedLibraryCore;
+using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces;
using System;
using System.Text;
@@ -11,9 +12,10 @@ namespace IW4MAdmin.Application
{
public class Program
{
- public static double Version { get; private set; } = Utilities.GetVersionAsDouble();
+ public static BuildNumber Version { get; private set; } = BuildNumber.Parse(Utilities.GetVersionAsString());
public static ApplicationManager ServerManager;
private static Task ApplicationTask;
+ private static readonly BuildNumber _fallbackVersion = BuildNumber.Parse("99.99.99.99");
///
/// entrypoint of the application
@@ -145,12 +147,12 @@ namespace IW4MAdmin.Application
var version = new API.Master.VersionInfo()
{
- CurrentVersionStable = 99.99f
+ CurrentVersionStable = _fallbackVersion
};
try
{
- version = await api.GetVersion();
+ version = await api.GetVersion(1);
}
catch (Exception e)
@@ -164,7 +166,7 @@ namespace IW4MAdmin.Application
ServerManager.Logger.WriteDebug(e.Message);
}
- if (version.CurrentVersionStable == 99.99f)
+ if (version.CurrentVersionStable == _fallbackVersion)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(loc["MANAGER_VERSION_FAIL"]);
@@ -175,16 +177,16 @@ namespace IW4MAdmin.Application
else if (version.CurrentVersionStable > Version)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString("0.0")}]");
- Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString("0.0")}]"));
+ Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString()}]");
+ Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString()}]"));
Console.ForegroundColor = ConsoleColor.Gray;
}
#else
else if (version.CurrentVersionPrerelease > Version)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
- Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.ToString("0.0")}-pr]");
- Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString("0.0")}-pr]"));
+ Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.ToString()}-pr]");
+ Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString()}-pr]"));
Console.ForegroundColor = ConsoleColor.Gray;
}
#endif
diff --git a/_commands.gsc b/GameFiles/IW4x/userraw/_commands.gsc
similarity index 100%
rename from _commands.gsc
rename to GameFiles/IW4x/userraw/_commands.gsc
diff --git a/_customcallbacks.gsc b/GameFiles/IW4x/userraw/_customcallbacks.gsc
similarity index 99%
rename from _customcallbacks.gsc
rename to GameFiles/IW4x/userraw/_customcallbacks.gsc
index 51301033d..efe725204 100644
--- a/_customcallbacks.gsc
+++ b/GameFiles/IW4x/userraw/_customcallbacks.gsc
@@ -8,7 +8,7 @@ init()
SetDvarIfUninitialized( "sv_framewaittime", 0.05 );
SetDvarIfUninitialized( "sv_additionalwaittime", 0.1 );
SetDvarIfUninitialized( "sv_maxstoredframes", 12 );
- SetDvarIfUninitialized( "sv_printradarupdates", false );
+ SetDvarIfUninitialized( "sv_printradarupdates", 0 );
SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 );
SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" );
diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln
index 0447d709f..352215090 100644
--- a/IW4MAdmin.sln
+++ b/IW4MAdmin.sln
@@ -6,8 +6,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{26E8
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C8F3945-0AEF-4949-A1F7-B18E952E50BC}"
ProjectSection(SolutionItems) = preProject
- _commands.gsc = _commands.gsc
- _customcallbacks.gsc = _customcallbacks.gsc
+ GameFiles\IW4x\userraw\_commands.gsc = GameFiles\IW4x\userraw\_commands.gsc
+ GameFiles\IW4x\userraw\_customcallbacks.gsc = GameFiles\IW4x\userraw\_customcallbacks.gsc
azure-pipelines.yml = azure-pipelines.yml
PostPublish.ps1 = PostPublish.ps1
README.md = README.md
diff --git a/SharedLibraryCore/Helpers/BuildNumber.cs b/SharedLibraryCore/Helpers/BuildNumber.cs
new file mode 100644
index 000000000..c828262c9
--- /dev/null
+++ b/SharedLibraryCore/Helpers/BuildNumber.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Linq;
+
+/*https://stackoverflow.com/questions/26581572/how-to-convert-string-into-version-in-net-3-5*/
+namespace SharedLibraryCore.Helpers
+{
+ public class BuildNumber : IComparable
+ {
+ public int Major { get; private set; }
+ public int Minor { get; private set; }
+ public int Build { get; private set; }
+ public int Revision { get; private set; }
+
+ private BuildNumber() { }
+
+ public static bool TryParse(string input, out BuildNumber buildNumber)
+ {
+ try
+ {
+ buildNumber = Parse(input);
+ return true;
+ }
+ catch
+ {
+ buildNumber = null;
+ return false;
+ }
+ }
+
+ ///
+ /// Parses a build number string into a BuildNumber class
+ ///
+ /// The build number string to parse
+ /// A new BuildNumber class set from the buildNumber string
+ /// Thrown if there are less than 2 or
+ /// more than 4 version parts to the build number
+ /// Thrown if string cannot be parsed
+ /// to a series of integers
+ /// Thrown if any version
+ /// integer is less than zero
+ public static BuildNumber Parse(string buildNumber)
+ {
+ if (buildNumber == null) throw new ArgumentNullException("buildNumber");
+
+ var versions = buildNumber
+ .Split(new[] { '.' },
+ StringSplitOptions.RemoveEmptyEntries)
+ .Select(v => v.Trim())
+ .ToList();
+
+ if (versions.Count < 2)
+ {
+ throw new ArgumentException("BuildNumber string was too short");
+ }
+
+ if (versions.Count > 4)
+ {
+ throw new ArgumentException("BuildNumber string was too long");
+ }
+
+ return new BuildNumber
+ {
+ Major = ParseVersion(versions[0]),
+ Minor = ParseVersion(versions[1]),
+ Build = versions.Count > 2 ? ParseVersion(versions[2]) : -1,
+ Revision = versions.Count > 3 ? ParseVersion(versions[3]) : -1
+ };
+ }
+
+ private static int ParseVersion(string input)
+ {
+ int version;
+
+ if (!int.TryParse(input, out version))
+ {
+ throw new FormatException(
+ "buildNumber string was not in a correct format");
+ }
+
+ if (version < 0)
+ {
+ throw new ArgumentOutOfRangeException(
+ "buildNumber",
+ "Versions must be greater than or equal to zero");
+ }
+
+ return version;
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}.{1}{2}{3}", Major, Minor,
+ Build < 0 ? "" : "." + Build,
+ Revision < 0 ? "" : "." + Revision);
+ }
+
+ public int CompareTo(object obj)
+ {
+ if (obj == null) return 1;
+ var buildNumber = obj as BuildNumber;
+ if (buildNumber == null) return 1;
+ if (ReferenceEquals(this, buildNumber)) return 0;
+
+ return (Major == buildNumber.Major)
+ ? (Minor == buildNumber.Minor)
+ ? (Build == buildNumber.Build)
+ ? Revision.CompareTo(buildNumber.Revision)
+ : Build.CompareTo(buildNumber.Build)
+ : Minor.CompareTo(buildNumber.Minor)
+ : Major.CompareTo(buildNumber.Major);
+ }
+
+ public static bool operator >(BuildNumber first, BuildNumber second)
+ {
+ return (first.CompareTo(second) > 0);
+ }
+
+ public static bool operator <(BuildNumber first, BuildNumber second)
+ {
+ return (first.CompareTo(second) < 0);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return (CompareTo(obj) == 0);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hash = 17;
+ hash = hash * 23 + Major.GetHashCode();
+ hash = hash * 23 + Minor.GetHashCode();
+ hash = hash * 23 + Build.GetHashCode();
+ hash = hash * 23 + Revision.GetHashCode();
+ return hash;
+ }
+ }
+ }
+}
diff --git a/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs b/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs
new file mode 100644
index 000000000..b5e639e4e
--- /dev/null
+++ b/SharedLibraryCore/Helpers/BuildNumberJsonConverter.cs
@@ -0,0 +1,26 @@
+using Newtonsoft.Json;
+using System;
+
+namespace SharedLibraryCore.Helpers
+{
+ ///
+ /// JSON converter for the build number
+ ///
+ public class BuildNumberJsonConverter : JsonConverter
+ {
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(string);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ return BuildNumber.Parse(reader.Value.ToString());
+ }
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ writer.WriteValue(value.ToString());
+ }
+ }
+}
diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj
index 29e977675..d3d8ddbe7 100644
--- a/WebfrontCore/WebfrontCore.csproj
+++ b/WebfrontCore/WebfrontCore.csproj
@@ -66,10 +66,13 @@
-
+
+
+
+
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index dbad2be95..6cce89f84 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -95,6 +95,12 @@ steps:
Contents: '*.dll'
TargetFolder: '$(outputFolder)\Plugins'
+- task: CopyFiles@2
+ inputs:
+ SourceFolder: '$(Build.Repository.LocalPath)\GameFiles'
+ Contents: '*.gsc'
+ TargetFolder: '$(outputFolder)\GameFiles'
+
- task: CmdLine@2
inputs:
script: 'xcopy /s /y /f wwwroot $(outputFolder)\wwwroot'
@@ -106,7 +112,7 @@ steps:
rootFolderOrFile: '$(outputFolder)'
includeRootFolder: false
archiveType: 'zip'
- archiveFile: '$(Build.ArtifactStagingDirectory)/IW4MAdmin-$(VersionInformation.Major).$(VersionInformation.Minor)-$(buildConfiguration)$(VersionInformation.Build)r$(VersionInformation.Revision)-$(Build.BuildId).zip'
+ archiveFile: '$(Build.ArtifactStagingDirectory)/IW4MAdmin-$(VersionInformation.Major).$(VersionInformation.Minor)-$(buildConfiguration)$(VersionInformation.Build)b$(Build.BuildId).zip'
replaceExistingArchive: true
- task: FtpUpload@2
@@ -130,8 +136,8 @@ steps:
action: 'create'
target: '$(Build.SourceVersion)'
tagSource: 'userSpecifiedTag'
- tag: '$(VersionInformation.Major).$(VersionInformation.Minor)-$(buildConfiguration)$(VersionInformation.Build)r$(VersionInformation.Revision)-$(Build.BuildId)'
- title: 'Version $(VersionInformation.Major).$(VersionInformation.Minor) $(buildConfiguration) $(VersionInformation.Build) Revision $(VersionInformation.Revision) Build $(Build.BuildId)'
+ tag: '$(VersionInformation.Major).$(VersionInformation.Minor)-$(buildConfiguration)$(VersionInformation.Build)b$(Build.BuildId)'
+ title: 'Version $(VersionInformation.Major).$(VersionInformation.Minor) $(buildConfiguration) Feature $(VersionInformation.Build) Build $(Build.BuildId)'
assets: '$(Build.ArtifactStagingDirectory)/*.zip'
isPreRelease: true
releaseNotesSource: 'inline'