mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Merge pull request #31 from Squirrel/single-instance
Bring back Single Instance
This commit is contained in:
@@ -203,19 +203,15 @@ namespace Squirrel
|
||||
if (updateLock != null) return Task.FromResult(updateLock);
|
||||
|
||||
return Task.Run(() => {
|
||||
// TODO: We'll bring this back later
|
||||
var key = Utility.CalculateStreamSHA1(new MemoryStream(Encoding.UTF8.GetBytes(rootAppDirectory)));
|
||||
var theLock = Disposable.Create(() => { });
|
||||
|
||||
/*
|
||||
IDisposable theLock;
|
||||
try {
|
||||
theLock = RxApp.InUnitTestRunner() ?
|
||||
Disposable.Empty : new SingleGlobalInstance(key, 2000);
|
||||
theLock = ModeDetector.InUnitTestRunner() ?
|
||||
Disposable.Create(() => {}) : new SingleGlobalInstance(key, 2000);
|
||||
} catch (TimeoutException) {
|
||||
throw new TimeoutException("Couldn't acquire update lock, another instance may be running updates");
|
||||
}
|
||||
*/
|
||||
|
||||
var ret = Disposable.Create(() => {
|
||||
theLock.Dispose();
|
||||
|
||||
@@ -312,42 +312,60 @@ namespace Squirrel
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public sealed class SingleGlobalInstance : IDisposable
|
||||
{
|
||||
readonly static object gate = 42;
|
||||
readonly ConcurrentExclusiveSchedulerPair lockScheduler =
|
||||
new ConcurrentExclusiveSchedulerPair();
|
||||
|
||||
bool HasHandle = false;
|
||||
Mutex mutex;
|
||||
EventLoopScheduler lockScheduler = new EventLoopScheduler();
|
||||
|
||||
public SingleGlobalInstance(string key, int timeOut)
|
||||
{
|
||||
if (RxApp.InUnitTestRunner()) {
|
||||
HasHandle = Observable.Start(() => Monitor.TryEnter(gate, timeOut), lockScheduler).First();
|
||||
if (ModeDetector.InUnitTestRunner()) {
|
||||
HasHandle = runExclusive(() => Monitor.TryEnter(gate, timeOut)).Result;
|
||||
|
||||
if (HasHandle == false)
|
||||
if (HasHandle == false) {
|
||||
throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
initMutex(key);
|
||||
try
|
||||
{
|
||||
if (timeOut <= 0)
|
||||
HasHandle = Observable.Start(() => mutex.WaitOne(Timeout.Infinite, false), lockScheduler).First();
|
||||
else
|
||||
HasHandle = Observable.Start(() => mutex.WaitOne(timeOut, false), lockScheduler).First();
|
||||
try {
|
||||
if (timeOut <= 0) {
|
||||
HasHandle = runExclusive(() => mutex.WaitOne(Timeout.Infinite, false)).Result;
|
||||
} else {
|
||||
HasHandle = runExclusive(() => mutex.WaitOne(timeOut, false)).Result;
|
||||
}
|
||||
|
||||
if (HasHandle == false)
|
||||
if (HasHandle == false) {
|
||||
throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
|
||||
}
|
||||
catch (AbandonedMutexException)
|
||||
{
|
||||
}
|
||||
} catch (AbandonedMutexException) {
|
||||
HasHandle = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void initMutex(string key)
|
||||
public void Dispose()
|
||||
{
|
||||
if (HasHandle && ModeDetector.InUnitTestRunner()) {
|
||||
runExclusive(() => Monitor.Exit(gate)).Wait();
|
||||
HasHandle = false;
|
||||
}
|
||||
|
||||
if (HasHandle && mutex != null) {
|
||||
runExclusive(() => mutex.ReleaseMutex()).Wait();
|
||||
HasHandle = false;
|
||||
}
|
||||
|
||||
lockScheduler.Complete();
|
||||
lockScheduler.Completion.Wait();
|
||||
}
|
||||
|
||||
void initMutex(string key)
|
||||
{
|
||||
string mutexId = string.Format("Global\\{{{0}}}", key);
|
||||
mutex = new Mutex(false, mutexId);
|
||||
@@ -358,22 +376,16 @@ namespace Squirrel
|
||||
mutex.SetAccessControl(securitySettings);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
Task runExclusive(Action block, CancellationToken token = default(CancellationToken))
|
||||
{
|
||||
if (HasHandle && RxApp.InUnitTestRunner()) {
|
||||
Observable.Start(() => Monitor.Exit(gate), lockScheduler).First();
|
||||
HasHandle = false;
|
||||
}
|
||||
return Task.Factory.StartNew(block, token, TaskCreationOptions.None, lockScheduler.ExclusiveScheduler);
|
||||
}
|
||||
|
||||
if (HasHandle && mutex != null) {
|
||||
Observable.Start(() => mutex.ReleaseMutex(), lockScheduler).First();
|
||||
HasHandle = false;
|
||||
}
|
||||
|
||||
lockScheduler.Dispose();
|
||||
Task<T> runExclusive<T>(Func<T> block, CancellationToken token = default(CancellationToken))
|
||||
{
|
||||
return Task.Factory.StartNew(block, token, TaskCreationOptions.None, lockScheduler.ExclusiveScheduler);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public static class Disposable
|
||||
{
|
||||
|
||||
@@ -241,9 +241,10 @@ namespace Squirrel.Tests
|
||||
public async Task WhenUrlResultsInWebExceptionReturnNull()
|
||||
{
|
||||
// This should result in a WebException (which gets caught) unless you can actually access http://lol
|
||||
var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net45);
|
||||
var updateInfo = await fixture.CheckForUpdate();
|
||||
Assert.Null(updateInfo);
|
||||
using (var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net45)) {
|
||||
var updateInfo = await fixture.CheckForUpdate();
|
||||
Assert.Null(updateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -255,8 +256,9 @@ namespace Squirrel.Tests
|
||||
input = Environment.ExpandEnvironmentVariables(input);
|
||||
var expected = expectedVersion != null ? new Version(expectedVersion) : default(Version);
|
||||
|
||||
var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net45);
|
||||
Assert.Equal(expected, fixture.CurrentlyInstalledVersion(input));
|
||||
using (var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net45)) {
|
||||
Assert.Equal(expected, fixture.CurrentlyInstalledVersion(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user