Merge pull request #92 from RaidMax/enhancement/update-client-master-versioning-and-include-userraw

updates to support new master versioning
This commit is contained in:
RaidMax 2020-01-11 20:33:52 -06:00 committed by GitHub
commit dd0d7192eb
14 changed files with 253 additions and 49 deletions

1
.gitignore vendored
View File

@ -237,3 +237,4 @@ launchSettings.json
**/Master/env_master **/Master/env_master
/GameLogServer/log_env /GameLogServer/log_env
**/*.css **/*.css
/Master/master/persistence

View File

@ -1,19 +1,36 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json; using Newtonsoft.Json;
using RestEase; using SharedLibraryCore.Helpers;
namespace IW4MAdmin.Application.API.Master namespace IW4MAdmin.Application.API.Master
{ {
/// <summary>
/// Defines the structure of the IW4MAdmin instance for the master API
/// </summary>
public class ApiInstance public class ApiInstance
{ {
/// <summary>
/// Unique ID of the instance
/// </summary>
[JsonProperty("id")] [JsonProperty("id")]
public string Id { get; set; } public string Id { get; set; }
/// <summary>
/// Indicates how long the instance has been running
/// </summary>
[JsonProperty("uptime")] [JsonProperty("uptime")]
public int Uptime { get; set; } public int Uptime { get; set; }
/// <summary>
/// Specifices the version of the instance
/// </summary>
[JsonProperty("version")] [JsonProperty("version")]
public float Version { get; set; } [JsonConverter(typeof(BuildNumberJsonConverter))]
public BuildNumber Version { get; set; }
/// <summary>
/// List of servers the instance is monitoring
/// </summary>
[JsonProperty("servers")] [JsonProperty("servers")]
public List<ApiServer> Servers { get; set; } public List<ApiServer> Servers { get; set; }
} }

View File

@ -1,22 +1,21 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using RestEase; using RestEase;
using SharedLibraryCore;
namespace IW4MAdmin.Application.API.Master namespace IW4MAdmin.Application.API.Master
{ {
public class HeartbeatState /// <summary>
{ /// Defines the heartbeat functionality for IW4MAdmin
public bool Connected { get; set; } /// </summary>
public CancellationToken Token { get; set; }
}
public class Heartbeat public class Heartbeat
{ {
/// <summary>
/// Sends heartbeat to master server
/// </summary>
/// <param name="mgr"></param>
/// <param name="firstHeartbeat"></param>
/// <returns></returns>
public static async Task Send(ApplicationManager mgr, bool firstHeartbeat = false) public static async Task Send(ApplicationManager mgr, bool firstHeartbeat = false)
{ {
var api = Endpoint.Get(); var api = Endpoint.Get();
@ -35,7 +34,7 @@ namespace IW4MAdmin.Application.API.Master
{ {
Id = mgr.GetApplicationSettings().Configuration().Id, Id = mgr.GetApplicationSettings().Configuration().Id,
Uptime = (int)(DateTime.UtcNow - mgr.StartTime).TotalSeconds, Uptime = (int)(DateTime.UtcNow - mgr.StartTime).TotalSeconds,
Version = (float)Program.Version, Version = Program.Version,
Servers = mgr.Servers.Select(s => Servers = mgr.Servers.Select(s =>
new ApiServer() new ApiServer()
{ {
@ -52,14 +51,21 @@ namespace IW4MAdmin.Application.API.Master
}).ToList() }).ToList()
}; };
Response<ResultMessage> response = null;
if (firstHeartbeat) if (firstHeartbeat)
{ {
var message = await api.AddInstance(instance); response = await api.AddInstance(instance);
} }
else 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}");
} }
} }
} }

View File

@ -4,6 +4,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using RestEase; using RestEase;
using SharedLibraryCore.Helpers;
namespace IW4MAdmin.Application.API.Master namespace IW4MAdmin.Application.API.Master
{ {
@ -22,9 +23,12 @@ namespace IW4MAdmin.Application.API.Master
public class VersionInfo public class VersionInfo
{ {
[JsonProperty("current-version-stable")] [JsonProperty("current-version-stable")]
public float CurrentVersionStable { get; set; } [JsonConverter(typeof(BuildNumberJsonConverter))]
public BuildNumber CurrentVersionStable { get; set; }
[JsonProperty("current-version-prerelease")] [JsonProperty("current-version-prerelease")]
public float CurrentVersionPrerelease { get; set; } [JsonConverter(typeof(BuildNumberJsonConverter))]
public BuildNumber CurrentVersionPrerelease { get; set; }
} }
public class ResultMessage public class ResultMessage
@ -38,11 +42,14 @@ namespace IW4MAdmin.Application.API.Master
#if !DEBUG #if !DEBUG
private static readonly IMasterApi api = RestClient.For<IMasterApi>("http://api.raidmax.org:5000"); private static readonly IMasterApi api = RestClient.For<IMasterApi>("http://api.raidmax.org:5000");
#else #else
private static IMasterApi api = RestClient.For<IMasterApi>("http://127.0.0.1"); private static readonly IMasterApi api = RestClient.For<IMasterApi>("http://127.0.0.1");
#endif #endif
public static IMasterApi Get() => api; public static IMasterApi Get() => api;
} }
/// <summary>
/// Defines the capabilities of the master API
/// </summary>
[Header("User-Agent", "IW4MAdmin-RestEase")] [Header("User-Agent", "IW4MAdmin-RestEase")]
public interface IMasterApi public interface IMasterApi
{ {
@ -53,13 +60,15 @@ namespace IW4MAdmin.Application.API.Master
Task<TokenId> Authenticate([Body] AuthenticationId Id); Task<TokenId> Authenticate([Body] AuthenticationId Id);
[Post("instance/")] [Post("instance/")]
Task<ResultMessage> AddInstance([Body] ApiInstance instance); [AllowAnyStatusCode]
Task<Response<ResultMessage>> AddInstance([Body] ApiInstance instance);
[Put("instance/{id}")] [Put("instance/{id}")]
Task<ResultMessage> UpdateInstance([Path] string id, [Body] ApiInstance instance); [AllowAnyStatusCode]
Task<Response<ResultMessage>> UpdateInstance([Path] string id, [Body] ApiInstance instance);
[Get("version")] [Get("version/{apiVersion}")]
Task<VersionInfo> GetVersion(); Task<VersionInfo> GetVersion([Path] int apiVersion);
[Get("localization")] [Get("localization")]
Task<List<SharedLibraryCore.Localization.Layout>> GetLocalization(); Task<List<SharedLibraryCore.Localization.Layout>> GetLocalization();

View File

@ -25,10 +25,3 @@ xcopy /Y "%SolutionDir%BUILD\Plugins" "%SolutionDir%Publish\WindowsPrerelease\Pl
echo Copying script plugins for publish echo Copying script plugins for publish
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\Windows\Plugins\" xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\Windows\Plugins\"
xcopy /Y "%SolutionDir%Plugins\ScriptPlugins" "%SolutionDir%Publish\WindowsPrerelease\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\"

View File

@ -17,7 +17,7 @@ echo deleting misc files
if exist "%PublishDir%\web.config" del "%PublishDir%\web.config" if exist "%PublishDir%\web.config" del "%PublishDir%\web.config"
if exist "%PublishDir%\libman.json" del "%PublishDir%\libman.json" if exist "%PublishDir%\libman.json" del "%PublishDir%\libman.json"
del "%PublishDir%\*.exe" del "%PublishDir%\*.exe"
REM del "%PublishDir%\*.pdb" del "%PublishDir%\*.pdb"
echo setting up default folders echo setting up default folders
if not exist "%PublishDir%\Configuration" md "%PublishDir%\Configuration" if not exist "%PublishDir%\Configuration" md "%PublishDir%\Configuration"

View File

@ -1,6 +1,7 @@
using IW4MAdmin.Application.Migration; using IW4MAdmin.Application.Migration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using System; using System;
using System.Text; using System.Text;
@ -11,9 +12,10 @@ namespace IW4MAdmin.Application
{ {
public class Program 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; public static ApplicationManager ServerManager;
private static Task ApplicationTask; private static Task ApplicationTask;
private static readonly BuildNumber _fallbackVersion = BuildNumber.Parse("99.99.99.99");
/// <summary> /// <summary>
/// entrypoint of the application /// entrypoint of the application
@ -145,12 +147,12 @@ namespace IW4MAdmin.Application
var version = new API.Master.VersionInfo() var version = new API.Master.VersionInfo()
{ {
CurrentVersionStable = 99.99f CurrentVersionStable = _fallbackVersion
}; };
try try
{ {
version = await api.GetVersion(); version = await api.GetVersion(1);
} }
catch (Exception e) catch (Exception e)
@ -164,7 +166,7 @@ namespace IW4MAdmin.Application
ServerManager.Logger.WriteDebug(e.Message); ServerManager.Logger.WriteDebug(e.Message);
} }
if (version.CurrentVersionStable == 99.99f) if (version.CurrentVersionStable == _fallbackVersion)
{ {
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(loc["MANAGER_VERSION_FAIL"]); Console.WriteLine(loc["MANAGER_VERSION_FAIL"]);
@ -175,16 +177,16 @@ namespace IW4MAdmin.Application
else if (version.CurrentVersionStable > Version) else if (version.CurrentVersionStable > Version)
{ {
Console.ForegroundColor = ConsoleColor.DarkYellow; Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString("0.0")}]"); Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString()}]");
Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString("0.0")}]")); Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString()}]"));
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
} }
#else #else
else if (version.CurrentVersionPrerelease > Version) else if (version.CurrentVersionPrerelease > Version)
{ {
Console.ForegroundColor = ConsoleColor.DarkYellow; Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.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("0.0")}-pr]")); Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString()}-pr]"));
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
} }
#endif #endif

View File

@ -8,7 +8,7 @@ init()
SetDvarIfUninitialized( "sv_framewaittime", 0.05 ); SetDvarIfUninitialized( "sv_framewaittime", 0.05 );
SetDvarIfUninitialized( "sv_additionalwaittime", 0.1 ); SetDvarIfUninitialized( "sv_additionalwaittime", 0.1 );
SetDvarIfUninitialized( "sv_maxstoredframes", 12 ); SetDvarIfUninitialized( "sv_maxstoredframes", 12 );
SetDvarIfUninitialized( "sv_printradarupdates", false ); SetDvarIfUninitialized( "sv_printradarupdates", 0 );
SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 ); SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 );
SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" ); SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" );

View File

@ -6,8 +6,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{26E8
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C8F3945-0AEF-4949-A1F7-B18E952E50BC}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C8F3945-0AEF-4949-A1F7-B18E952E50BC}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
_commands.gsc = _commands.gsc GameFiles\IW4x\userraw\_commands.gsc = GameFiles\IW4x\userraw\_commands.gsc
_customcallbacks.gsc = _customcallbacks.gsc GameFiles\IW4x\userraw\_customcallbacks.gsc = GameFiles\IW4x\userraw\_customcallbacks.gsc
azure-pipelines.yml = azure-pipelines.yml azure-pipelines.yml = azure-pipelines.yml
PostPublish.ps1 = PostPublish.ps1 PostPublish.ps1 = PostPublish.ps1
README.md = README.md README.md = README.md

View File

@ -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;
}
}
/// <summary>
/// Parses a build number string into a BuildNumber class
/// </summary>
/// <param name="buildNumber">The build number string to parse</param>
/// <returns>A new BuildNumber class set from the buildNumber string</returns>
/// <exception cref="ArgumentException">Thrown if there are less than 2 or
/// more than 4 version parts to the build number</exception>
/// <exception cref="FormatException">Thrown if string cannot be parsed
/// to a series of integers</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown if any version
/// integer is less than zero</exception>
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;
}
}
}
}

View File

@ -0,0 +1,26 @@
using Newtonsoft.Json;
using System;
namespace SharedLibraryCore.Helpers
{
/// <summary>
/// JSON converter for the build number
/// </summary>
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());
}
}
}

View File

@ -66,10 +66,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="3.2.435" /> <PackageReference Include="BuildBundlerMinifier" Version="3.2.435" />
<PackageReference Include="BuildWebCompiler" Version="1.12.405" /> <PackageReference Include="BuildWebCompiler" Version="1.12.405" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.0" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.0.96" /> <PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.0.96" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.0" />
</ItemGroup>
<ItemGroup Condition="'$(CONFIG)'=='Debug'"> <ItemGroup Condition="'$(CONFIG)'=='Debug'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.0.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.0.0" />
</ItemGroup> </ItemGroup>

View File

@ -95,6 +95,12 @@ steps:
Contents: '*.dll' Contents: '*.dll'
TargetFolder: '$(outputFolder)\Plugins' TargetFolder: '$(outputFolder)\Plugins'
- task: CopyFiles@2
inputs:
SourceFolder: '$(Build.Repository.LocalPath)\GameFiles'
Contents: '*.gsc'
TargetFolder: '$(outputFolder)\GameFiles'
- task: CmdLine@2 - task: CmdLine@2
inputs: inputs:
script: 'xcopy /s /y /f wwwroot $(outputFolder)\wwwroot' script: 'xcopy /s /y /f wwwroot $(outputFolder)\wwwroot'
@ -106,7 +112,7 @@ steps:
rootFolderOrFile: '$(outputFolder)' rootFolderOrFile: '$(outputFolder)'
includeRootFolder: false includeRootFolder: false
archiveType: 'zip' 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 replaceExistingArchive: true
- task: FtpUpload@2 - task: FtpUpload@2
@ -130,8 +136,8 @@ steps:
action: 'create' action: 'create'
target: '$(Build.SourceVersion)' target: '$(Build.SourceVersion)'
tagSource: 'userSpecifiedTag' tagSource: 'userSpecifiedTag'
tag: '$(VersionInformation.Major).$(VersionInformation.Minor)-$(buildConfiguration)$(VersionInformation.Build)r$(VersionInformation.Revision)-$(Build.BuildId)' tag: '$(VersionInformation.Major).$(VersionInformation.Minor)-$(buildConfiguration)$(VersionInformation.Build)b$(Build.BuildId)'
title: 'Version $(VersionInformation.Major).$(VersionInformation.Minor) $(buildConfiguration) $(VersionInformation.Build) Revision $(VersionInformation.Revision) Build $(Build.BuildId)' title: 'Version $(VersionInformation.Major).$(VersionInformation.Minor) $(buildConfiguration) Feature $(VersionInformation.Build) Build $(Build.BuildId)'
assets: '$(Build.ArtifactStagingDirectory)/*.zip' assets: '$(Build.ArtifactStagingDirectory)/*.zip'
isPreRelease: true isPreRelease: true
releaseNotesSource: 'inline' releaseNotesSource: 'inline'