mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-29 16:11:05 +01:00
Merge pull request #706 from tgstation/598-TestChatTagging
Chat and watchdog fixes
This commit is contained in:
@@ -222,14 +222,13 @@
|
||||
export_lock = FALSE
|
||||
|
||||
/datum/tgs_api/v4/OnReboot()
|
||||
var/json = Export(TGS4_COMM_WORLD_REBOOT)
|
||||
var/list/result = json_decode(json)
|
||||
var/list/result = Export(TGS4_COMM_WORLD_REBOOT)
|
||||
if(!result)
|
||||
return
|
||||
|
||||
//okay so the standard TGS4 proceedure is: right before rebooting change the port to whatever was sent to us in the above json's data parameter
|
||||
|
||||
var/port = json[TGS4_PARAMETER_DATA]
|
||||
var/port = result[TGS4_PARAMETER_DATA]
|
||||
if(!isnum(port))
|
||||
return //this is valid, server may just want use to reboot
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
logger.LogInformation("Detected dotnet executable at {0}", dotnetPath);
|
||||
|
||||
var rootLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
|
||||
var assemblyStoragePath = Path.Combine(rootLocation, "lib"); //always always next to watchdog
|
||||
var defaultAssemblyPath = Path.GetFullPath(Path.Combine(assemblyStoragePath, "Default"));
|
||||
#if DEBUG
|
||||
@@ -114,7 +114,7 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
using (var process = new Process())
|
||||
{
|
||||
process.StartInfo.FileName = dotnetPath;
|
||||
process.StartInfo.WorkingDirectory = Environment.CurrentDirectory; //for appsettings
|
||||
process.StartInfo.WorkingDirectory = rootLocation; //for appsettings
|
||||
|
||||
var arguments = new List<string>
|
||||
{
|
||||
@@ -138,7 +138,7 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
|
||||
logger.LogInformation("Launching host...");
|
||||
|
||||
var iShotTheSheriff = false;
|
||||
var killedHostProcess = false;
|
||||
try
|
||||
{
|
||||
process.Start();
|
||||
@@ -172,7 +172,7 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
{
|
||||
if (!process.HasExited)
|
||||
{
|
||||
iShotTheSheriff = true;
|
||||
killedHostProcess = true;
|
||||
process.Kill();
|
||||
process.WaitForExit();
|
||||
}
|
||||
@@ -206,7 +206,7 @@ namespace Tgstation.Server.Host.Watchdog
|
||||
}
|
||||
throw new Exception(String.Format(CultureInfo.InvariantCulture, "Host propagated exception: {0}", data));
|
||||
default:
|
||||
if (iShotTheSheriff)
|
||||
if (killedHostProcess)
|
||||
{
|
||||
logger.LogWarning("Watchdog forced to kill host process!");
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -122,7 +122,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
var channelsAvailable = new TaskCompletionSource<object>();
|
||||
client.Ready += () =>
|
||||
{
|
||||
channelsAvailable.SetResult(null);
|
||||
channelsAvailable.TrySetResult(null);
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
using (cancellationToken.Register(() => channelsAvailable.SetCanceled()))
|
||||
|
||||
@@ -291,16 +291,17 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
|
||||
listenTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
while (!disconnecting && client.IsConnected)
|
||||
while (!disconnecting && client.IsConnected && client.Nickname != nickname)
|
||||
{
|
||||
client.ListenOnce(true);
|
||||
if (disconnecting || !client.IsConnected)
|
||||
break;
|
||||
client.Listen(false);
|
||||
//ensure we have the correct nick
|
||||
if (client.Nickname != nickname && client.GetIrcUser(nickname) == null)
|
||||
if (client.GetIrcUser(nickname) == null)
|
||||
client.RfcNick(nickname);
|
||||
}
|
||||
client.Listen();
|
||||
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -146,7 +147,7 @@ namespace Tgstation.Server.Host.Components
|
||||
throw new JobException("Missing Repository!");
|
||||
|
||||
var repoSha = repo.Head;
|
||||
revInfo = await databaseContext.RevisionInformations.Where(x => x.CommitSha == repoSha).Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
revInfo = await databaseContext.RevisionInformations.Where(x => x.CommitSha == repoSha && x.Instance.Id == metadata.Id).Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
|
||||
if (revInfo == default)
|
||||
{
|
||||
@@ -202,7 +203,7 @@ namespace Tgstation.Server.Host.Components
|
||||
StartedBy = user
|
||||
};
|
||||
|
||||
var repositoryUpdateSuccess = false;
|
||||
string deploySha = null;
|
||||
await jobManager.RegisterOperation(repositoryUpdateJob, async (paramJob, databaseContext, progressReporter, jobCancellationToken) =>
|
||||
{
|
||||
var repositorySettingsTask = databaseContext.RepositorySettings.Where(x => x.InstanceId == metadata.Id).FirstAsync(jobCancellationToken);
|
||||
@@ -230,47 +231,140 @@ namespace Tgstation.Server.Host.Components
|
||||
return;
|
||||
}
|
||||
|
||||
var startSha = repo.Head;
|
||||
if (!repo.Tracking)
|
||||
{
|
||||
logger.LogTrace("Aborting repo update, not tracking origin!");
|
||||
deploySha = startSha;
|
||||
return;
|
||||
}
|
||||
|
||||
var repositorySettings = await repositorySettingsTask.ConfigureAwait(false);
|
||||
|
||||
|
||||
//the main point of auto update is to pull the remote
|
||||
await repo.FetchOrigin(repositorySettings.AccessUser, repositorySettings.AccessToken, NextProgressReporter(), jobCancellationToken).ConfigureAwait(false);
|
||||
|
||||
var startSha = repo.Head;
|
||||
RevisionInformation currentRevInfo = null;
|
||||
bool hasDbChanges = false;
|
||||
|
||||
Task<RevisionInformation> LoadRevInfo() => databaseContext.RevisionInformations
|
||||
.Where(x => x.CommitSha == startSha && x.Instance.Id == metadata.Id)
|
||||
.Include(x => x.ActiveTestMerges).ThenInclude(x => x.TestMerge)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
async Task UpdateRevInfo(string currentHead, bool onOrigin)
|
||||
{
|
||||
if(currentRevInfo == null)
|
||||
currentRevInfo = await LoadRevInfo().ConfigureAwait(false);
|
||||
|
||||
if (currentRevInfo == default)
|
||||
{
|
||||
logger.LogWarning(Repository.Repository.OriginTrackingErrorTemplate, currentHead);
|
||||
onOrigin = true;
|
||||
}
|
||||
|
||||
var attachedInstance = new Models.Instance
|
||||
{
|
||||
Id = metadata.Id
|
||||
};
|
||||
var oldRevInfo = currentRevInfo;
|
||||
currentRevInfo = new RevisionInformation
|
||||
{
|
||||
CommitSha = currentHead,
|
||||
OriginCommitSha = onOrigin ? currentHead : oldRevInfo.OriginCommitSha,
|
||||
Instance = attachedInstance
|
||||
};
|
||||
if (!onOrigin)
|
||||
currentRevInfo.ActiveTestMerges = new List<RevInfoTestMerge>(oldRevInfo.ActiveTestMerges);
|
||||
|
||||
databaseContext.Instances.Attach(attachedInstance);
|
||||
databaseContext.RevisionInformations.Add(currentRevInfo);
|
||||
hasDbChanges = true;
|
||||
}
|
||||
|
||||
//take appropriate auto update actions
|
||||
bool shouldSyncTracked;
|
||||
if (repositorySettings.AutoUpdatesKeepTestMerges.Value)
|
||||
{
|
||||
logger.LogTrace("Preserving test merges...");
|
||||
|
||||
var currentRevInfoTask = LoadRevInfo();
|
||||
|
||||
var result = await repo.MergeOrigin(repositorySettings.CommitterName, repositorySettings.CommitterEmail, NextProgressReporter(), jobCancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!result.HasValue)
|
||||
throw new JobException("Merge conflict while preserving test merges!");
|
||||
shouldSyncTracked = result.Value;
|
||||
|
||||
currentRevInfo = await currentRevInfoTask.ConfigureAwait(false);
|
||||
|
||||
var lastRevInfoWasOriginCommit = currentRevInfo == default || currentRevInfo.CommitSha == currentRevInfo.OriginCommitSha;
|
||||
var stillOnOrigin = result.Value && lastRevInfoWasOriginCommit;
|
||||
|
||||
var currentHead = repo.Head;
|
||||
if (currentHead != startSha)
|
||||
{
|
||||
await UpdateRevInfo(currentHead, stillOnOrigin).ConfigureAwait(false);
|
||||
shouldSyncTracked = stillOnOrigin;
|
||||
}
|
||||
else
|
||||
shouldSyncTracked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogTrace("Not preserving test merges...");
|
||||
await repo.ResetToOrigin(NextProgressReporter(), jobCancellationToken).ConfigureAwait(false);
|
||||
|
||||
var currentHead = repo.Head;
|
||||
|
||||
currentRevInfo = await databaseContext.RevisionInformations
|
||||
.Where(x => x.CommitSha == currentHead && x.Instance.Id == metadata.Id)
|
||||
.FirstOrDefaultAsync(jobCancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (currentHead != startSha && currentRevInfo != default)
|
||||
await UpdateRevInfo(currentHead, true).ConfigureAwait(false);
|
||||
|
||||
shouldSyncTracked = true;
|
||||
}
|
||||
|
||||
//synch if necessary
|
||||
if (repositorySettings.AutoUpdatesSynchronize.Value && startSha != repo.Head)
|
||||
await repo.Sychronize(repositorySettings.AccessUser, repositorySettings.AccessToken, repositorySettings.CommitterName, repositorySettings.CommitterEmail, NextProgressReporter(), shouldSyncTracked, jobCancellationToken).ConfigureAwait(false);
|
||||
{
|
||||
var pushedOrigin = await repo.Sychronize(repositorySettings.AccessUser, repositorySettings.AccessToken, repositorySettings.CommitterName, repositorySettings.CommitterEmail, NextProgressReporter(), shouldSyncTracked, jobCancellationToken).ConfigureAwait(false);
|
||||
var currentHead = repo.Head;
|
||||
if (currentHead != currentRevInfo.CommitSha)
|
||||
await UpdateRevInfo(currentHead, pushedOrigin).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if(hasDbChanges)
|
||||
try
|
||||
{
|
||||
await databaseContext.Save(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await repo.ResetToSha(startSha, progressReporter, default).ConfigureAwait(false);
|
||||
throw;
|
||||
}
|
||||
|
||||
progressReporter(5 * ProgressStep);
|
||||
deploySha = repo.Head;
|
||||
}
|
||||
repositoryUpdateSuccess = true;
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await jobManager.WaitForJobCompletion(repositoryUpdateJob, user, cancellationToken, default).ConfigureAwait(false);
|
||||
|
||||
if (!repositoryUpdateSuccess)
|
||||
if (deploySha == null)
|
||||
{
|
||||
logger.LogTrace("Aborting auto update, repository error!");
|
||||
continue;
|
||||
}
|
||||
|
||||
if(deploySha == LatestCompileJob()?.RevisionInformation.CommitSha)
|
||||
{
|
||||
logger.LogTrace("Aborting auto update, same revision as latest CompileJob");
|
||||
continue;
|
||||
}
|
||||
|
||||
//finally set up the job
|
||||
var compileProcessJob = new Job
|
||||
{
|
||||
|
||||
@@ -122,8 +122,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="synchronizeTrackedBranch">If the synchronizations should be made to the tracked reference as opposed to a temporary branch</param>
|
||||
/// <param name="progressReporter"><see cref="Action{T1}"/> to report 0-100 <see cref="int"/> progress of the operation</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param>
|
||||
/// <returns>A <see cref="Task"/> representing the running operation</returns>
|
||||
Task Sychronize(string username, string password, string committerName, string committerEmail, Action<int> progressReporter, bool synchronizeTrackedBranch, CancellationToken cancellationToken);
|
||||
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if commits were pushed to the tracked origin reference, <see langword="false"/> otherwise</returns>
|
||||
Task<bool> Sychronize(string username, string password, string committerName, string committerEmail, Action<int> progressReporter, bool synchronizeTrackedBranch, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Copies the current working directory to a given <paramref name="path"/>
|
||||
|
||||
@@ -489,7 +489,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Sychronize(string username, string password, string committerName, string committerEmail, Action<int> progressReporter, bool synchronizeTrackedBranch, CancellationToken cancellationToken)
|
||||
public async Task<bool> Sychronize(string username, string password, string committerName, string committerEmail, Action<int> progressReporter, bool synchronizeTrackedBranch, CancellationToken cancellationToken)
|
||||
{
|
||||
if (committerName == null)
|
||||
throw new ArgumentNullException(nameof(committerName));
|
||||
@@ -501,7 +501,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if (username == null && password == null)
|
||||
{
|
||||
logger.LogTrace("Not synchronizing due to lack of credentials!");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
logger.LogTrace("Begin Synchronize...");
|
||||
|
||||
@@ -526,7 +526,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if (!await eventConsumer.HandleEvent(EventType.RepoPreSynchronize, new List<string> { ioMananger.ResolvePath(".") }, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
logger.LogDebug("Aborted synchronize due to event handler response!");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -548,32 +548,35 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if (!synchronizeTrackedBranch)
|
||||
{
|
||||
await PushHeadToTemporaryBranch(username, password, FinalReporter, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var sameHead = Head == startHead;
|
||||
if (sameHead || !Tracking)
|
||||
{
|
||||
logger.LogTrace("Aborted synchronize due to {0}!", sameHead ? "lack of changes" : "not being on tracked reference");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.LogInformation("Synchronizing with origin...");
|
||||
|
||||
await Task.Factory.StartNew(() =>
|
||||
return await Task.Factory.StartNew(() =>
|
||||
{
|
||||
var remote = repository.Network.Remotes.First();
|
||||
try
|
||||
{
|
||||
repository.Network.Push(repository.Head, GeneratePushOptions(FinalReporter, username, password, cancellationToken));
|
||||
return true;
|
||||
}
|
||||
catch (NonFastForwardException)
|
||||
{
|
||||
logger.LogInformation("Synchronize aborted, non-fast forward!");
|
||||
return false;
|
||||
}
|
||||
catch (UserCancelledException)
|
||||
catch (UserCancelledException e)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
throw new InvalidOperationException("Caught UserCancelledException without cancellationToken triggering", e);
|
||||
}
|
||||
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -713,9 +713,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
await Task.WhenAny(allTask, cancelTcs.Task).ConfigureAwait(false);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
//both servers are now running, alpha is the active server, huzzah
|
||||
//both servers are now running, alpha is the active server(unless reattach), huzzah
|
||||
AlphaIsActive = doReattach ? reattachInfo?.AlphaIsActive ?? true : true;
|
||||
LastLaunchResult = alphaLrt.Result;
|
||||
(AlphaIsActive ? alphaServer : bravoServer).ClosePortOnReboot = true;
|
||||
|
||||
logger.LogInformation("Launched servers successfully");
|
||||
Running = true;
|
||||
|
||||
|
||||
@@ -53,7 +53,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
IrcChannel = api.IrcChannel,
|
||||
IsAdminChannel = api.IsAdminChannel ?? false,
|
||||
IsWatchdogChannel = api.IsWatchdogChannel ?? false,
|
||||
IsUpdatesChannel = api.IsUpdatesChannel ?? false
|
||||
IsUpdatesChannel = api.IsUpdatesChannel ?? false,
|
||||
Tag = api.Tag
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); //search every rev info because LOL SHA COLLISIONS
|
||||
|
||||
if (revisionInfo == default)
|
||||
revisionInfo = databaseContext.RevisionInformations.Local.Where(x => x.CommitSha == repoSha).FirstOrDefault();
|
||||
revisionInfo = databaseContext.RevisionInformations.Local.Where(x => x.CommitSha == repoSha && x.Instance.Id == instance.Id).FirstOrDefault();
|
||||
|
||||
var needsDbUpdate = revisionInfo == default;
|
||||
if (needsDbUpdate)
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Tgstation.Server.Host.Models
|
||||
IsAdminChannel = IsAdminChannel,
|
||||
IsWatchdogChannel = IsWatchdogChannel,
|
||||
IsUpdatesChannel = IsUpdatesChannel,
|
||||
IrcChannel = IrcChannel
|
||||
IrcChannel = IrcChannel,
|
||||
Tag = Tag
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user