mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
* Convert server to new single-file startup model. * Add remote control implementations. * Implement IViewerAuthorizer. * Update hub endpoints. * Implement HubEventHandler. * Implement ViewerHubDataProvider. * Implement page data provider. * Implement RCL and refactor. * Update submodule. * Replace submodule with NuGet. * Update copy URL. * Update NuGet. * Remove deprecated WebRTC. * Remove deprecated WebRTC. * Update Immense.RemoteControl * Building out desktop projects. * Bring more services into submodule. * Update submodule. * Update submodule. * Refactoring for module. * Update submodule. * Update submodule * Got Windows desktop app running. * Refactor for submodule changes. * FIx unattended session start. * Switch desktop app out of console mode. * Fix tests. * Update publishing. * Remove ClickOnce middleware. * Remove ClickOnce remnants. * Update submodule * Add some logging. * Update Linux path. * Update submodule. * Add cleanup service for unattended sessions that failed to start. * Update submodule. * Fix chat. * Add ValidateExecutableReferencesMatchSelfContained property. * Add other submodule projects. Align checkbox. * Update submodule. Reduce deserialization in the browser, resulting in faster renders. * Update submodule. * Update submodule. * Update submodule. * Update submodule. * Add orgId back for branding. * Get branding loading in desktop apps. * Update submodule. * Create log dir. * Refactor version check on config page. * Update submodule. * Update submodule. * Change submodule URL. * Correct namespace. * Update submodule. * Checkout submodules recursively.
252 lines
8.8 KiB
C#
252 lines
8.8 KiB
C#
using Microsoft.AspNetCore.SignalR.Client;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Remotely.Desktop.Core.Interfaces;
|
|
using Remotely.Shared.Models;
|
|
using Remotely.Shared.Utilities;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Remotely.Desktop.Core.Services
|
|
{
|
|
public interface ICasterSocket
|
|
{
|
|
HubConnection Connection { get; }
|
|
bool IsConnected { get; }
|
|
|
|
Task<bool> Connect(string host);
|
|
Task Disconnect();
|
|
Task DisconnectAllViewers();
|
|
Task DisconnectViewer(Viewer viewer, bool notifyViewer);
|
|
Task<string> GetSessionID();
|
|
Task NotifyRequesterUnattendedReady(string requesterID);
|
|
Task NotifyViewersRelaunchedScreenCasterReady(string[] viewerIDs);
|
|
Task SendConnectionFailedToViewers(List<string> viewerIDs);
|
|
Task SendConnectionRequestDenied(string viewerID);
|
|
Task SendCtrlAltDelToAgent();
|
|
Task SendDeviceInfo(string serviceID, string machineName, string deviceID);
|
|
Task SendDtoToViewer<T>(T dto, string viewerId);
|
|
Task SendMessageToViewer(string viewerID, string message);
|
|
Task SendViewerConnected(string viewerConnectionId);
|
|
}
|
|
|
|
public class CasterSocket : ICasterSocket
|
|
{
|
|
public CasterSocket(
|
|
IdleTimer idleTimer,
|
|
IDtoMessageHandler messageHandler,
|
|
IScreenCaster screenCastService,
|
|
IRemoteControlAccessService remoteControlAccessService)
|
|
{
|
|
IdleTimer = idleTimer;
|
|
MessageHandler = messageHandler;
|
|
ScreenCaster = screenCastService;
|
|
RemoteControlAccessService = remoteControlAccessService;
|
|
}
|
|
|
|
public HubConnection Connection { get; private set; }
|
|
public bool IsConnected => Connection?.State == HubConnectionState.Connected;
|
|
private IdleTimer IdleTimer { get; }
|
|
private IDtoMessageHandler MessageHandler { get; }
|
|
private IScreenCaster ScreenCaster { get; }
|
|
private IRemoteControlAccessService RemoteControlAccessService { get; }
|
|
|
|
public async Task<bool> Connect(string host)
|
|
{
|
|
try
|
|
{
|
|
if (Connection?.State == HubConnectionState.Connected)
|
|
{
|
|
try
|
|
{
|
|
await Connection.StopAsync();
|
|
await Connection.DisposeAsync();
|
|
}
|
|
catch { }
|
|
}
|
|
Connection = new HubConnectionBuilder()
|
|
.WithUrl($"{host.Trim().TrimEnd('/')}/hubs/desktop")
|
|
.AddMessagePackProtocol()
|
|
.WithAutomaticReconnect()
|
|
.Build();
|
|
|
|
ApplyConnectionHandlers();
|
|
|
|
await Connection.StartAsync();
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Write(ex);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task Disconnect()
|
|
{
|
|
try
|
|
{
|
|
await Connection.StopAsync();
|
|
await Connection.DisposeAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Write(ex, "Error disconnecting websocket.");
|
|
}
|
|
}
|
|
|
|
public async Task DisconnectAllViewers()
|
|
{
|
|
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
|
|
foreach (var viewer in conductor.Viewers.Values.ToList())
|
|
{
|
|
await DisconnectViewer(viewer, true);
|
|
}
|
|
}
|
|
|
|
public Task DisconnectViewer(Viewer viewer, bool notifyViewer)
|
|
{
|
|
viewer.DisconnectRequested = true;
|
|
viewer.Dispose();
|
|
return Connection.SendAsync("DisconnectViewer", viewer.ViewerConnectionID, notifyViewer);
|
|
}
|
|
|
|
public async Task<string> GetSessionID()
|
|
{
|
|
return await Connection.InvokeAsync<string>("GetSessionID");
|
|
}
|
|
public Task NotifyRequesterUnattendedReady(string requesterID)
|
|
{
|
|
return Connection.SendAsync("NotifyRequesterUnattendedReady", requesterID);
|
|
}
|
|
|
|
public Task NotifyViewersRelaunchedScreenCasterReady(string[] viewerIDs)
|
|
{
|
|
return Connection.SendAsync("NotifyViewersRelaunchedScreenCasterReady", viewerIDs);
|
|
}
|
|
|
|
public Task SendConnectionFailedToViewers(List<string> viewerIDs)
|
|
{
|
|
return Connection.SendAsync("SendConnectionFailedToViewers", viewerIDs);
|
|
}
|
|
|
|
public Task SendConnectionRequestDenied(string viewerID)
|
|
{
|
|
return Connection.SendAsync("SendConnectionRequestDenied", viewerID);
|
|
}
|
|
|
|
public Task SendMessageToViewer(string viewerID, string message)
|
|
{
|
|
return Connection.SendAsync("SendMessageToViewer", viewerID, message);
|
|
}
|
|
|
|
public Task SendCtrlAltDelToAgent()
|
|
{
|
|
return Connection.SendAsync("SendCtrlAltDelToAgent");
|
|
}
|
|
|
|
public Task SendDeviceInfo(string serviceID, string machineName, string deviceID)
|
|
{
|
|
return Connection.SendAsync("ReceiveDeviceInfo", serviceID, machineName, deviceID);
|
|
}
|
|
|
|
public Task SendDtoToViewer<T>(T dto, string viewerId)
|
|
{
|
|
var serializedDto = MessagePack.MessagePackSerializer.Serialize(dto);
|
|
return Connection.SendAsync("SendDtoToBrowser", serializedDto, viewerId);
|
|
}
|
|
|
|
public Task SendViewerConnected(string viewerConnectionId)
|
|
{
|
|
return Connection.SendAsync("ViewerConnected", viewerConnectionId);
|
|
}
|
|
|
|
private void ApplyConnectionHandlers()
|
|
{
|
|
// TODO: Remove circular dependencies and the need for static IServiceProvider instance
|
|
// by emitting these events so other services can listen for them.
|
|
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
|
|
Connection.Closed += (ex) =>
|
|
{
|
|
Logger.Write($"Connection closed. Error: {ex?.Message}");
|
|
return Task.CompletedTask;
|
|
};
|
|
|
|
Connection.On("Disconnect", async (string reason) =>
|
|
{
|
|
Logger.Write($"Disconnecting caster socket. Reason: {reason}");
|
|
await DisconnectAllViewers();
|
|
});
|
|
|
|
Connection.On("GetScreenCast", async (
|
|
string viewerID,
|
|
string requesterName,
|
|
bool notifyUser,
|
|
bool enforceAttendedAccess,
|
|
string organizationName) =>
|
|
{
|
|
try
|
|
{
|
|
if (enforceAttendedAccess)
|
|
{
|
|
await SendMessageToViewer(viewerID, "Asking user for permission...");
|
|
|
|
IdleTimer.Stop();
|
|
var result = await RemoteControlAccessService.PromptForAccess(requesterName, organizationName);
|
|
IdleTimer.Start();
|
|
|
|
if (!result)
|
|
{
|
|
await SendConnectionRequestDenied(viewerID);
|
|
return;
|
|
}
|
|
}
|
|
|
|
ScreenCaster.BeginScreenCasting(new ScreenCastRequest()
|
|
{
|
|
NotifyUser = notifyUser,
|
|
ViewerID = viewerID,
|
|
RequesterName = requesterName
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Write(ex);
|
|
}
|
|
});
|
|
|
|
|
|
Connection.On("RequestScreenCast", (string viewerID, string requesterName, bool notifyUser) =>
|
|
{
|
|
conductor.InvokeScreenCastRequested(new ScreenCastRequest()
|
|
{
|
|
NotifyUser = notifyUser,
|
|
ViewerID = viewerID,
|
|
RequesterName = requesterName
|
|
});
|
|
});
|
|
|
|
Connection.On("SendDtoToClient", (byte[] baseDto, string viewerConnectionId) =>
|
|
{
|
|
if (conductor.Viewers.TryGetValue(viewerConnectionId, out var viewer))
|
|
{
|
|
MessageHandler.ParseMessage(viewer, baseDto);
|
|
}
|
|
});
|
|
|
|
Connection.On("ViewerDisconnected", async (string viewerID) =>
|
|
{
|
|
await Connection.SendAsync("DisconnectViewer", viewerID, false);
|
|
if (conductor.Viewers.TryGetValue(viewerID, out var viewer))
|
|
{
|
|
viewer.DisconnectRequested = true;
|
|
viewer.Dispose();
|
|
}
|
|
conductor.InvokeViewerRemoved(viewerID);
|
|
|
|
});
|
|
}
|
|
}
|
|
}
|