Skip to content

Commit 0657a27

Browse files
Add socket.io client csharp package
1 parent e3acc79 commit 0657a27

26 files changed

Lines changed: 5257 additions & 3834 deletions

ElectronNET.API/App.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using ElectronNET.API.Extensions;
10+
using static System.Collections.Specialized.BitVector32;
1011

1112
namespace ElectronNET.API
1213
{
@@ -1614,29 +1615,29 @@ internal void PreventQuit()
16141615
/// Subscribe to an unmapped event on the <see cref="App"/> module.
16151616
/// </summary>
16161617
/// <param name="eventName">The event name</param>
1617-
/// <param name="fn">The handler</param>
1618-
public void On(string eventName, Action fn)
1619-
=> Events.Instance.On(ModuleName, eventName, fn);
1618+
/// <param name="action">The handler</param>
1619+
public void On(string eventName, Action action)
1620+
=> Events.Instance.On(ModuleName, eventName, action);
16201621
/// <summary>
16211622
/// Subscribe to an unmapped event on the <see cref="App"/> module.
16221623
/// </summary>
16231624
/// <param name="eventName">The event name</param>
1624-
/// <param name="fn">The handler</param>
1625-
public void On(string eventName, Action<object> fn)
1626-
=> Events.Instance.On(ModuleName, eventName, fn);
1625+
/// <param name="action">The handler</param>
1626+
public async Task On(string eventName, Action<object> action)
1627+
=> await Events.Instance.On(ModuleName, eventName, action);
16271628
/// <summary>
16281629
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
16291630
/// </summary>
16301631
/// <param name="eventName">The event name</param>
1631-
/// <param name="fn">The handler</param>
1632-
public void Once(string eventName, Action fn)
1633-
=> Events.Instance.Once(ModuleName, eventName, fn);
1632+
/// <param name="action">The handler</param>
1633+
public void Once(string eventName, Action action)
1634+
=> Events.Instance.Once(ModuleName, eventName, action);
16341635
/// <summary>
16351636
/// Subscribe to an unmapped event on the <see cref="App"/> module once.
16361637
/// </summary>
16371638
/// <param name="eventName">The event name</param>
1638-
/// <param name="fn">The handler</param>
1639-
public void Once(string eventName, Action<object> fn)
1640-
=> Events.Instance.Once(ModuleName, eventName, fn);
1639+
/// <param name="action">The handler</param>
1640+
public async Task Once(string eventName, Action<object> action)
1641+
=> await Events.Instance.Once(ModuleName, eventName, action);
16411642
}
16421643
}

ElectronNET.API/BridgeConnector.cs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,27 @@
1-
using Quobject.SocketIoClientDotNet.Client;
2-
using System;
3-
4-
namespace ElectronNET.API
1+
namespace ElectronNET.API
52
{
63
internal static class BridgeConnector
74
{
8-
private static Socket _socket;
9-
private static object _syncRoot = new object();
5+
private static SocketIoFacade _socket;
6+
private static readonly object SyncRoot = new();
107

11-
public static Socket Socket
8+
public static SocketIoFacade Socket
129
{
1310
get
1411
{
15-
if(_socket == null && HybridSupport.IsElectronActive)
12+
if (_socket == null)
1613
{
17-
lock (_syncRoot)
14+
lock (SyncRoot)
1815
{
19-
if (_socket == null && HybridSupport.IsElectronActive)
16+
if (_socket == null)
2017
{
21-
_socket = IO.Socket("http://localhost:" + BridgeSettings.SocketPort);
22-
_socket.On(Socket.EVENT_CONNECT, () =>
23-
{
24-
Console.WriteLine("BridgeConnector connected!");
25-
});
26-
}
27-
}
28-
}
29-
else if(_socket == null && !HybridSupport.IsElectronActive)
30-
{
31-
lock (_syncRoot)
32-
{
33-
if (_socket == null && !HybridSupport.IsElectronActive)
34-
{
35-
_socket = IO.Socket(new Uri("http://localhost"), new IO.Options { AutoConnect = false });
18+
19+
string socketUrl = HybridSupport.IsElectronActive
20+
? $"http://localhost:{BridgeSettings.SocketPort}"
21+
: "http://localhost";
22+
23+
_socket = new SocketIoFacade(socketUrl);
24+
_socket.Connect();
3625
}
3726
}
3827
}
@@ -41,4 +30,4 @@ public static Socket Socket
4130
}
4231
}
4332
}
44-
}
33+
}

ElectronNET.API/ElectronNET.API.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
55
<PackageOutputPath>..\artifacts</PackageOutputPath>
66
<PackageId>ElectronNET.API</PackageId>
7-
<Authors>Gregor Biswanger, Robert Muehsig</Authors>
7+
<Authors>Gregor Biswanger, Florian Rappl</Authors>
88
<Company />
99
<Product>Electron.NET</Product>
1010
<PackageLicenseExpression>MIT</PackageLicenseExpression>
@@ -37,7 +37,9 @@ This package contains the API to access the "native" electron API.</Description>
3737
<PrivateAssets>all</PrivateAssets>
3838
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
3939
</PackageReference>
40-
<PackageReference Include="SocketIoClientDotNet" Version="1.0.5" />
40+
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
41+
<PackageReference Include="SocketIOClient" Version="3.0.8" />
42+
<PackageReference Include="SocketIOClient.Newtonsoft.Json" Version="3.0.7" />
4143
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
4244
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.410601">
4345
<PrivateAssets>all</PrivateAssets>

ElectronNET.API/Events.cs

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using System.Globalization;
3-
using Quobject.EngineIoClientDotNet.ComponentEmitter;
3+
using System.Threading.Tasks;
44

55
namespace ElectronNET.API
66
{
@@ -10,20 +10,19 @@ namespace ElectronNET.API
1010
internal class Events
1111
{
1212
private static Events _events;
13-
private static object _syncRoot = new object();
14-
private TextInfo _ti = new CultureInfo("en-US", false).TextInfo;
13+
private static readonly object SyncRoot = new();
14+
private readonly TextInfo _textInfo = new CultureInfo("en-US", false).TextInfo;
15+
1516
private Events()
16-
{
17-
18-
}
17+
{}
1918

2019
public static Events Instance
2120
{
2221
get
2322
{
2423
if (_events == null)
2524
{
26-
lock (_syncRoot)
25+
lock (SyncRoot)
2726
{
2827
if (_events == null)
2928
{
@@ -41,32 +40,24 @@ public static Events Instance
4140
/// </summary>
4241
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
4342
/// <param name="eventName">The name of the event</param>
44-
/// <param name="fn">The event handler</param>
45-
public void On(string moduleName, string eventName, Action fn)
46-
=> On(moduleName, eventName, new ListenerImpl(fn));
43+
/// <param name="action">The event handler</param>
44+
public void On(string moduleName, string eventName, Action action)
45+
=> On(moduleName, eventName, action);
4746

48-
/// <summary>
49-
/// Subscribe to an unmapped electron event.
50-
/// </summary>
51-
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
52-
/// <param name="eventName">The name of the event</param>
53-
/// <param name="fn">The event handler</param>
54-
public void On(string moduleName, string eventName, Action<object> fn)
55-
=> On(moduleName, eventName, new ListenerImpl(fn));
5647

5748
/// <summary>
5849
/// Subscribe to an unmapped electron event.
5950
/// </summary>
6051
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
6152
/// <param name="eventName">The name of the event</param>
62-
/// <param name="fn">The event handler</param>
63-
private void On(string moduleName, string eventName, IListener fn)
53+
/// <param name="action">The event handler</param>
54+
public async Task On<T>(string moduleName, string eventName, Action<T> action)
6455
{
65-
var listener = $"{moduleName}{_ti.ToTitleCase(eventName)}Completed";
56+
var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
6657
var subscriber = $"register-{moduleName}-on-event";
67-
68-
BridgeConnector.Socket.On(listener, fn);
69-
BridgeConnector.Socket.Emit(subscriber, eventName, listener);
58+
59+
BridgeConnector.Socket.On(listener, action);
60+
await BridgeConnector.Socket.Emit(subscriber, eventName, listener);
7061
}
7162

7263
/// <summary>
@@ -75,30 +66,22 @@ private void On(string moduleName, string eventName, IListener fn)
7566
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
7667
/// <param name="eventName">The name of the event</param>
7768
/// <param name="fn">The event handler</param>
78-
public void Once(string moduleName, string eventName, Action fn)
79-
=> Once(moduleName, eventName, new ListenerImpl(fn));
69+
public void Once(string moduleName, string eventName, Action action)
70+
=> Once(moduleName, eventName, action);
8071

81-
/// <summary>
82-
/// Subscribe to an unmapped electron event.
83-
/// </summary>
84-
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
85-
/// <param name="eventName">The name of the event</param>
86-
/// <param name="fn">The event handler</param>
87-
public void Once(string moduleName, string eventName, Action<object> fn)
88-
=> Once(moduleName, eventName, new ListenerImpl(fn));
8972

9073
/// <summary>
9174
/// Subscribe to an unmapped electron event.
9275
/// </summary>
9376
/// <param name="moduleName">The name of the module, e.g. app, dock, etc...</param>
9477
/// <param name="eventName">The name of the event</param>
95-
/// <param name="fn">The event handler</param>
96-
private void Once(string moduleName, string eventName, IListener fn)
78+
/// <param name="action">The event handler</param>
79+
public async Task Once<T>(string moduleName, string eventName, Action<T> action)
9780
{
98-
var listener = $"{moduleName}{_ti.ToTitleCase(eventName)}Completed";
81+
var listener = $"{moduleName}{_textInfo.ToTitleCase(eventName)}Completed";
9982
var subscriber = $"register-{moduleName}-once-event";
100-
BridgeConnector.Socket.Once(listener, fn);
101-
BridgeConnector.Socket.Emit(subscriber, eventName, listener);
83+
BridgeConnector.Socket.Once(listener, action);
84+
await BridgeConnector.Socket.Emit(subscriber, eventName, listener);
10285
}
10386

10487
}

ElectronNET.API/IpcMain.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections;
66
using System.Collections.Generic;
77
using System.Linq;
8+
using System.Threading.Tasks;
89

910
namespace ElectronNET.API
1011
{
@@ -43,9 +44,9 @@ internal static IpcMain Instance
4344
/// </summary>
4445
/// <param name="channel">Channelname.</param>
4546
/// <param name="listener">Callback Method.</param>
46-
public void On(string channel, Action<object> listener)
47+
public async Task On(string channel, Action<object> listener)
4748
{
48-
BridgeConnector.Socket.Emit("registerIpcMainChannel", channel);
49+
await BridgeConnector.Socket.Emit("registerIpcMainChannel", channel);
4950
BridgeConnector.Socket.Off(channel);
5051
BridgeConnector.Socket.On(channel, (args) =>
5152
{

ElectronNET.API/SocketIOFacade.cs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Newtonsoft.Json;
4+
using Newtonsoft.Json.Serialization;
5+
using SocketIOClient;
6+
using SocketIOClient.Newtonsoft.Json;
7+
8+
namespace ElectronNET.API;
9+
10+
internal class SocketIoFacade
11+
{
12+
private readonly SocketIO _socket;
13+
14+
public SocketIoFacade(string uri)
15+
{
16+
_socket = new SocketIO(uri);
17+
var jsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings
18+
{
19+
ContractResolver = new CamelCasePropertyNamesContractResolver(),
20+
NullValueHandling = NullValueHandling.Ignore,
21+
DefaultValueHandling = DefaultValueHandling.Ignore
22+
});
23+
24+
_socket.JsonSerializer = jsonSerializer;
25+
}
26+
27+
public void Connect()
28+
{
29+
_socket.OnError += (sender, e) =>
30+
{
31+
Console.WriteLine($"BridgeConnector Error: {sender} {e}");
32+
};
33+
34+
_socket.OnConnected += (_, _) =>
35+
{
36+
Console.WriteLine("BridgeConnector connected!");
37+
};
38+
39+
_socket.OnDisconnected += (_, _) =>
40+
{
41+
Console.WriteLine("BridgeConnector disconnected!");
42+
};
43+
44+
_socket.ConnectAsync().GetAwaiter().GetResult();
45+
}
46+
47+
public void On(string eventName, Action action)
48+
{
49+
_socket.On(eventName, response =>
50+
{
51+
Task.Run(action);
52+
});
53+
}
54+
55+
public void On<T>(string eventName, Action<T> action)
56+
{
57+
_socket.On(eventName, response =>
58+
{
59+
var value = response.GetValue<T>();
60+
Task.Run(() => action(value));
61+
});
62+
}
63+
64+
// TODO: Remove this method when SocketIoClient supports object deserialization
65+
public void On(string eventName, Action<object> action)
66+
{
67+
_socket.On(eventName, response =>
68+
{
69+
var value = response.GetValue<object>();
70+
Console.WriteLine($"Called Event {eventName} - data {value}");
71+
Task.Run(() => action(value));
72+
});
73+
}
74+
75+
public void Once<T>(string eventName, Action<T> action)
76+
{
77+
_socket.On(eventName, (socketIoResponse) =>
78+
{
79+
_socket.Off(eventName);
80+
action(socketIoResponse.GetValue<T>());
81+
});
82+
}
83+
84+
public void Off(string eventName)
85+
{
86+
_socket.Off(eventName);
87+
}
88+
89+
public async Task Emit(string eventName, params object[] args)
90+
{
91+
await _socket.EmitAsync(eventName, args);
92+
}
93+
}

0 commit comments

Comments
 (0)