diff --git a/src/Tgstation.Server.Api/Models/Instance.cs b/src/Tgstation.Server.Api/Models/Instance.cs
index 22bd31e1be..74910fdf68 100644
--- a/src/Tgstation.Server.Api/Models/Instance.cs
+++ b/src/Tgstation.Server.Api/Models/Instance.cs
@@ -41,6 +41,12 @@ namespace Tgstation.Server.Api.Models
[Permissions(WriteRight = InstanceManagerRights.SetConfiguration)]
public bool ConfigurationAllowed { get; set; }
+ ///
+ /// The time interval in minutes the repository is automatically pulled and compiles
+ ///
+ [Permissions(WriteRight = InstanceManagerRights.SetAutoUpdate)]
+ public int? AutoUpdateInterval { get; set; }
+
///
public Instance CloneMetadata() => new Instance
{
diff --git a/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs b/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs
index 2e07ee683a..154167ec82 100644
--- a/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/DreamMakerSettings.cs
@@ -8,12 +8,6 @@ namespace Tgstation.Server.Api.Models.Internal
[Model(RightsType.DreamMaker, ReadRight = DreamMakerRights.Read, CanCrud = true, RequiresInstance = true)]
public class DreamMakerSettings
{
- ///
- /// How often the automatically compiles in minutes
- ///
- [Permissions(WriteRight = DreamMakerRights.SetAutoCompile)]
- public int? AutoCompileInterval { get; set; }
-
///
/// The .dme file tries to compile with without the extension
///
diff --git a/src/Tgstation.Server.Api/Models/Internal/RepositorySettings.cs b/src/Tgstation.Server.Api/Models/Internal/RepositorySettings.cs
index 35a560f7da..5893293fa7 100644
--- a/src/Tgstation.Server.Api/Models/Internal/RepositorySettings.cs
+++ b/src/Tgstation.Server.Api/Models/Internal/RepositorySettings.cs
@@ -46,11 +46,5 @@ namespace Tgstation.Server.Api.Models.Internal
///
[Permissions(WriteRight = RepositoryRights.ChangeTestMergeCommits)]
public bool ShowTestMergeCommitters { get; set; }
-
- ///
- /// How often the automatically updates in minutes
- ///
- [Permissions(WriteRight = RepositoryRights.ChangeAutoUpdate)]
- public int? AutoUpdateInterval { get; set; }
}
}
diff --git a/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs b/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs
index 661530c95a..bce942c165 100644
--- a/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs
+++ b/src/Tgstation.Server.Api/Rights/DreamMakerRights.cs
@@ -25,12 +25,8 @@ namespace Tgstation.Server.Api.Rights
///
CancelCompile = 4,
///
- /// User may modify
- ///
- SetAutoCompile = 8,
- ///
/// User may modify
///
- SetDme = 16
+ SetDme = 8
}
}
diff --git a/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs b/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs
index 106eaa1ad1..fbec63f9d5 100644
--- a/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs
+++ b/src/Tgstation.Server.Api/Rights/InstanceManagerRights.cs
@@ -43,6 +43,10 @@ namespace Tgstation.Server.Api.Rights
///
/// User can change
///
- SetConfiguration = 128
+ SetConfiguration = 128,
+ ///
+ /// User can change
+ ///
+ SetAutoUpdate = 256
}
}
diff --git a/src/Tgstation.Server.Api/Rights/RepositoryRights.cs b/src/Tgstation.Server.Api/Rights/RepositoryRights.cs
index c418507036..23703fd446 100644
--- a/src/Tgstation.Server.Api/Rights/RepositoryRights.cs
+++ b/src/Tgstation.Server.Api/Rights/RepositoryRights.cs
@@ -37,20 +37,16 @@ namespace Tgstation.Server.Api.Rights
///
ChangeTestMergeCommits = 64,
///
- /// User may change
- ///
- ChangeAutoUpdate = 128,
- ///
/// User may read and change and
///
- ChangeCredentials = 256,
+ ChangeCredentials = 128,
///
/// User may set to another git reference (not a SHA)
///
- SetReference = 512,
+ SetReference = 256,
///
/// User may read all fields in the with the exception of
///
- Read = 1024,
+ Read = 512,
}
}
diff --git a/src/Tgstation.Server.Host/Components/DmbFactory.cs b/src/Tgstation.Server.Host/Components/DmbFactory.cs
index cce071c63f..9d21f4747f 100644
--- a/src/Tgstation.Server.Host/Components/DmbFactory.cs
+++ b/src/Tgstation.Server.Host/Components/DmbFactory.cs
@@ -14,9 +14,9 @@ namespace Tgstation.Server.Host.Components
sealed class DmbFactory : IDmbFactory, ICompileJobConsumer
{
///
- /// The for the
+ /// The for the
///
- readonly IDatabaseContext databaseContext;
+ readonly IDatabaseContextFactory databaseContextFactory;
///
/// The for the
///
@@ -42,11 +42,11 @@ namespace Tgstation.Server.Host.Components
///
/// Construct a
///
- /// The value of
+ /// The value of
/// The value of
- public DmbFactory(IDatabaseContext databaseContext, IIOManager ioManager)
+ public DmbFactory(IDatabaseContextFactory databaseContextFactory, IIOManager ioManager)
{
- this.databaseContext = databaseContext ?? throw new ArgumentNullException(nameof(databaseContext));
+ this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
cleanupCts = new CancellationTokenSource();
@@ -117,16 +117,16 @@ namespace Tgstation.Server.Host.Components
}
///
- public async Task StartAsync(CancellationToken cancellationToken)
+ public Task StartAsync(CancellationToken cancellationToken) => databaseContextFactory.UseContext(async (db) =>
{
- var cj = await databaseContext.CompileJobs.OrderByDescending(x => x.Job.StoppedAt).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+ var cj = await db.CompileJobs.OrderByDescending(x => x.Job.StoppedAt).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
if (cj == default(CompileJob))
return;
LoadCompileJob(cj);
//delete all other compile jobs
var directories = await ioManager.GetDirectories(".", cancellationToken).ConfigureAwait(false);
await Task.WhenAll(directories.Where(x => x != cj.Job.ToString()).Select(x => ioManager.DeleteDirectory(x, cancellationToken))).ConfigureAwait(false);
- }
+ });
///
public async Task StopAsync(CancellationToken cancellationToken)
diff --git a/src/Tgstation.Server.Host/Components/DreamMaker.cs b/src/Tgstation.Server.Host/Components/DreamMaker.cs
index 441b45de40..f70df87e5e 100644
--- a/src/Tgstation.Server.Host/Components/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/DreamMaker.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
+using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -23,8 +24,13 @@ namespace Tgstation.Server.Host.Components
/// Name of the secondary directory used for compilation
///
public const string BDirectoryName = "B";
+ ///
+ /// Extension for .dmbs
+ ///
public const string DmbExtension = ".dmb";
-
+ ///
+ /// Extension for .dmes
+ ///
const string DmeExtension = ".dme";
///
@@ -61,6 +67,7 @@ namespace Tgstation.Server.Host.Components
/// The value of
/// The value of
/// The value of
+ ///
public DreamMaker(IIOManager ioManager, IConfiguration configuration, IDreamDaemonExecutor dreamDaemonExecutor, IByond byond, IInterop interop, ICompileJobConsumer compileJobConsumer)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
@@ -202,12 +209,12 @@ namespace Tgstation.Server.Host.Components
}
///
- public async Task Compile(string dmeName, IRepository repository, CancellationToken cancellationToken)
+ public async Task Compile(string projectName, IRepository repository, CancellationToken cancellationToken)
{
var job = new Host.Models.CompileJob
{
DirectoryName = Guid.NewGuid(),
- DmeName = dmeName
+ DmeName = projectName
};
await ioManager.CreateDirectory(job.DirectoryName.ToString(), cancellationToken).ConfigureAwait(false);
var dirA = ioManager.ConcatPath(job.DirectoryName.ToString(), ADirectoryName);
@@ -229,6 +236,16 @@ namespace Tgstation.Server.Host.Components
using (repository)
await repository.CopyTo(fullDirA, cancellationToken).ConfigureAwait(false);
+ if (job.DmeName == null)
+ {
+ job.DmeName = (await ioManager.GetFilesWithExtension(dirA, DmeExtension, cancellationToken).ConfigureAwait(false)).FirstOrDefault();
+ if (job.DmeName == default)
+ {
+ job.Output = "Unable to find any .dme!";
+ return job;
+ }
+ }
+
await ModifyDme(job, cancellationToken).ConfigureAwait(false);
//run compiler, verify api
@@ -263,18 +280,5 @@ namespace Tgstation.Server.Host.Components
throw;
}
}
-
- ///
- public Task StartAsync(CancellationToken cancellationToken)
- {
- //THIS IS FOR AUTO COMPILE INTERVAL STUFF, STOP TRYING TO REMOVE IT
- throw new NotImplementedException();
- }
-
- ///
- public Task StopAsync(CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
}
}
diff --git a/src/Tgstation.Server.Host/Components/IDreamMaker.cs b/src/Tgstation.Server.Host/Components/IDreamMaker.cs
index 3e7c52eca5..215c1582ac 100644
--- a/src/Tgstation.Server.Host/Components/IDreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/IDreamMaker.cs
@@ -8,15 +8,15 @@ namespace Tgstation.Server.Host.Components
///
/// For managing the compiler
///
- interface IDreamMaker : IHostedService
+ interface IDreamMaker
{
///
/// Starts a compile
///
- /// The .dme file to use without the extension
+ /// The name of the .dme to compile without the extension
/// The to copy from
/// The for the operation
/// A resulting in the partially populated for the operation. In particular, note the field will only have it's field populated
- Task Compile(string dmeName, IRepository repository, CancellationToken cancellationToken);
+ Task Compile(string projectName, IRepository repository, CancellationToken cancellationToken);
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Components/IInstance.cs b/src/Tgstation.Server.Host/Components/IInstance.cs
index 3735a5cc13..8105873fc5 100644
--- a/src/Tgstation.Server.Host/Components/IInstance.cs
+++ b/src/Tgstation.Server.Host/Components/IInstance.cs
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Hosting;
+using System.Threading.Tasks;
namespace Tgstation.Server.Host.Components
{
@@ -19,5 +20,7 @@ namespace Tgstation.Server.Host.Components
Api.Models.Instance GetMetadata();
void Rename(string newName);
+
+ Task SetAutoUpdateInterval(int? newInterval);
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs
index 7dfd5a667d..5e4e3934f8 100644
--- a/src/Tgstation.Server.Host/Components/IInstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/IInstanceFactory.cs
@@ -1,4 +1,4 @@
-using Tgstation.Server.Host.Models;
+using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components
{
@@ -11,8 +11,8 @@ namespace Tgstation.Server.Host.Components
/// Create an
///
/// The
- /// The for the operation
+ /// The for the operation
/// A new
- IInstance CreateInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext);
+ IInstance CreateInstance(Host.Models.Instance metadata, IDatabaseContextFactory databaseContextFactory);
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Components/IRepositoryManager.cs b/src/Tgstation.Server.Host/Components/IRepositoryManager.cs
index f778e46798..f7db73a8d7 100644
--- a/src/Tgstation.Server.Host/Components/IRepositoryManager.cs
+++ b/src/Tgstation.Server.Host/Components/IRepositoryManager.cs
@@ -7,8 +7,8 @@ namespace Tgstation.Server.Host.Components
///
/// Factory for creating and loading s
///
- interface IRepositoryManager : IHostedService
- {
+ interface IRepositoryManager
+ {
///
/// Attempt to load the from the default location
///
@@ -24,12 +24,5 @@ namespace Tgstation.Server.Host.Components
/// The for the operation
/// The newly cloned
Task CloneRepository(string url, string accessString, CancellationToken cancellationToken);
-
- ///
- /// Change the interval in minutes at which the repository auto updates
- ///
- /// The new interval in minutes or to disable the auto update
- /// A representing the running operation
- Task SetAutoUpdateInterval(int? newInterval);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Instance.cs b/src/Tgstation.Server.Host/Components/Instance.cs
index 475c12e3d4..aea3891519 100644
--- a/src/Tgstation.Server.Host/Components/Instance.cs
+++ b/src/Tgstation.Server.Host/Components/Instance.cs
@@ -1,28 +1,58 @@
-using System;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Tgstation.Server.Host.Core;
namespace Tgstation.Server.Host.Components
{
- sealed class Instance : IInstance
+ ///
+ sealed class Instance : IInstance, IDisposable
{
+ ///
public IRepositoryManager RepositoryManager { get; }
+ ///
public IByond Byond { get; }
+ ///
public IDreamMaker DreamMaker { get; }
+ ///
public IDreamDaemon DreamDaemon { get; }
+ ///
public IChat Chat { get; }
+ ///
public IConfiguration Configuration { get; }
+ ///
+ /// The for the
+ ///
readonly ICompileJobConsumer compileJobConsumer;
+
+ ///
+ /// The for the
+ ///
+ readonly IDatabaseContextFactory databaseContextFactory;
+ ///
+ /// The for the
+ ///
readonly Api.Models.Instance metadata;
- public Instance(Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByond byond, IDreamMaker dreamMaker, IDreamDaemon dreamDaemon, IChat chat, IConfiguration configuration, ICompileJobConsumer compileJobConsumer)
+ ///
+ /// The auto update
+ ///
+ Task timerTask;
+ ///
+ /// for
+ ///
+ CancellationTokenSource timerCts;
+
+ public Instance(Api.Models.Instance metadata, IRepositoryManager repositoryManager, IByond byond, IDreamMaker dreamMaker, IDreamDaemon dreamDaemon, IChat chat, IConfiguration configuration, ICompileJobConsumer compileJobConsumer, IDatabaseContextFactory databaseContextFactory)
{
this.metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
RepositoryManager = repositoryManager ?? throw new ArgumentNullException(nameof(repositoryManager));
@@ -32,10 +62,50 @@ namespace Tgstation.Server.Host.Components
Chat = chat ?? throw new ArgumentNullException(nameof(chat));
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
this.compileJobConsumer = compileJobConsumer ?? throw new ArgumentNullException(nameof(compileJobConsumer));
+ this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
}
+ ///
+ public void Dispose() => timerCts?.Dispose();
+
+ ///
+ /// Pull the repository and compile for every set of given
+ ///
+ /// How many minutes the operation should repeat. Does not include running time
+ /// The for the operation
+ /// A representing the running operation
+ async Task TimerLoop(int minutes, CancellationToken cancellationToken)
+ {
+ try
+ {
+ while (true)
+ {
+ await Task.Delay(new TimeSpan(0, minutes, 0), cancellationToken).ConfigureAwait(false);
+
+ string accessToken = null, projectName = null;
+ var dbTask = databaseContextFactory.UseContext(async (db) =>
+ {
+ var instanceQuery = db.Instances.Where(x => x.Id == metadata.Id);
+ var projectNameTask = instanceQuery.Select(x => x.DreamMakerSettings.ProjectName).FirstOrDefaultAsync(cancellationToken);
+ accessToken = await instanceQuery.Select(x => x.RepositorySettings.AccessToken).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+ projectName = await projectNameTask.ConfigureAwait(false);
+ });
+ using (var repo = await RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
+ {
+ await dbTask.ConfigureAwait(false);
+ await repo.FetchOrigin(accessToken, cancellationToken).ConfigureAwait(false);
+ await repo.ResetToOrigin(cancellationToken).ConfigureAwait(false);
+ await DreamMaker.Compile(projectName, repo, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ }
+ catch (OperationCanceledException) { }
+ }
+
+ ///
public Api.Models.Instance GetMetadata() => metadata.CloneMetadata();
+ ///
public void Rename(string newName)
{
if (String.IsNullOrWhiteSpace(newName))
@@ -43,8 +113,38 @@ namespace Tgstation.Server.Host.Components
metadata.Name = newName;
}
- public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(RepositoryManager.StartAsync(cancellationToken), DreamDaemon.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), compileJobConsumer.StartAsync(cancellationToken), DreamMaker.StartAsync(cancellationToken));
+ ///
+ public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(SetAutoUpdateInterval(metadata.AutoUpdateInterval), DreamDaemon.StartAsync(cancellationToken), Chat.StartAsync(cancellationToken), compileJobConsumer.StartAsync(cancellationToken));
- public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(RepositoryManager.StopAsync(cancellationToken), DreamDaemon.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken), compileJobConsumer.StopAsync(cancellationToken), DreamMaker.StopAsync(cancellationToken));
+ ///
+ public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(SetAutoUpdateInterval(null), DreamDaemon.StopAsync(cancellationToken), Chat.StopAsync(cancellationToken), compileJobConsumer.StopAsync(cancellationToken));
+
+ ///
+ public async Task SetAutoUpdateInterval(int? newInterval)
+ {
+ Task toWait;
+ lock (this)
+ {
+ if (timerTask != null)
+ {
+ timerCts.Cancel();
+ toWait = timerTask;
+ }
+ else
+ toWait = Task.CompletedTask;
+ }
+ await toWait.ConfigureAwait(false);
+ if (!newInterval.HasValue)
+ return;
+ lock (this)
+ {
+ //race condition, just quit
+ if (timerTask != null)
+ return;
+ timerCts?.Dispose();
+ timerCts = new CancellationTokenSource();
+ timerTask = TimerLoop(newInterval.Value, timerCts.Token);
+ }
+ }
}
}
diff --git a/src/Tgstation.Server.Host/Components/InstanceFactory.cs b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
index ed4955194e..00767fcabd 100644
--- a/src/Tgstation.Server.Host/Components/InstanceFactory.cs
+++ b/src/Tgstation.Server.Host/Components/InstanceFactory.cs
@@ -1,6 +1,5 @@
using System;
using Tgstation.Server.Host.Core;
-using Tgstation.Server.Host.Models;
namespace Tgstation.Server.Host.Components
{
@@ -19,7 +18,7 @@ namespace Tgstation.Server.Host.Components
public InstanceFactory(IIOManager ioManager) => this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
///
- public IInstance CreateInstance(Host.Models.Instance metadata, IDatabaseContext databaseContext)
+ public IInstance CreateInstance(Host.Models.Instance metadata, IDatabaseContextFactory databaseContextFactory)
{
//Create the ioManager for the instance
@@ -32,7 +31,7 @@ namespace Tgstation.Server.Host.Components
var configurationIoManager = new ResolvingIOManager(instanceIoManager, "Configuration");
var codeModificationsIoMananger = new ResolvingIOManager(instanceIoManager, "CodeModifications");
- var dmbFactory = new DmbFactory(databaseContext, gameIoManager);
+ var dmbFactory = new DmbFactory(databaseContextFactory, gameIoManager);
diff --git a/src/Tgstation.Server.Host/Components/RepositoryManager.cs b/src/Tgstation.Server.Host/Components/RepositoryManager.cs
index 5982887adb..ffb8cf1049 100644
--- a/src/Tgstation.Server.Host/Components/RepositoryManager.cs
+++ b/src/Tgstation.Server.Host/Components/RepositoryManager.cs
@@ -25,16 +25,6 @@ namespace Tgstation.Server.Host.Components
///
readonly SemaphoreSlim semaphore;
- ///
- /// for
- ///
- CancellationTokenSource timerCancellationTokenSource;
-
- ///
- /// Represents the running update timer if any
- ///
- Task currentTimerTask;
-
///
/// Construct a
///
@@ -48,49 +38,7 @@ namespace Tgstation.Server.Host.Components
}
///
- public void Dispose()
- {
- timerCancellationTokenSource?.Dispose();
- semaphore.Dispose();
- }
-
- ///
- /// Stops and joins it
- ///
- /// A representing the running operation
- async Task StopTimer()
- {
- if (currentTimerTask == null)
- return;
- timerCancellationTokenSource.Cancel();
- await currentTimerTask.ConfigureAwait(false);
- currentTimerTask = null;
- }
-
- ///
- /// Asyncronously fetch and reset the current branch for each given amount of
- ///
- /// The delay of the timer
- /// The accessString to use for fetch operations
- /// The for the operation
- /// A representing the running operation
- async Task TimerLoop(int minutes, string accessString, CancellationToken cancellationToken)
- {
- try
- {
- while (true)
- {
- await Task.Delay(TimeSpan.FromMinutes(minutes), cancellationToken).ConfigureAwait(false);
- using (var repo = await LoadRepository(cancellationToken).ConfigureAwait(false))
- {
- //TODO: Find the unauthorized exception, catch it, and log it
- await repo.FetchOrigin(accessString, cancellationToken).ConfigureAwait(false);
- await repo.ResetToOrigin(cancellationToken).ConfigureAwait(false);
- }
- }
- }
- catch (OperationCanceledException) { }
- }
+ public void Dispose() => semaphore.Dispose();
///
public async Task CloneRepository(string url, string accessString, CancellationToken cancellationToken)
@@ -134,33 +82,5 @@ namespace Tgstation.Server.Host.Components
localSemaphore = null;
});
}
-
- ///
- public async Task SetAutoUpdateInterval(int? newInterval)
- {
- await StopTimer().ConfigureAwait(false);
- if (!newInterval.HasValue)
- return;
-
- string accessString = null;
-
- if (timerCancellationTokenSource != null)
- timerCancellationTokenSource.Dispose();
- timerCancellationTokenSource = new CancellationTokenSource();
-
- currentTimerTask = TimerLoop(repositorySettings.AutoUpdateInterval.Value, accessString, timerCancellationTokenSource.Token);
- }
-
- ///
- public Task StartAsync(CancellationToken cancellationToken) => SetAutoUpdateInterval(repositorySettings.AutoUpdateInterval);
-
- ///
- public async Task StopAsync(CancellationToken cancellationToken)
- {
- var timerStopTask = StopTimer();
- var tcs = new TaskCompletionSource