mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-09-23 07:25:16 +00:00
Merge pull request #908 from softworkz/submit_api_consolidation
Mitigate race conditions and simplify API invocations
This commit is contained in:
177
src/ElectronNET.API/API/ApiBase.cs
Normal file
177
src/ElectronNET.API/API/ApiBase.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
namespace ElectronNET.API
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using ElectronNET.Common;
|
||||
|
||||
public abstract class ApiBase
|
||||
{
|
||||
internal const int PropertyTimeout = 1000;
|
||||
|
||||
private readonly string objectName;
|
||||
private readonly ConcurrentDictionary<string, PropertyGetter> propertyGetters = new ConcurrentDictionary<string, PropertyGetter>();
|
||||
private readonly ConcurrentDictionary<string, string> propertyEventNames = new ConcurrentDictionary<string, string>();
|
||||
private readonly ConcurrentDictionary<string, string> propertyMessageNames = new ConcurrentDictionary<string, string>();
|
||||
private readonly ConcurrentDictionary<string, string> methodMessageNames = new ConcurrentDictionary<string, string>();
|
||||
private readonly object objLock = new object();
|
||||
|
||||
public virtual int Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ReSharper disable once ValueParameterNotUsed
|
||||
protected set
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract string SocketEventCompleteSuffix { get; }
|
||||
|
||||
protected ApiBase()
|
||||
{
|
||||
this.objectName = this.GetType().Name.LowerFirst();
|
||||
}
|
||||
|
||||
protected void CallMethod0([CallerMemberName] string callerName = null)
|
||||
{
|
||||
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
|
||||
if (this.Id >= 0)
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, this.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void CallMethod1(object val1, [CallerMemberName] string callerName = null)
|
||||
{
|
||||
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
|
||||
if (this.Id >= 0)
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, this.Id, val1);
|
||||
}
|
||||
else
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, val1);
|
||||
}
|
||||
}
|
||||
|
||||
protected void CallMethod2(object val1, object val2, [CallerMemberName] string callerName = null)
|
||||
{
|
||||
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
|
||||
if (this.Id >= 0)
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2);
|
||||
}
|
||||
else
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, val1, val2);
|
||||
}
|
||||
}
|
||||
|
||||
protected void CallMethod3(object val1, object val2, object val3, [CallerMemberName] string callerName = null)
|
||||
{
|
||||
var messageName = this.methodMessageNames.GetOrAdd(callerName, s => this.objectName + s);
|
||||
if (this.Id >= 0)
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, this.Id, val1, val2, val3);
|
||||
}
|
||||
else
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, val1, val2, val3);
|
||||
}
|
||||
}
|
||||
|
||||
protected Task<T> GetPropertyAsync<T>([CallerMemberName] string callerName = null)
|
||||
{
|
||||
Debug.Assert(callerName != null, nameof(callerName) + " != null");
|
||||
|
||||
lock (this.objLock)
|
||||
{
|
||||
return this.propertyGetters.GetOrAdd(callerName, _ =>
|
||||
{
|
||||
var getter = new PropertyGetter<T>(this, callerName, PropertyTimeout);
|
||||
|
||||
getter.Task<T>().ContinueWith(_ =>
|
||||
{
|
||||
lock (this.objLock)
|
||||
{
|
||||
return this.propertyGetters.TryRemove(callerName, out var _);
|
||||
}
|
||||
});
|
||||
|
||||
return getter;
|
||||
}).Task<T>();
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class PropertyGetter
|
||||
{
|
||||
public abstract Task<T> Task<T>();
|
||||
}
|
||||
|
||||
internal class PropertyGetter<T> : PropertyGetter
|
||||
{
|
||||
private readonly Task<T> tcsTask;
|
||||
private TaskCompletionSource<T> tcs;
|
||||
|
||||
public PropertyGetter(ApiBase apiBase, string callerName, int timeoutMs)
|
||||
{
|
||||
this.tcs = new TaskCompletionSource<T>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
this.tcsTask = this.tcs.Task;
|
||||
|
||||
var eventName = apiBase.propertyEventNames.GetOrAdd(callerName, s => $"{apiBase.objectName}-{s.StripAsync().LowerFirst()}{apiBase.SocketEventCompleteSuffix}");
|
||||
var messageName = apiBase.propertyMessageNames.GetOrAdd(callerName, s => apiBase.objectName + s.StripAsync());
|
||||
|
||||
BridgeConnector.Socket.On<T>(eventName, (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off(eventName);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
this.tcs?.SetResult(result);
|
||||
this.tcs = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (apiBase.Id >= 0)
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName, apiBase.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
BridgeConnector.Socket.Emit(messageName);
|
||||
}
|
||||
|
||||
System.Threading.Tasks.Task.Delay(ApiBase.PropertyTimeout).ContinueWith(_ =>
|
||||
{
|
||||
if (this.tcs != null)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (this.tcs != null)
|
||||
{
|
||||
var ex = new TimeoutException($"No response after {timeoutMs:D}ms trying to retrieve value {apiBase.objectName}.{callerName}()");
|
||||
this.tcs.TrySetException(ex);
|
||||
this.tcs = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override Task<T1> Task<T1>()
|
||||
{
|
||||
return this.tcsTask as Task<T1>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,10 @@ namespace ElectronNET.API
|
||||
/// <summary>
|
||||
/// Control your application's event lifecycle.
|
||||
/// </summary>
|
||||
public sealed class App
|
||||
public sealed class App : ApiBase
|
||||
{
|
||||
protected override string SocketEventCompleteSuffix => "Completed";
|
||||
|
||||
/// <summary>
|
||||
/// Emitted when all windows have been closed.
|
||||
/// <para/>
|
||||
@@ -372,20 +374,7 @@ namespace ElectronNET.API
|
||||
{
|
||||
get
|
||||
{
|
||||
return Task.Run<string>(() =>
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
|
||||
BridgeConnector.Socket.On("appGetNameCompleted", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetNameCompleted");
|
||||
taskCompletionSource.SetResult((string)result);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetName");
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
});
|
||||
return this.GetPropertyAsync<string>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,7 +419,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Quit()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appQuit");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -440,7 +429,7 @@ namespace ElectronNET.API
|
||||
/// <param name="exitCode">Exits immediately with exitCode. exitCode defaults to 0.</param>
|
||||
public void Exit(int exitCode = 0)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appExit", exitCode);
|
||||
this.CallMethod1(exitCode);
|
||||
}
|
||||
|
||||
public void DisposeSocket()
|
||||
@@ -460,7 +449,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Relaunch()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appRelaunch");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -478,7 +467,7 @@ namespace ElectronNET.API
|
||||
/// <param name="relaunchOptions">Options for the relaunch.</param>
|
||||
public void Relaunch(RelaunchOptions relaunchOptions)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appRelaunch", JObject.FromObject(relaunchOptions, _jsonSerializer));
|
||||
this.CallMethod1(JObject.FromObject(relaunchOptions, _jsonSerializer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -487,7 +476,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Focus()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appFocus");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -498,7 +487,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Focus(FocusOptions focusOptions)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appFocus", JObject.FromObject(focusOptions, _jsonSerializer));
|
||||
this.CallMethod1(JObject.FromObject(focusOptions, _jsonSerializer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -506,7 +495,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Hide()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appHide");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -514,7 +503,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void Show()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appShow");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -523,21 +512,7 @@ namespace ElectronNET.API
|
||||
public async Task<string> GetAppPathAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetAppPathCompleted", (path) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetAppPathCompleted");
|
||||
taskCompletionSource.SetResult(path.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetAppPath");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -550,7 +525,7 @@ namespace ElectronNET.API
|
||||
/// <param name="path">A custom path for your logs. Must be absolute.</param>
|
||||
public void SetAppLogsPath(string path)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetAppLogsPath", path);
|
||||
this.CallMethod1(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -596,7 +571,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void SetPath(PathName name, string path)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetPath", name.GetDescription(), path);
|
||||
this.CallMethod2(name.GetDescription(), path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -607,21 +582,7 @@ namespace ElectronNET.API
|
||||
public async Task<string> GetVersionAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
using(cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetVersionCompleted", (version) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetVersionCompleted");
|
||||
taskCompletionSource.SetResult(version.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetVersion");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -635,21 +596,7 @@ namespace ElectronNET.API
|
||||
public async Task<string> GetLocaleAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetLocaleCompleted", (local) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetLocaleCompleted");
|
||||
taskCompletionSource.SetResult(local.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetLocale");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -659,7 +606,7 @@ namespace ElectronNET.API
|
||||
/// <param name="path">Path to add.</param>
|
||||
public void AddRecentDocument(string path)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appAddRecentDocument", path);
|
||||
this.CallMethod1(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -667,7 +614,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void ClearRecentDocuments()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appClearRecentDocuments");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -940,21 +887,7 @@ namespace ElectronNET.API
|
||||
public async Task<JumpListSettings> GetJumpListSettingsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<JumpListSettings>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetJumpListSettingsCompleted", (jumpListSettings) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetJumpListSettingsCompleted");
|
||||
taskCompletionSource.SetResult(JObject.Parse(jumpListSettings.ToString()).ToObject<JumpListSettings>());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetJumpListSettings");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<JumpListSettings>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -975,7 +908,7 @@ namespace ElectronNET.API
|
||||
/// <param name="categories">Array of <see cref="JumpListCategory"/> objects.</param>
|
||||
public void SetJumpList(JumpListCategory[] categories)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetJumpList", JArray.FromObject(categories, _jsonSerializer));
|
||||
this.CallMethod1(JArray.FromObject(categories, _jsonSerializer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1035,7 +968,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void ReleaseSingleInstanceLock()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appReleaseSingleInstanceLock");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1047,21 +980,7 @@ namespace ElectronNET.API
|
||||
public async Task<bool> HasSingleInstanceLockAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appHasSingleInstanceLockCompleted", (hasLock) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appHasSingleInstanceLockCompleted");
|
||||
taskCompletionSource.SetResult((bool) hasLock);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appHasSingleInstanceLock");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1090,7 +1009,7 @@ namespace ElectronNET.API
|
||||
/// </param>
|
||||
public void SetUserActivity(string type, object userInfo, string webpageUrl)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetUserActivity", type, userInfo, webpageUrl);
|
||||
this.CallMethod3(type, userInfo, webpageUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1100,21 +1019,7 @@ namespace ElectronNET.API
|
||||
public async Task<string> GetCurrentActivityTypeAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetCurrentActivityTypeCompleted", (activityType) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetCurrentActivityTypeCompleted");
|
||||
taskCompletionSource.SetResult(activityType.ToString());
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetCurrentActivityType");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<string>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1122,7 +1027,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void InvalidateCurrentActivity()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appInvalidateCurrentActivity");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1130,7 +1035,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void ResignCurrentActivity()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appResignCurrentActivity");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1139,7 +1044,7 @@ namespace ElectronNET.API
|
||||
/// <param name="id">Model Id.</param>
|
||||
public void SetAppUserModelId(string id)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetAppUserModelId", id);
|
||||
this.CallMethod1(id);
|
||||
}
|
||||
|
||||
/// TODO: Check new parameter which is a function [App.ImportCertificate]
|
||||
@@ -1182,23 +1087,7 @@ namespace ElectronNET.API
|
||||
public async Task<ProcessMetric[]> GetAppMetricsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<ProcessMetric[]>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetAppMetricsCompleted", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetAppMetricsCompleted");
|
||||
var processMetrics = ((JArray)result).ToObject<ProcessMetric[]>();
|
||||
|
||||
taskCompletionSource.SetResult(processMetrics);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetAppMetrics");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<ProcessMetric[]>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1210,23 +1099,7 @@ namespace ElectronNET.API
|
||||
public async Task<GPUFeatureStatus> GetGpuFeatureStatusAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<GPUFeatureStatus>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetGpuFeatureStatusCompleted", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetGpuFeatureStatusCompleted");
|
||||
var gpuFeatureStatus = ((JObject)result).ToObject<GPUFeatureStatus>();
|
||||
|
||||
taskCompletionSource.SetResult(gpuFeatureStatus);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetGpuFeatureStatus");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<GPUFeatureStatus>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1266,21 +1139,7 @@ namespace ElectronNET.API
|
||||
public async Task<int> GetBadgeCountAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<int>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appGetBadgeCountCompleted", (count) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetBadgeCountCompleted");
|
||||
taskCompletionSource.SetResult((int)count);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetBadgeCount");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<int>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1295,21 +1154,7 @@ namespace ElectronNET.API
|
||||
public async Task<bool> IsUnityRunningAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appIsUnityRunningCompleted", (isUnityRunning) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appIsUnityRunningCompleted");
|
||||
taskCompletionSource.SetResult((bool)isUnityRunning);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appIsUnityRunning");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1365,7 +1210,7 @@ namespace ElectronNET.API
|
||||
/// <param name="loginSettings"></param>
|
||||
public void SetLoginItemSettings(LoginSettings loginSettings)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetLoginItemSettings", JObject.FromObject(loginSettings, _jsonSerializer));
|
||||
this.CallMethod1(JObject.FromObject(loginSettings, _jsonSerializer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1377,21 +1222,7 @@ namespace ElectronNET.API
|
||||
public async Task<bool> IsAccessibilitySupportEnabledAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
using (cancellationToken.Register(() => taskCompletionSource.TrySetCanceled()))
|
||||
{
|
||||
BridgeConnector.Socket.On("appIsAccessibilitySupportEnabledCompleted", (isAccessibilitySupportEnabled) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appIsAccessibilitySupportEnabledCompleted");
|
||||
taskCompletionSource.SetResult((bool)isAccessibilitySupportEnabled);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appIsAccessibilitySupportEnabled");
|
||||
|
||||
return await taskCompletionSource.Task
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
return await this.GetPropertyAsync<bool>().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1406,7 +1237,7 @@ namespace ElectronNET.API
|
||||
/// <param name="enabled">Enable or disable <see href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree">accessibility tree</see> rendering.</param>
|
||||
public void SetAccessibilitySupportEnabled(bool enabled)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetAccessibilitySupportEnabled", enabled);
|
||||
this.CallMethod1(enabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1415,7 +1246,7 @@ namespace ElectronNET.API
|
||||
/// </summary>
|
||||
public void ShowAboutPanel()
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appShowAboutPanel");
|
||||
this.CallMethod0();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1431,7 +1262,7 @@ namespace ElectronNET.API
|
||||
/// <param name="options">About panel options.</param>
|
||||
public void SetAboutPanelOptions(AboutPanelOptions options)
|
||||
{
|
||||
BridgeConnector.Socket.Emit("appSetAboutPanelOptions", JObject.FromObject(options, _jsonSerializer));
|
||||
this.CallMethod1(JObject.FromObject(options, _jsonSerializer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1467,20 +1298,7 @@ namespace ElectronNET.API
|
||||
{
|
||||
get
|
||||
{
|
||||
return Task.Run<string>(() =>
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<string>();
|
||||
|
||||
BridgeConnector.Socket.On("appGetUserAgentFallbackCompleted", (result) =>
|
||||
{
|
||||
BridgeConnector.Socket.Off("appGetUserAgentFallbackCompleted");
|
||||
taskCompletionSource.SetResult((string)result);
|
||||
});
|
||||
|
||||
BridgeConnector.Socket.Emit("appGetUserAgentFallback");
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
});
|
||||
return this.GetPropertyAsync<string>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ using SocketIO = SocketIOClient.SocketIO;
|
||||
internal class SocketIoFacade
|
||||
{
|
||||
private readonly SocketIO _socket;
|
||||
private readonly object _lockObj = new object();
|
||||
|
||||
public SocketIoFacade(string uri)
|
||||
{
|
||||
@@ -54,53 +55,71 @@ internal class SocketIoFacade
|
||||
|
||||
public void On(string eventName, Action action)
|
||||
{
|
||||
_socket.On(eventName, _ =>
|
||||
lock (_lockObj)
|
||||
{
|
||||
Task.Run(action);
|
||||
});
|
||||
_socket.On(eventName, _ =>
|
||||
{
|
||||
Task.Run(action);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void On<T>(string eventName, Action<T> action)
|
||||
{
|
||||
_socket.On(eventName, response =>
|
||||
lock (_lockObj)
|
||||
{
|
||||
var value = response.GetValue<T>();
|
||||
Task.Run(() => action(value));
|
||||
});
|
||||
_socket.On(eventName, response =>
|
||||
{
|
||||
var value = response.GetValue<T>();
|
||||
Task.Run(() => action(value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this method when SocketIoClient supports object deserialization
|
||||
public void On(string eventName, Action<object> action)
|
||||
{
|
||||
_socket.On(eventName, response =>
|
||||
lock (_lockObj)
|
||||
{
|
||||
var value = response.GetValue<object>();
|
||||
////Console.WriteLine($"Called Event {eventName} - data {value}");
|
||||
Task.Run(() => action(value));
|
||||
});
|
||||
_socket.On(eventName, response =>
|
||||
{
|
||||
var value = response.GetValue<object>();
|
||||
////Console.WriteLine($"Called Event {eventName} - data {value}");
|
||||
Task.Run(() => action(value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Once(string eventName, Action action)
|
||||
{
|
||||
_socket.On(eventName, _ =>
|
||||
lock (_lockObj)
|
||||
{
|
||||
_socket.Off(eventName);
|
||||
Task.Run(action);
|
||||
});
|
||||
_socket.On(eventName, _ =>
|
||||
{
|
||||
_socket.Off(eventName);
|
||||
Task.Run(action);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Once<T>(string eventName, Action<T> action)
|
||||
{
|
||||
_socket.On(eventName, (socketIoResponse) =>
|
||||
lock (_lockObj)
|
||||
{
|
||||
_socket.Off(eventName);
|
||||
Task.Run(() => action(socketIoResponse.GetValue<T>()));
|
||||
});
|
||||
_socket.On(eventName, (socketIoResponse) =>
|
||||
{
|
||||
_socket.Off(eventName);
|
||||
Task.Run(() => action(socketIoResponse.GetValue<T>()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Off(string eventName)
|
||||
{
|
||||
_socket.Off(eventName);
|
||||
lock (_lockObj)
|
||||
{
|
||||
_socket.Off(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Emit(string eventName, params object[] args)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace ElectronNET.Common
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using ElectronNET.Runtime.Data;
|
||||
using ElectronNET.Runtime.Services;
|
||||
|
||||
public static class Extensions
|
||||
internal static class Extensions
|
||||
{
|
||||
public static bool IsUnpackaged(this StartupMethod method)
|
||||
{
|
||||
@@ -19,6 +18,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
public static string LowerFirst(this string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
if (str.Length == 1)
|
||||
{
|
||||
return str.ToLower();
|
||||
}
|
||||
|
||||
return char.ToLower(str[0]) + str.Substring(1);
|
||||
}
|
||||
|
||||
public static string StripAsync(this string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
var pos = str.LastIndexOf("Async", StringComparison.Ordinal);
|
||||
|
||||
if (pos > 0)
|
||||
{
|
||||
return str.Substring(0, pos);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static bool IsReady(this LifetimeServiceBase service)
|
||||
{
|
||||
return service != null && service.State == LifetimeState.Ready;
|
||||
|
||||
Reference in New Issue
Block a user