Replace static state with DI container services.

This commit is contained in:
Jared Goodwin 2020-01-22 22:47:04 -08:00
parent f581f836e8
commit efd3f7d5ed
13 changed files with 179 additions and 84 deletions

View File

@ -25,6 +25,8 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Remotely.Desktop.Linux.ViewModels
{
@ -42,9 +44,10 @@ namespace Remotely.Desktop.Linux.ViewModels
{
return;
}
var screenCaster = new LinuxScreenCaster();
var casterSocket = new CasterSocket(new X11Input(), screenCaster, new LinuxAudioCapturer(), new LinuxClipboardService());
Conductor = new Conductor(casterSocket, screenCaster);
BuildServices();
Conductor = Services.GetRequiredService<Conductor>();
Conductor.SessionIDChanged += SessionIDChanged;
Conductor.ViewerRemoved += ViewerRemoved;
@ -52,8 +55,11 @@ namespace Remotely.Desktop.Linux.ViewModels
Conductor.ScreenCastRequested += ScreenCastRequested;
}
public static MainWindowViewModel Current { get; private set; }
public static IServiceProvider Services => ServiceContainer.Instance;
public ICommand ChangeServerCommand => new Executor(async (param) =>
{
await PromptForHostName();
@ -105,6 +111,14 @@ namespace Remotely.Desktop.Linux.ViewModels
(param as Window).WindowState = WindowState.Minimized;
});
public ICommand OpenOptionsMenu => new Executor((param) =>
{
if (param is Button)
{
(param as Button).ContextMenu?.Open(param as Button);
}
});
public ICommand RemoveViewerCommand => new Executor(async (param) =>
{
var viewerList = param as AvaloniaList<object> ?? new AvaloniaList<object>();
@ -149,14 +163,6 @@ namespace Remotely.Desktop.Linux.ViewModels
await Conductor.CasterSocket.GetSessionID();
}
public ICommand OpenOptionsMenu => new Executor((param) =>
{
if (param is Button)
{
(param as Button).ContextMenu?.Open(param as Button);
}
});
public async Task PromptForHostName()
{
var prompt = new HostNamePrompt();
@ -180,7 +186,26 @@ namespace Remotely.Desktop.Linux.ViewModels
}
}
private static void BuildServices()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(builder =>
{
builder.AddConsole().AddEventLog();
});
serviceCollection.AddSingleton<IScreenCaster, LinuxScreenCaster>();
serviceCollection.AddSingleton<IKeyboardMouseInput, X11Input>();
serviceCollection.AddSingleton<IClipboardService, LinuxClipboardService>();
serviceCollection.AddSingleton<IAudioCapturer, LinuxAudioCapturer>();
serviceCollection.AddSingleton<CasterSocket>();
serviceCollection.AddSingleton<IdleTimer>();
serviceCollection.AddSingleton<Conductor>();
serviceCollection.AddTransient<ICapturer, X11Capture>();
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
}
private void ScreenCastRequested(object sender, ScreenCastRequest screenCastRequest)
{
Dispatcher.UIThread.InvokeAsync(async () =>
@ -191,7 +216,7 @@ namespace Remotely.Desktop.Linux.ViewModels
_ = Task.Run(async () =>
{
await Conductor.CasterSocket.SendCursorChange(new CursorInfo(null, Point.Empty, "default"), new List<string>() { screenCastRequest.ViewerID });
_ = Conductor.ScreenCaster.BeginScreenCasting(screenCastRequest);
_ = Services.GetRequiredService<IScreenCaster>().BeginScreenCasting(screenCastRequest);
});
}
});

View File

@ -19,6 +19,8 @@ using System.Windows.Input;
using Remotely.ScreenCast.Win.Services;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Core.Communication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Remotely.Desktop.Win.ViewModels
{
@ -30,15 +32,12 @@ namespace Remotely.Desktop.Win.ViewModels
{
Current = this;
CursorIconWatcher = new CursorIconWatcher();
BuildServices();
CursorIconWatcher = Services.GetRequiredService<CursorIconWatcher>();
CursorIconWatcher.OnChange += CursorIconWatcher_OnChange;
var screenCaster = new WinScreenCaster(CursorIconWatcher);
var clipboardService = new WinClipboardService();
clipboardService.BeginWatching();
var casterSocket = new CasterSocket(new WinInput(), screenCaster, new WinAudioCapturer(), clipboardService);
Conductor = new Conductor(casterSocket, screenCaster);
Services.GetRequiredService<IClipboardService>().BeginWatching();
Conductor = Services.GetRequiredService<Conductor>();
Conductor.SessionIDChanged += SessionIDChanged;
Conductor.ViewerRemoved += ViewerRemoved;
Conductor.ViewerAdded += ViewerAdded;
@ -46,6 +45,7 @@ namespace Remotely.Desktop.Win.ViewModels
}
public static MainWindowViewModel Current { get; private set; }
public static IServiceProvider Services => ServiceContainer.Instance;
public ICommand ChangeServerCommand
{
@ -60,7 +60,6 @@ namespace Remotely.Desktop.Win.ViewModels
}
public Conductor Conductor { get; }
public CursorIconWatcher CursorIconWatcher { get; private set; }
public string Host
@ -128,7 +127,6 @@ namespace Remotely.Desktop.Win.ViewModels
}
public ObservableCollection<Viewer> Viewers { get; } = new ObservableCollection<Viewer>();
public void CopyLink()
{
Clipboard.SetText($"{Host}/RemoteControl?sessionID={SessionID?.Replace(" ", "")}");
@ -186,6 +184,36 @@ namespace Remotely.Desktop.Win.ViewModels
}
}
private static void BuildServices()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(builder =>
{
builder.AddConsole().AddEventLog();
});
serviceCollection.AddSingleton<CursorIconWatcher>();
serviceCollection.AddSingleton<IScreenCaster, WinScreenCaster>();
serviceCollection.AddSingleton<IKeyboardMouseInput, WinInput>();
serviceCollection.AddSingleton<IClipboardService, WinClipboardService>();
serviceCollection.AddSingleton<IAudioCapturer, WinAudioCapturer>();
serviceCollection.AddSingleton<CasterSocket>();
serviceCollection.AddSingleton<IdleTimer>();
serviceCollection.AddSingleton<Conductor>();
serviceCollection.AddTransient<ICapturer>(provider => {
try
{
return new DXCapture();
}
catch
{
return new BitBltCapture();
}
});
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
}
private async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
{
if (Conductor?.CasterSocket != null && Conductor?.Viewers?.Count > 0)
@ -205,7 +233,7 @@ namespace Remotely.Desktop.Win.ViewModels
Task.Run(async () =>
{
await Conductor.CasterSocket.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List<string>() { screenCastRequest.ViewerID });
_ = Conductor.ScreenCaster.BeginScreenCasting(screenCastRequest);
_ = Services.GetRequiredService<IScreenCaster>().BeginScreenCasting(screenCastRequest);
});
}
});

View File

@ -16,6 +16,7 @@ using Remotely.ScreenCast.Core.Interfaces;
using System.Diagnostics;
using System.Threading;
using System.Drawing.Imaging;
using Microsoft.Extensions.DependencyInjection;
namespace Remotely.ScreenCast.Core.Capture
{
@ -25,9 +26,10 @@ namespace Remotely.ScreenCast.Core.Capture
string requesterName,
ICapturer capturer)
{
var viewers = Conductor.Current.Viewers;
var mode = Conductor.Current.Mode;
var casterSocket = Conductor.Current.CasterSocket;
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
var viewers = conductor.Viewers;
var mode = conductor.Mode;
var casterSocket = ServiceContainer.Instance.GetRequiredService<CasterSocket>();
Logger.Write($"Starting screen cast. Requester: {requesterName}. Viewer ID: {viewerID}. Capturer: {capturer.GetType().ToString()}. App Mode: {mode}");
@ -47,7 +49,7 @@ namespace Remotely.ScreenCast.Core.Capture
if (mode == Enums.AppMode.Normal)
{
Conductor.Current.InvokeViewerAdded(viewer);
conductor.InvokeViewerAdded(viewer);
}
if (OSUtils.IsWindows)
@ -79,7 +81,7 @@ namespace Remotely.ScreenCast.Core.Capture
break;
}
if (Conductor.Current.IsDebug)
if (conductor.IsDebug)
{
while (fpsQueue.Any() && DateTime.Now - fpsQueue.Peek() > TimeSpan.FromSeconds(1))
{

View File

@ -143,7 +143,7 @@ namespace Remotely.ScreenCast.Core.Communication
}
private void ApplyConnectionHandlers()
{
var conductor = Conductor.Current;
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
Connection.Closed += (ex) =>
{
Logger.Write($"Connection closed. Error: {ex?.Message}");
@ -432,7 +432,8 @@ namespace Remotely.ScreenCast.Core.Communication
private async void ClipboardService_ClipboardTextChanged(object sender, string clipboardText)
{
var viewerIDs = Conductor.Current.Viewers.Keys.ToList();
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
var viewerIDs = conductor.Viewers.Keys.ToList();
if (viewerIDs.Any())
{
await SendClipboardText(clipboardText, viewerIDs);

View File

@ -13,15 +13,10 @@ namespace Remotely.ScreenCast.Core
{
public class Conductor
{
public static Conductor Current { get; private set; }
public IScreenCaster ScreenCaster { get; }
public bool IsDebug { get; }
public Conductor(CasterSocket casterSocket,
IScreenCaster screenCaster)
public Conductor(CasterSocket casterSocket)
{
Current = this;
ScreenCaster = screenCaster;
CasterSocket = casterSocket;
#if DEBUG
IsDebug = true;
@ -38,7 +33,6 @@ namespace Remotely.ScreenCast.Core
public CasterSocket CasterSocket { get; private set; }
public string DeviceID { get; private set; }
public string Host { get; private set; }
public IdleTimer IdleTimer { get; set; }
public AppMode Mode { get; private set; }
public string RequesterID { get; private set; }
public string ServiceID { get; private set; }

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Remotely.ScreenCast.Core
{
public class ServiceContainer
{
private static IServiceProvider instance;
public static IServiceProvider Instance
{
get
{
return instance;
}
set
{
if (instance != null)
{
throw new Exception("ServiceProvider can only be set once.");
}
instance = value;
}
}
}
}

View File

@ -9,9 +9,9 @@ namespace Remotely.ScreenCast.Core.Services
{
public class IdleTimer
{
public IdleTimer(ConcurrentDictionary<string, Viewer> viewerList)
public IdleTimer(Conductor conductor)
{
ViewerList = viewerList;
ViewerList = conductor.Viewers;
Timer.Elapsed += Timer_Elapsed;
}

View File

@ -5,28 +5,33 @@ using System.Threading;
using Remotely.ScreenCast.Linux.Services;
using Remotely.ScreenCast.Linux.Capture;
using Remotely.ScreenCast.Core.Communication;
using Remotely.ScreenCast.Core.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Remotely.ScreenCast.Linux
{
public class Program
{
public static Conductor Conductor { get; private set; }
public static IServiceProvider Services => ServiceContainer.Instance;
public static void Main(string[] args)
{
try
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
var screenCaster = new LinuxScreenCaster();
var casterSocket = new CasterSocket(new X11Input(), screenCaster, new LinuxAudioCapturer(), new LinuxClipboardService());
Conductor = new Conductor(casterSocket, screenCaster);
BuildServices();
Conductor = Services.GetRequiredService<Conductor>();
Conductor.ProcessArgs(args);
Conductor.Connect().ContinueWith(async (task) =>
{
await Conductor.CasterSocket.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName, Conductor.DeviceID);
await Conductor.CasterSocket.NotifyRequesterUnattendedReady(Conductor.RequesterID);
Conductor.IdleTimer = new IdleTimer(Conductor.Viewers);
Conductor.IdleTimer.Start();
Services.GetRequiredService<IdleTimer>().Start();
});
Thread.Sleep(Timeout.Infinite);
@ -38,6 +43,26 @@ namespace Remotely.ScreenCast.Linux
}
}
private static void BuildServices()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(builder =>
{
builder.AddConsole().AddEventLog();
});
serviceCollection.AddSingleton<IScreenCaster, LinuxScreenCaster>();
serviceCollection.AddSingleton<IKeyboardMouseInput, X11Input>();
serviceCollection.AddSingleton<IClipboardService, LinuxClipboardService>();
serviceCollection.AddSingleton<IAudioCapturer, LinuxAudioCapturer>();
serviceCollection.AddSingleton<CasterSocket>();
serviceCollection.AddSingleton<IdleTimer>();
serviceCollection.AddSingleton<Conductor>();
serviceCollection.AddTransient<ICapturer, X11Capture>();
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{

View File

@ -1,4 +1,5 @@
using Remotely.ScreenCast.Core;
using Microsoft.Extensions.DependencyInjection;
using Remotely.ScreenCast.Core;
using Remotely.ScreenCast.Core.Capture;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Core.Services;
@ -18,8 +19,9 @@ namespace Remotely.ScreenCast.Linux.Services
{
try
{
await Conductor.Current.CasterSocket.SendCursorChange(new CursorInfo(null, Point.Empty, "default"), new List<string>() { screenCastRequest.ViewerID });
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, new X11Capture());
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
await conductor.CasterSocket.SendCursorChange(new CursorInfo(null, Point.Empty, "default"), new List<string>() { screenCastRequest.ViewerID });
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, ServiceContainer.Instance.GetRequiredService<ICapturer>());
}
catch (Exception ex)
{

View File

@ -20,7 +20,7 @@ namespace Remotely.ScreenCast.Win
{
public static Conductor Conductor { get; private set; }
public static CursorIconWatcher CursorIconWatcher { get; private set; }
public static ServiceProvider Services { get; private set; }
public static IServiceProvider Services => ServiceContainer.Instance;
private static string CurrentDesktopName { get; set;
}
@ -65,8 +65,7 @@ namespace Remotely.ScreenCast.Win
Logger.Write("Failed to get initial desktop name.");
}
await CheckForRelaunch();
Conductor.IdleTimer = new IdleTimer(Conductor.Viewers);
Conductor.IdleTimer.Start();
Services.GetRequiredService<IdleTimer>().Start();
CursorIconWatcher.OnChange += CursorIconWatcher_OnChange;
Services.GetRequiredService<IClipboardService>().BeginWatching();
});
@ -88,16 +87,26 @@ namespace Remotely.ScreenCast.Win
builder.AddConsole().AddEventLog();
});
serviceCollection.AddSingleton<Conductor>();
serviceCollection.AddSingleton<CursorIconWatcher>();
serviceCollection.AddScoped<IScreenCaster, WinScreenCaster>();
serviceCollection.AddScoped<IKeyboardMouseInput, WinInput>();
serviceCollection.AddScoped<IClipboardService, WinClipboardService>();
serviceCollection.AddScoped<IAudioCapturer, WinAudioCapturer>();
serviceCollection.AddSingleton<IScreenCaster, WinScreenCaster>();
serviceCollection.AddSingleton<IKeyboardMouseInput, WinInput>();
serviceCollection.AddSingleton<IClipboardService, WinClipboardService>();
serviceCollection.AddSingleton<IAudioCapturer, WinAudioCapturer>();
serviceCollection.AddSingleton<CasterSocket>();
serviceCollection.AddSingleton<IdleTimer>();
serviceCollection.AddSingleton<Conductor>();
serviceCollection.AddTransient<ICapturer>(provider => {
try
{
return new DXCapture();
}
catch
{
return new BitBltCapture();
}
});
Services = serviceCollection.BuildServiceProvider();
ServiceContainer.Instance = serviceCollection.BuildServiceProvider();
}
private static async Task CheckForRelaunch()

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Microsoft.Extensions.DependencyInjection;
using NAudio.Wave;
using Remotely.ScreenCast.Core;
using Remotely.ScreenCast.Core.Interfaces;
@ -54,7 +55,8 @@ namespace Remotely.ScreenCast.Win.Services
{
WaveFileWriter.WriteWavFileToStream(ms3, resampler);
}
await Conductor.Current.CasterSocket.SendAudioSample(ms3.ToArray(), Program.Conductor.Viewers.Keys.ToList());
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
await conductor.CasterSocket.SendAudioSample(ms3.ToArray(), Program.Conductor.Viewers.Keys.ToList());
}
}
}

View File

@ -12,6 +12,7 @@ using Remotely.ScreenCast.Core.Models;
using Remotely.Shared.Models;
using Remotely.ScreenCast.Win.Capture;
using Remotely.Shared.Win32;
using Microsoft.Extensions.DependencyInjection;
namespace Remotely.ScreenCast.Win.Services
{
@ -35,32 +36,11 @@ namespace Remotely.ScreenCast.Win.Services
{
Logger.Write("Failed to get current desktop before screen casting.");
}
await Conductor.Current.CasterSocket.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List<string>() { screenCastRequest.ViewerID });
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, GetCapturer());
var conductor = ServiceContainer.Instance.GetRequiredService<Conductor>();
await conductor.CasterSocket.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List<string>() { screenCastRequest.ViewerID });
_ = BeginScreenCasting(screenCastRequest.ViewerID, screenCastRequest.RequesterName, ServiceContainer.Instance.GetRequiredService<ICapturer>());
}
private static ICapturer GetCapturer()
{
ICapturer capturer;
try
{
if (Conductor.Current.Viewers.Count == 0)
{
capturer = new DXCapture();
}
else
{
capturer = new BitBltCapture();
}
}
catch (Exception ex)
{
Logger.Write(ex);
capturer = new BitBltCapture();
}
return capturer;
}
}
}

View File

@ -120,7 +120,7 @@ namespace Remotely.Server.Services
var currentUsers = RCBrowserSocketHub.OrganizationConnectionList.Count(x => x.Value.OrganizationID == RemotelyUser.OrganizationID);
if (currentUsers >= AppConfig.RemoteControlSessionLimit)
{
await Clients.Caller.SendAsync("DisplayMessage", $"There are already the maximum amount of active remote control sessions for your organization.");
await Clients.Caller.SendAsync("DisplayMessage", $"There are already the maximum amount of active remote control sessions for your organization.", "Max number of concurrent sessions reached.");
return;
}
await this.Clients.Caller.SendAsync("ServiceID", targetDevice.Key);