-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
387 changed files
with
61,448 additions
and
6,573 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +0,0 @@ | ||
[submodule "submodules/Immense.RemoteControl"] | ||
path = submodules/Immense.RemoteControl | ||
url = [email protected]:immense/RemoteControl.git | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
using Immense.RemoteControl.Desktop.Shared.Abstractions; | ||
using Immense.RemoteControl.Desktop.Shared.Enums; | ||
using Immense.RemoteControl.Desktop.Shared.Services; | ||
using Immense.RemoteControl.Desktop.UI.Services; | ||
using Immense.RemoteControl.Shared.Models; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Immense.RemoteControl.Desktop.Linux.Services; | ||
|
||
internal class AppStartup : IAppStartup | ||
{ | ||
private readonly IAppState _appState; | ||
private readonly IKeyboardMouseInput _inputService; | ||
private readonly IDesktopHubConnection _desktopHub; | ||
private readonly IClipboardService _clipboardService; | ||
private readonly IChatHostService _chatHostService; | ||
private readonly ICursorIconWatcher _cursorIconWatcher; | ||
private readonly IUiDispatcher _dispatcher; | ||
private readonly IIdleTimer _idleTimer; | ||
private readonly IShutdownService _shutdownService; | ||
private readonly IBrandingProvider _brandingProvider; | ||
private readonly ILogger<AppStartup> _logger; | ||
|
||
public AppStartup( | ||
IAppState appState, | ||
IKeyboardMouseInput inputService, | ||
IDesktopHubConnection desktopHub, | ||
IClipboardService clipboardService, | ||
IChatHostService chatHostService, | ||
ICursorIconWatcher iconWatcher, | ||
IUiDispatcher dispatcher, | ||
IIdleTimer idleTimer, | ||
IShutdownService shutdownService, | ||
IBrandingProvider brandingProvider, | ||
ILogger<AppStartup> logger) | ||
{ | ||
_appState = appState; | ||
_inputService = inputService; | ||
_desktopHub = desktopHub; | ||
_clipboardService = clipboardService; | ||
_chatHostService = chatHostService; | ||
_cursorIconWatcher = iconWatcher; | ||
_dispatcher = dispatcher; | ||
_idleTimer = idleTimer; | ||
_shutdownService = shutdownService; | ||
_brandingProvider = brandingProvider; | ||
_logger = logger; | ||
} | ||
|
||
public async Task Run() | ||
{ | ||
await _brandingProvider.Initialize(); | ||
|
||
if (_appState.Mode is AppMode.Unattended or AppMode.Attended) | ||
{ | ||
_clipboardService.BeginWatching(); | ||
_inputService.Init(); | ||
_cursorIconWatcher.OnChange += CursorIconWatcher_OnChange; | ||
} | ||
|
||
switch (_appState.Mode) | ||
{ | ||
case AppMode.Unattended: | ||
{ | ||
var result = await _dispatcher.StartHeadless(); | ||
if (!result.IsSuccess) | ||
{ | ||
return; | ||
} | ||
await StartScreenCasting().ConfigureAwait(false); | ||
break; | ||
} | ||
case AppMode.Attended: | ||
{ | ||
_dispatcher.StartClassicDesktop(); | ||
break; | ||
} | ||
case AppMode.Chat: | ||
{ | ||
var result = await _dispatcher.StartHeadless(); | ||
if (!result.IsSuccess) | ||
{ | ||
return; | ||
} | ||
await _chatHostService | ||
.StartChat(_appState.PipeName, _appState.OrganizationName) | ||
.ConfigureAwait(false); | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
|
||
private async Task StartScreenCasting() | ||
{ | ||
if (!await _desktopHub.Connect(TimeSpan.FromSeconds(30), _dispatcher.ApplicationExitingToken)) | ||
{ | ||
await _shutdownService.Shutdown(); | ||
return; | ||
} | ||
|
||
var result = await _desktopHub.SendUnattendedSessionInfo( | ||
_appState.SessionId, | ||
_appState.AccessKey, | ||
Environment.MachineName, | ||
_appState.RequesterName, | ||
_appState.OrganizationName); | ||
|
||
if (!result.IsSuccess) | ||
{ | ||
_logger.LogError(result.Exception, "An error occurred while trying to establish a session with the server."); | ||
await _shutdownService.Shutdown(); | ||
return; | ||
} | ||
|
||
try | ||
{ | ||
if (_appState.ArgDict.ContainsKey("relaunch")) | ||
{ | ||
_logger.LogInformation("Resuming after relaunch."); | ||
var viewerIDs = _appState.RelaunchViewers; | ||
await _desktopHub.NotifyViewersRelaunchedScreenCasterReady(viewerIDs); | ||
} | ||
else | ||
{ | ||
await _desktopHub.NotifyRequesterUnattendedReady(); | ||
} | ||
} | ||
finally | ||
{ | ||
_idleTimer.Start(); | ||
} | ||
} | ||
|
||
|
||
|
||
private async void CursorIconWatcher_OnChange(object? sender, CursorInfo cursor) | ||
{ | ||
if (_appState.Viewers.Any() == true && | ||
_desktopHub.IsConnected) | ||
{ | ||
foreach (var viewer in _appState.Viewers.Values) | ||
{ | ||
await viewer.SendCursorChange(cursor); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Immense.RemoteControl.Desktop.Shared.Abstractions; | ||
|
||
namespace Immense.RemoteControl.Desktop.Linux.Services; | ||
|
||
public class AudioCapturerLinux : IAudioCapturer | ||
{ | ||
#pragma warning disable CS0067 | ||
public event EventHandler<byte[]>? AudioSampleReady; | ||
#pragma warning restore | ||
|
||
public void ToggleAudio(bool toggleOn) | ||
{ | ||
// Not implemented. | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Immense.RemoteControl.Desktop.Shared.Abstractions; | ||
using Immense.RemoteControl.Shared.Models; | ||
using System.Drawing; | ||
|
||
namespace Immense.RemoteControl.Desktop.Linux.Services; | ||
|
||
public class CursorIconWatcherLinux : ICursorIconWatcher | ||
{ | ||
#pragma warning disable CS0067 | ||
public event EventHandler<CursorInfo>? OnChange; | ||
#pragma warning restore | ||
|
||
|
||
public CursorInfo GetCurrentCursor() => new(Array.Empty<byte>(), Point.Empty, "default"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
using Immense.RemoteControl.Desktop.Shared.Abstractions; | ||
using Immense.RemoteControl.Desktop.Shared.Services; | ||
using Immense.RemoteControl.Desktop.Shared.ViewModels; | ||
using Microsoft.Extensions.Logging; | ||
using System.Collections.Concurrent; | ||
using Immense.RemoteControl.Desktop.UI.Controls.Dialogs; | ||
using Immense.RemoteControl.Desktop.UI.Views; | ||
using Immense.RemoteControl.Desktop.UI.Services; | ||
using System.Threading; | ||
using System.IO; | ||
|
||
namespace Immense.RemoteControl.Desktop.Linux.Services; | ||
|
||
public class FileTransferServiceLinux : IFileTransferService | ||
{ | ||
private static readonly ConcurrentDictionary<string, FileTransferWindow> _fileTransferWindows = new(); | ||
private static readonly ConcurrentDictionary<string, FileStream> _partialTransfers = new(); | ||
private static readonly SemaphoreSlim _writeLock = new(1, 1); | ||
private static volatile bool _messageBoxPending; | ||
private readonly IViewModelFactory _viewModelFactory; | ||
private readonly IUiDispatcher _dispatcher; | ||
private readonly IDialogProvider _dialogProvider; | ||
private readonly ILogger<FileTransferServiceLinux> _logger; | ||
|
||
public FileTransferServiceLinux( | ||
IViewModelFactory viewModelFactory, | ||
IUiDispatcher dispatcher, | ||
IDialogProvider dialogProvider, | ||
ILogger<FileTransferServiceLinux> logger) | ||
{ | ||
_viewModelFactory = viewModelFactory; | ||
_dispatcher = dispatcher; | ||
_dialogProvider = dialogProvider; | ||
_logger = logger; | ||
} | ||
|
||
public string GetBaseDirectory() | ||
{ | ||
var desktopDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); | ||
if (Directory.Exists(desktopDir)) | ||
{ | ||
return desktopDir; | ||
} | ||
|
||
return Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "RemoteControl")).FullName; | ||
} | ||
|
||
public void OpenFileTransferWindow(IViewer viewer) | ||
{ | ||
_dispatcher.Post(() => | ||
{ | ||
if (_fileTransferWindows.TryGetValue(viewer.ViewerConnectionId, out var window)) | ||
{ | ||
window.Activate(); | ||
} | ||
else | ||
{ | ||
window = new FileTransferWindow | ||
{ | ||
DataContext = _viewModelFactory.CreateFileTransferWindowViewModel(viewer) | ||
}; | ||
window.Closed += (sender, arg) => | ||
{ | ||
_fileTransferWindows.Remove(viewer.ViewerConnectionId, out _); | ||
}; | ||
_fileTransferWindows.AddOrUpdate(viewer.ViewerConnectionId, window, (k, v) => window); | ||
window.Show(); | ||
} | ||
}); | ||
} | ||
|
||
public async Task ReceiveFile(byte[] buffer, string fileName, string messageId, bool endOfFile, bool startOfFile) | ||
{ | ||
try | ||
{ | ||
await _writeLock.WaitAsync(); | ||
|
||
var baseDir = GetBaseDirectory(); | ||
|
||
if (startOfFile) | ||
{ | ||
var filePath = Path.Combine(baseDir, fileName); | ||
|
||
if (File.Exists(filePath)) | ||
{ | ||
var count = 0; | ||
var ext = Path.GetExtension(fileName); | ||
var fileWithoutExt = Path.GetFileNameWithoutExtension(fileName); | ||
while (File.Exists(filePath)) | ||
{ | ||
filePath = Path.Combine(baseDir, $"{fileWithoutExt}-{count}{ext}"); | ||
count++; | ||
} | ||
} | ||
|
||
File.Create(filePath).Close(); | ||
|
||
var fs = new FileStream(filePath, FileMode.OpenOrCreate); | ||
_partialTransfers.AddOrUpdate(messageId, fs, (k, v) => fs); | ||
} | ||
|
||
var fileStream = _partialTransfers[messageId]; | ||
|
||
if (buffer?.Length > 0) | ||
{ | ||
await fileStream.WriteAsync(buffer); | ||
|
||
} | ||
|
||
if (endOfFile) | ||
{ | ||
fileStream.Close(); | ||
_partialTransfers.Remove(messageId, out _); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError(ex, "Error while receiving file."); | ||
} | ||
finally | ||
{ | ||
_writeLock.Release(); | ||
if (endOfFile) | ||
{ | ||
await Task.Run(ShowTransferComplete); | ||
} | ||
} | ||
} | ||
|
||
public async Task UploadFile( | ||
FileUpload fileUpload, | ||
IViewer viewer, | ||
Action<double> progressUpdateCallback, | ||
CancellationToken cancelToken) | ||
{ | ||
try | ||
{ | ||
await viewer.SendFile(fileUpload, progressUpdateCallback, cancelToken); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_logger.LogError(ex, "Error while uploading file."); | ||
} | ||
} | ||
|
||
private async Task ShowTransferComplete() | ||
{ | ||
// Prevent multiple dialogs from popping up. | ||
if (!_messageBoxPending) | ||
{ | ||
_messageBoxPending = true; | ||
|
||
await _dialogProvider.Show($"File tranfer complete. Files saved to directory:\n\n{GetBaseDirectory()}", | ||
"Tranfer Complete", | ||
MessageBoxType.OK); | ||
|
||
_messageBoxPending = false; | ||
} | ||
} | ||
} |
Oops, something went wrong.