mirror of
https://github.com/ElectronNET/Electron.NET.git
synced 2026-09-23 23:45:19 +00:00
Implement bidirectional event routing for SignalR mode
- Update signalr-bridge.js to handle .NET→Electron events via 'event' channel - Add socket.io-compatible .on() and .emit() methods to SignalRBridge - Update main.js to load all Electron API modules with SignalR bridge - Update SignalRFacade.Emit() to send events via 'event' channel - Add ElectronHub.ElectronEvent() to receive Electron→.NET events - Add SignalRFacade.TriggerEvent() to invoke .NET event handlers - Remove duplicate ElectronEvent method from hub This enables full bidirectional communication: - .NET can call Electron APIs via Emit (e.g., createBrowserWindow) - Electron can send events back to .NET (e.g., BrowserWindowCreated) - Event handlers registered via On/Once now work with SignalR
This commit is contained in:
@@ -116,8 +116,10 @@ namespace ElectronNET.API
|
||||
|
||||
try
|
||||
{
|
||||
// Send message to specific Electron client
|
||||
await _hubContext.Clients.Client(_connectionId).SendAsync(eventName, args);
|
||||
// Send message to specific Electron client via the 'event' hub method
|
||||
// This will be received by signalr-bridge.js's connection.on('event', ...)
|
||||
Console.WriteLine($"[SignalRFacade] Emitting event '{eventName}' to connection {_connectionId}");
|
||||
await _hubContext.Clients.Client(_connectionId).SendAsync("event", eventName, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -126,12 +128,20 @@ namespace ElectronNET.API
|
||||
}
|
||||
}
|
||||
|
||||
public void TriggerEvent(string eventName, object data)
|
||||
public void TriggerEvent(string eventName, params object[] args)
|
||||
{
|
||||
Console.WriteLine($"[SignalRFacade] Triggering event '{eventName}' for .NET handlers");
|
||||
|
||||
if (_eventHandlers.TryGetValue(eventName, out var handler))
|
||||
{
|
||||
// If single arg, pass it directly; otherwise pass the array
|
||||
var data = args.Length == 1 ? args[0] : args;
|
||||
handler(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[SignalRFacade] No handler registered for event '{eventName}'");
|
||||
}
|
||||
}
|
||||
|
||||
public void DisposeSocket()
|
||||
|
||||
@@ -60,6 +60,27 @@ namespace ElectronNET.AspNet.Hubs
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Receives events from Electron (e.g., "BrowserWindowCreated", "dialogResult").
|
||||
/// Called by Electron to send data back to .NET.
|
||||
/// </summary>
|
||||
/// <param name="eventName">The event name</param>
|
||||
/// <param name="args">The event arguments</param>
|
||||
public async Task ElectronEvent(string eventName, params object[] args)
|
||||
{
|
||||
Console.WriteLine($"[ElectronHub] Received event from Electron: {eventName}");
|
||||
|
||||
// Get the SignalRFacade and trigger the event handlers
|
||||
var runtimeController = ElectronNetRuntime.RuntimeController as RuntimeControllerAspNetDotnetFirstSignalR;
|
||||
if (runtimeController?.Socket is ElectronNET.API.SignalRFacade signalRFacade)
|
||||
{
|
||||
// Invoke the event handlers registered via On/Once
|
||||
signalRFacade.TriggerEvent(eventName, args);
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes an Electron API method. Called by .NET to control Electron.
|
||||
/// </summary>
|
||||
@@ -91,17 +112,5 @@ namespace ElectronNET.AspNet.Hubs
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles events from Electron.
|
||||
/// Called by Electron to notify .NET about events (e.g., window closed).
|
||||
/// </summary>
|
||||
/// <param name="eventName">The event name</param>
|
||||
/// <param name="eventData">The event data as JSON</param>
|
||||
public async Task ElectronEvent(string eventName, string eventData)
|
||||
{
|
||||
Console.WriteLine($"[ElectronHub] ElectronEvent received: {eventName}");
|
||||
// This will be handled by the event system
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ class SignalRBridge {
|
||||
this.hubUrl = hubUrl;
|
||||
this.connection = null;
|
||||
this.isConnected = false;
|
||||
this.pendingCalls = new Map(); // For tracking API calls
|
||||
this.eventHandlers = new Map(); // For socket.io-style .on() handlers
|
||||
this.callIdCounter = 0;
|
||||
}
|
||||
|
||||
@@ -56,46 +56,46 @@ class SignalRBridge {
|
||||
}
|
||||
|
||||
setupMessageHandlers() {
|
||||
// Handle API calls from .NET
|
||||
this.connection.on('electronApiCall', (method, data) => {
|
||||
console.log(`[SignalRBridge] Received API call: ${method}`);
|
||||
this.handleApiCall(method, data);
|
||||
// Handle generic events from .NET - this is where .NET's Emit() calls arrive
|
||||
this.connection.on('event', (eventName, ...args) => {
|
||||
console.log(`[SignalRBridge] Received event: ${eventName}`);
|
||||
|
||||
// Check if we have handlers registered for this event
|
||||
if (this.eventHandlers.has(eventName)) {
|
||||
const handlers = this.eventHandlers.get(eventName);
|
||||
handlers.forEach(handler => {
|
||||
try {
|
||||
handler(...args);
|
||||
} catch (err) {
|
||||
console.error(`[SignalRBridge] Error in event handler for ${eventName}:`, err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async handleApiCall(method, data) {
|
||||
// This will be implemented to route to the actual Electron API
|
||||
// For now, just log it
|
||||
console.log(`[SignalRBridge] Handling API call: ${method} with data:`, data);
|
||||
|
||||
// TODO: Route to actual Electron API handlers
|
||||
// This will be connected to the existing API modules (browserWindows, dialog, etc.)
|
||||
// Socket.io compatibility: register event handler
|
||||
on(eventName, callback) {
|
||||
if (!this.eventHandlers.has(eventName)) {
|
||||
this.eventHandlers.set(eventName, []);
|
||||
}
|
||||
this.eventHandlers.get(eventName).push(callback);
|
||||
console.log(`[SignalRBridge] Registered handler for event: ${eventName}`);
|
||||
}
|
||||
|
||||
async invokeMethod(methodName, ...args) {
|
||||
// Socket.io compatibility: emit event (send to .NET)
|
||||
async emit(eventName, ...args) {
|
||||
if (!this.isConnected) {
|
||||
throw new Error('SignalR connection is not established');
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.connection.invoke(methodName, ...args);
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.error(`[SignalRBridge] Error invoking ${methodName}:`, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async sendElectronEvent(eventName, eventData) {
|
||||
if (!this.isConnected) {
|
||||
console.warn(`[SignalRBridge] Cannot send event - not connected`);
|
||||
console.warn(`[SignalRBridge] Cannot emit ${eventName} - not connected`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.connection.invoke('ElectronEvent', eventName, JSON.stringify(eventData));
|
||||
console.log(`[SignalRBridge] Emitting event: ${eventName}`);
|
||||
await this.connection.invoke('ElectronEvent', eventName, ...args);
|
||||
} catch (err) {
|
||||
console.error(`[SignalRBridge] Error sending event:`, err);
|
||||
console.error(`[SignalRBridge] Error emitting ${eventName}:`, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,19 +106,6 @@ class SignalRBridge {
|
||||
console.log(`[SignalRBridge] Disconnected`);
|
||||
}
|
||||
}
|
||||
|
||||
// Socket.io compatibility method - for easier transition
|
||||
on(eventName, callback) {
|
||||
if (this.connection) {
|
||||
this.connection.on(eventName, callback);
|
||||
}
|
||||
}
|
||||
|
||||
// Socket.io compatibility method
|
||||
emit(eventName, ...args) {
|
||||
// Map to SignalR invoke
|
||||
return this.invokeMethod(eventName, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { SignalRBridge };
|
||||
|
||||
@@ -427,11 +427,31 @@ async function startSignalRApiBridge(baseUrl) {
|
||||
// Store the bridge globally for API access
|
||||
global['electronsignalr'] = signalRBridge;
|
||||
|
||||
// Load API modules with SignalR bridge
|
||||
// Load API modules with SignalR bridge (same as socket.io)
|
||||
console.log('[SignalRBridge] Loading API components...');
|
||||
|
||||
// TODO: Load API modules adapted for SignalR
|
||||
// For now, just log that we're connected
|
||||
if (appApi === undefined) appApi = require('./api/app')(signalRBridge, app);
|
||||
if (browserWindows === undefined) browserWindows = require('./api/browserWindows')(signalRBridge, app);
|
||||
if (commandLine === undefined) commandLine = require('./api/commandLine')(signalRBridge, app);
|
||||
if (autoUpdater === undefined) autoUpdater = require('./api/autoUpdater')(signalRBridge);
|
||||
if (ipc === undefined) ipc = require('./api/ipc')(signalRBridge);
|
||||
if (menu === undefined) menu = require('./api/menu')(signalRBridge);
|
||||
if (dialogApi === undefined) dialogApi = require('./api/dialog')(signalRBridge);
|
||||
if (notification === undefined) notification = require('./api/notification')(signalRBridge);
|
||||
if (tray === undefined) tray = require('./api/tray')(signalRBridge);
|
||||
if (webContents === undefined) webContents = require('./api/webContents')(signalRBridge);
|
||||
if (globalShortcut === undefined) globalShortcut = require('./api/globalShortcut')(signalRBridge);
|
||||
if (clipboard === undefined) clipboard = require('./api/clipboard')(signalRBridge);
|
||||
if (screen === undefined) screen = require('./api/screen')(signalRBridge);
|
||||
if (shell === undefined) shell = require('./api/shell')(signalRBridge);
|
||||
if (nativeTheme === undefined) nativeTheme = require('./api/nativeTheme')(signalRBridge);
|
||||
if (powerMonitor === undefined) powerMonitor = require('./api/powerMonitor')(signalRBridge);
|
||||
if (dock === undefined) dock = require('./api/dock')(signalRBridge, app);
|
||||
if (desktopCapturer === undefined) desktopCapturer = require('./api/desktopCapturer')(signalRBridge);
|
||||
if (electronHostHook === undefined) electronHostHook = require('./api/hostHook')();
|
||||
if (process.platform === 'darwin') {
|
||||
if (touchBar === undefined) touchBar = require('./api/touchBar')(signalRBridge);
|
||||
}
|
||||
|
||||
console.log('[SignalRBridge] Startup complete');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user