Remotely/Desktop.Win/ViewModels/MainWindowViewModel.cs
2021-07-29 07:54:01 -07:00

260 lines
8.5 KiB
C#

using Remotely.Desktop.Win.Controls;
using Remotely.Desktop.Win.Services;
using Remotely.Shared.Models;
using Remotely.ScreenCast.Core;
using Remotely.ScreenCast.Core.Capture;
using Remotely.ScreenCast.Core.Models;
using Remotely.ScreenCast.Core.Services;
using Remotely.ScreenCast.Win.Capture;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Security.Principal;
using System.Windows.Input;
using Remotely.ScreenCast.Win.Services;
using Remotely.ScreenCast.Core.Interfaces;
using Remotely.ScreenCast.Core.Sockets;
namespace Remotely.Desktop.Win.ViewModels
{
public class MainWindowViewModel : ViewModelBase
{
private string host;
private string sessionID;
public MainWindowViewModel()
{
Current = this;
CursorIconWatcher = new CursorIconWatcher(Conductor);
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);
Conductor.SessionIDChanged += SessionIDChanged;
Conductor.ViewerRemoved += ViewerRemoved;
Conductor.ViewerAdded += ViewerAdded;
Conductor.ScreenCastRequested += ScreenCastRequested;
}
public static MainWindowViewModel Current { get; private set; }
public ICommand ChangeServerCommand
{
get
{
return new Executor(async (param) =>
{
PromptForHostName();
await Init();
});
}
}
public Conductor Conductor { get; }
public CursorIconWatcher CursorIconWatcher { get; private set; }
public string Host
{
get => host;
set
{
host = value;
FirePropertyChanged("Host");
}
}
public bool IsAdministrator => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
public ICommand RemoveViewersCommand
{
get
{
return new Executor(async (param) =>
{
foreach (Viewer viewer in (param as IList<object>))
{
viewer.DisconnectRequested = true;
await Conductor.CasterSocket.SendViewerRemoved(viewer.ViewerConnectionID);
}
},
(param) =>
{
return (param as IList<object>)?.Count > 0;
});
}
}
public ICommand RestartAsAdminCommand
{
get
{
return new Executor((param) =>
{
try
{
var psi = new ProcessStartInfo(Assembly.GetExecutingAssembly().Location);
psi.Verb = "RunAs";
Process.Start(psi);
Environment.Exit(0);
}
// Exception can be thrown if UAC is dialog is cancelled.
catch { }
}, (param) =>
{
return !IsAdministrator;
});
}
}
public string SessionID
{
get => sessionID;
set
{
sessionID = value;
FirePropertyChanged("SessionID");
}
}
public ObservableCollection<Viewer> Viewers { get; } = new ObservableCollection<Viewer>();
public void CopyLink()
{
Clipboard.SetText($"{Host}/RemoteControl?sessionID={SessionID.Replace(" ", "")}");
}
public async Task Init()
{
SessionID = "Retrieving...";
var config = Config.GetConfig();
Host = config.Host;
while (string.IsNullOrWhiteSpace(Host))
{
Host = "https://";
PromptForHostName();
}
Conductor.ProcessArgs(new string[] { "-mode", "Normal", "-host", Host });
try
{
await Conductor.Connect();
}
catch (Exception ex)
{
Logger.Write(ex);
MessageBox.Show(Application.Current.MainWindow, "Failed to connect to server.", "Connection Failed", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
await Conductor.CasterSocket.SendDeviceInfo(Conductor.ServiceID, Environment.MachineName, Conductor.DeviceID);
await Conductor.CasterSocket.GetSessionID();
}
public void PromptForHostName()
{
var prompt = new HostNamePrompt();
if (!string.IsNullOrWhiteSpace(Host))
{
HostNamePromptViewModel.Current.Host = Host;
}
prompt.Owner = App.Current?.MainWindow;
prompt.ShowDialog();
var result = HostNamePromptViewModel.Current.Host;
if (!result.StartsWith("https://") && !result.StartsWith("http://"))
{
result = $"https://{result}";
}
if (result != Host)
{
Host = result.TrimEnd('/');
var config = Config.GetConfig();
config.Host = Host;
config.Save();
}
}
private async void CursorIconWatcher_OnChange(object sender, CursorInfo cursor)
{
if (Conductor?.CasterSocket != null && Conductor?.Viewers?.Count > 0)
{
await Conductor?.CasterSocket?.SendCursorChange(cursor, Conductor.Viewers.Keys.ToList());
}
}
private void ScreenCastRequested(object sender, ScreenCastRequest screenCastRequest)
{
App.Current.Dispatcher.Invoke(() =>
{
var result = MessageBox.Show(Application.Current.MainWindow, $"You've received a connection request from {screenCastRequest.RequesterName}. Accept?", "Connection Request", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
Task.Run(async () =>
{
ICapturer capturer;
try
{
if (Conductor.Viewers.Count == 0)
{
capturer = new DXCapture();
}
else
{
capturer = new BitBltCapture();
}
}
catch (Exception ex)
{
Logger.Write(ex);
capturer = new BitBltCapture();
}
await Conductor.CasterSocket.SendCursorChange(CursorIconWatcher.GetCurrentCursor(), new List<string>() { screenCastRequest.ViewerID });
_ = Conductor.ScreenCaster.BeginScreenCasting(screenCastRequest);
});
}
});
}
private void SessionIDChanged(object sender, string sessionID)
{
var formattedSessionID = "";
for (var i = 0; i < sessionID.Length; i += 3)
{
formattedSessionID += sessionID.Substring(i, 3) + " ";
}
SessionID = formattedSessionID.Trim();
}
private void ViewerAdded(object sender, Viewer viewer)
{
App.Current.Dispatcher.Invoke(() =>
{
Viewers.Add(viewer);
});
}
private void ViewerRemoved(object sender, string viewerID)
{
App.Current.Dispatcher.Invoke(() =>
{
var viewer = Viewers.FirstOrDefault(x => x.ViewerConnectionID == viewerID);
if (viewer != null)
{
Viewers.Remove(viewer);
}
});
}
}
}