From 6ecbc3f4b2b7ca73306f424d5d4a64e79bd1977f Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Fri, 24 Jan 2025 15:37:01 +1000 Subject: [PATCH] feat: add mocked tray app (#10) --- App/App.csproj | 48 +++ App/App.xaml | 14 + App/App.xaml.cs | 29 ++ App/Assets/coder_icon_32_dark.ico | Bin 0 -> 4314 bytes App/Assets/coder_icon_32_light.ico | Bin 0 -> 4314 bytes App/HorizontalRule.xaml | 16 + App/HorizontalRule.xaml.cs | 11 + App/TrayIcon.xaml | 72 ++++ App/TrayIcon.xaml.cs | 45 +++ App/TrayWindow.xaml | 170 +++++++++ App/TrayWindow.xaml.cs | 323 ++++++++++++++++++ App/app.manifest | 19 ++ Coder.Desktop.sln | 155 ++++++++- CoderSdk/CoderSdk.csproj | 3 +- Package/Images/SplashScreen.scale-200.png | Bin 0 -> 5372 bytes .../Images/Square150x150Logo.scale-200.png | Bin 0 -> 1755 bytes Package/Images/Square44x44Logo.scale-200.png | Bin 0 -> 637 bytes Package/Package.appxmanifest | 52 +++ Package/Package.wapproj | 67 ++++ Tests.Vpn.Service/TestHttpServer.cs | 4 +- Tests.Vpn/SpeakerTest.cs | 14 +- Vpn.Proto/RpcHeader.cs | 6 +- Vpn.Proto/RpcMessage.cs | 4 +- Vpn.Proto/RpcVersion.cs | 6 +- Vpn.Service/Downloader.cs | 18 +- Vpn/Speaker.cs | 16 +- Vpn/Utilities/BidirectionalPipe.cs | 16 +- 27 files changed, 1057 insertions(+), 51 deletions(-) create mode 100644 App/App.csproj create mode 100644 App/App.xaml create mode 100644 App/App.xaml.cs create mode 100644 App/Assets/coder_icon_32_dark.ico create mode 100644 App/Assets/coder_icon_32_light.ico create mode 100644 App/HorizontalRule.xaml create mode 100644 App/HorizontalRule.xaml.cs create mode 100644 App/TrayIcon.xaml create mode 100644 App/TrayIcon.xaml.cs create mode 100644 App/TrayWindow.xaml create mode 100644 App/TrayWindow.xaml.cs create mode 100644 App/app.manifest create mode 100644 Package/Images/SplashScreen.scale-200.png create mode 100644 Package/Images/Square150x150Logo.scale-200.png create mode 100644 Package/Images/Square44x44Logo.scale-200.png create mode 100644 Package/Package.appxmanifest create mode 100644 Package/Package.wapproj diff --git a/App/App.csproj b/App/App.csproj new file mode 100644 index 0000000..7a9ec8f --- /dev/null +++ b/App/App.csproj @@ -0,0 +1,48 @@ + + + WinExe + net8.0-windows10.0.19041.0 + 10.0.17763.0 + Coder.Desktop.App + app.manifest + x86;x64;ARM64 + win-x86;win-x64;win-arm64 + true + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + MSBuild:Compile + + + + + + MSBuild:Compile + + + + + + False + True + False + True + + diff --git a/App/App.xaml b/App/App.xaml new file mode 100644 index 0000000..a5b6d8b --- /dev/null +++ b/App/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/App/App.xaml.cs b/App/App.xaml.cs new file mode 100644 index 0000000..4fbde75 --- /dev/null +++ b/App/App.xaml.cs @@ -0,0 +1,29 @@ +using Microsoft.UI.Xaml; + +namespace Coder.Desktop.App; + +public partial class App : Application +{ + private TrayWindow? TrayWindow; + + public App() + { + InitializeComponent(); + } + + private bool HandleClosedEvents { get; } = true; + + protected override void OnLaunched(LaunchActivatedEventArgs args) + { + TrayWindow = new TrayWindow(); + TrayWindow.Closed += (sender, args) => + { + // TODO: wire up HandleClosedEvents properly + if (HandleClosedEvents) + { + args.Handled = true; + TrayWindow.AppWindow.Hide(); + } + }; + } +} diff --git a/App/Assets/coder_icon_32_dark.ico b/App/Assets/coder_icon_32_dark.ico new file mode 100644 index 0000000000000000000000000000000000000000..4eaa1bb2d71454c8888566329ceeac3b447dd805 GIT binary patch literal 4314 zcmeH|OQ=>=7>4)JqlRfIr9mJZE$UcGiCCG}FbGSDny5wh`=midK^hgIP-1}?VQ8Y( zD4GOa2%L;Q`5 zH2U9sFso_iHcc}Ma5Zaz{Ov=me#XYenv)oO2Fz~~nA``G%6Y;Y0>kEyi8>+S zKHRKvsIKdEOz_vd(pK--=nKK+;8Nof<>b)nKN1+MDX% zo@wNRKz*|Zpmp=nIUaWhVrvhGpF2Fk2ohY(!F_C$(PQfb?7{0 zX1mdo(@W+q*Sp>h9y2z&Ue50d*UA1{Sobb%xZNz!*8$zB$AI2lQtQ8_%2|p}^WOl@ zbN}|+VyAy*zog9VrIXX`oy76Y0QDVxCBFN>_262t5o`kb-On7;KlkrNso77G-_8NK z9$W=30E6|Yua~OyVjsPb9SB6%Z8Ua^U!k_Md~+hD$qX7Z{RR`3)SPf z2T0K!lKy)g>+Zc?z2hST;JrzkDLRvCv`WRRmWowBFXR8Fd%=z+EfEf@DEZi9P)M7s?G`5qh8@kPmPnZ L``u+M|Ig=d^#Snq literal 0 HcmV?d00001 diff --git a/App/Assets/coder_icon_32_light.ico b/App/Assets/coder_icon_32_light.ico new file mode 100644 index 0000000000000000000000000000000000000000..1fc307f97fe5adf039ef2da9202d6e18ed6e71f7 GIT binary patch literal 4314 zcmeH|ONdrw7{|}(=!BLgWq}}!7G82hMXbz9BSA_&fp;{c{?7LYv=zWa1URm*bERfZpgj z0cXH0)q{@)SAggiI0OcTFO32Hj_ZoAHDcdK7Tp9llGOWWRpd^LJoOjt3%mA($56W- z_}$-g?@|Hi95@V)furC^pc5`~uNl$n>)f2|zaba50rCjN)Db@S|0eRqPSnN9hVKEO zv6zmB{k1S??QR2IQHtLa_N}2e{TKM$|J#TYTOYCNRX&RY!#*7QH3dRffnughf%N~0 zIwCgL8jYV2QZLy}w!zE&H_LCIW6L&tKLC;TH9t3{;FLi?BA8*+`p|FC!IL|r%E{$ zwihDb{U?U~$*`OKi0}p22G#>TXR7%rFnuDM2!qyj7uXrlxe#gHMe`!=#au1UZrXq0 zTO7VRrtxU~9s!pk;IqgZhW>ll>ev>=iExgr1e`=)3(|VSXM(e!On-&)Rn!=Q{sw3d zU2_(Bujg96msduN-XHgPF9LM_5=Bh0?=k9LUkW}>0spS!cJ!eUKNxvy#lH@HId~O3 z6mi;{>YvUu{6iq}9%v{|giU9(=?+BK9uRfqEY0&G@}HsGzBjMZ{3WK`yFGHubZ@@X zoKcKJ=gDif!wGlbzRNY&x50+MeAPzw`JI6*^4l@K+Pkb1SF8o{%RqN(C(zu*HU7Dk zoT=Ef{`0^X`QW}k-QR0JrJP$QlUwW^`>{O;s(18kY^%W{umH>li-F#KucQ0>{+;BS zJ#q5WI>286bHG!e18Bc^ZFRQa0?UB*;G5tB@H%k+=aEHs+u!SVFi%h4Ga56J@7uA+ zs{bs|JSTfj$R6V~WYK@^zdKJ)Z|Bd*#hZ=11bhxQf-PVT&>NEG9%EgHF1nGk#srVC zCr+&A|54=mPWlynKS*m(t%2QVUVB6Ln)aRV9o?D3syTH!ajr8G*>}3R-nfB4`_yk> zD{_MBA-@Ymx+~m&Pxy*^udcUk282T9BZEUImy4m|u&oSidu2r30$D>}3 NmFyb#`Tu_f{s9P)GQ$7> literal 0 HcmV?d00001 diff --git a/App/HorizontalRule.xaml b/App/HorizontalRule.xaml new file mode 100644 index 0000000..706e9b7 --- /dev/null +++ b/App/HorizontalRule.xaml @@ -0,0 +1,16 @@ + + + + + + diff --git a/App/HorizontalRule.xaml.cs b/App/HorizontalRule.xaml.cs new file mode 100644 index 0000000..ffb86dc --- /dev/null +++ b/App/HorizontalRule.xaml.cs @@ -0,0 +1,11 @@ +using Microsoft.UI.Xaml.Controls; + +namespace Coder.Desktop.App; + +public sealed partial class HorizontalRule : UserControl +{ + public HorizontalRule() + { + InitializeComponent(); + } +} diff --git a/App/TrayIcon.xaml b/App/TrayIcon.xaml new file mode 100644 index 0000000..7f5dede --- /dev/null +++ b/App/TrayIcon.xaml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/App/TrayIcon.xaml.cs b/App/TrayIcon.xaml.cs new file mode 100644 index 0000000..db62e79 --- /dev/null +++ b/App/TrayIcon.xaml.cs @@ -0,0 +1,45 @@ +using System.Diagnostics; +using System.Windows.Input; +using Windows.UI.ViewManagement; +using DependencyPropertyGenerator; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Imaging; + +namespace Coder.Desktop.App; + +[DependencyProperty("OpenCommand")] +[DependencyProperty("ExitCommand")] +public sealed partial class TrayIcon : UserControl +{ + private readonly UISettings _uiSettings = new(); + + public TrayIcon() + { + InitializeComponent(); + _uiSettings.ColorValuesChanged += OnColorValuesChanged; + UpdateTrayIconBasedOnTheme(); + } + + private void OnColorValuesChanged(UISettings sender, object args) + { + DispatcherQueue.TryEnqueue(UpdateTrayIconBasedOnTheme); + } + + private void UpdateTrayIconBasedOnTheme() + { + var currentTheme = Application.Current.RequestedTheme; + Debug.WriteLine("Theme update requested, found theme: " + currentTheme); + + switch (currentTheme) + { + case ApplicationTheme.Dark: + TaskbarIcon.IconSource = (BitmapImage)Resources["IconDarkTheme"]; + break; + case ApplicationTheme.Light: + default: + TaskbarIcon.IconSource = (BitmapImage)Resources["IconLightTheme"]; + break; + } + } +} diff --git a/App/TrayWindow.xaml b/App/TrayWindow.xaml new file mode 100644 index 0000000..a779bb5 --- /dev/null +++ b/App/TrayWindow.xaml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/App/TrayWindow.xaml.cs b/App/TrayWindow.xaml.cs new file mode 100644 index 0000000..9e172b4 --- /dev/null +++ b/App/TrayWindow.xaml.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Runtime.InteropServices; +using Windows.ApplicationModel.DataTransfer; +using Windows.Foundation; +using Windows.Graphics; +using Windows.System; +using Windows.UI; +using Windows.UI.Core; +using CommunityToolkit.Mvvm.Input; +using Microsoft.UI; +using Microsoft.UI.Input; +using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Documents; +using Microsoft.UI.Xaml.Media; +using WinRT.Interop; +using WindowActivatedEventArgs = Microsoft.UI.Xaml.WindowActivatedEventArgs; + +namespace Coder.Desktop.App; + +public enum AgentStatus +{ + Green, + Red, + Gray, +} + +public partial class Agent +{ + public required string Hostname { get; set; } // without suffix + public required string Suffix { get; set; } + public AgentStatus Status { get; set; } + + public Brush StatusColor => Status switch + { + AgentStatus.Green => new SolidColorBrush(Color.FromArgb(255, 52, 199, 89)), + AgentStatus.Red => new SolidColorBrush(Color.FromArgb(255, 255, 59, 48)), + _ => new SolidColorBrush(Color.FromArgb(255, 142, 142, 147)), + }; + + [RelayCommand] + private void AgentHostnameButton_Click() + { + try + { + Process.Start(new ProcessStartInfo + { + // TODO: this should probably be more robust instead of just joining strings + FileName = "http://" + Hostname + Suffix, + UseShellExecute = true, + }); + } + catch + { + // TODO: log (notify?) + } + } + + [RelayCommand] + private void AgentHostnameCopyButton_Click(object parameter) + { + var dataPackage = new DataPackage + { + RequestedOperation = DataPackageOperation.Copy, + }; + dataPackage.SetText(Hostname + Suffix); + Clipboard.SetContent(dataPackage); + + if (parameter is not FrameworkElement frameworkElement) return; + + var flyout = new Flyout + { + Content = new TextBlock + { + Text = "DNS Copied", + Margin = new Thickness(4), + }, + }; + FlyoutBase.SetAttachedFlyout(frameworkElement, flyout); + FlyoutBase.ShowAttachedFlyout(frameworkElement); + } + + public void AgentHostnameText_OnLoaded(object sender, RoutedEventArgs e) + { + if (sender is not TextBlock textBlock) return; + textBlock.Inlines.Clear(); + textBlock.Inlines.Add(new Run + { + Text = Hostname, + Foreground = + (SolidColorBrush)Application.Current.Resources.ThemeDictionaries[ + "DefaultTextForegroundThemeBrush"], + }); + textBlock.Inlines.Add(new Run + { + Text = Suffix, + Foreground = + (SolidColorBrush)Application.Current.Resources.ThemeDictionaries[ + "SystemControlForegroundBaseMediumBrush"], + }); + } +} + +public sealed partial class TrayWindow : Window +{ + private const int WIDTH = 300; + + private NativeApi.POINT? _lastActivatePosition; + + public ObservableCollection Agents = + [ + new() + { + Hostname = "coder2", + Suffix = ".coder", + Status = AgentStatus.Green, + }, + new() + { + Hostname = "coder3", + Suffix = ".coder", + Status = AgentStatus.Red, + }, + new() + { + Hostname = "coder4", + Suffix = ".coder", + Status = AgentStatus.Gray, + }, + new() + { + Hostname = "superlongworkspacenamewhyisitsolong", + Suffix = ".coder", + Status = AgentStatus.Gray, + }, + ]; + + public TrayWindow() + { + InitializeComponent(); + AppWindow.Hide(); + SystemBackdrop = new DesktopAcrylicBackdrop(); + Activated += Window_Activated; + + // Setting OpenCommand and ExitCommand directly in the .xaml doesn't seem to work for whatever reason. + TrayIcon.OpenCommand = Tray_OpenCommand; + TrayIcon.ExitCommand = Tray_ExitCommand; + + if (Content is FrameworkElement frameworkElement) + frameworkElement.SizeChanged += Content_SizeChanged; + else + throw new Exception("Failed to get Content as FrameworkElement for window"); + + // Hide the title bar and buttons. WinUi 3 provides a method to do this with + // `ExtendsContentIntoTitleBar = true;`, but it automatically adds emulated title bar buttons that cannot be + // removed. + if (AppWindow.Presenter is not OverlappedPresenter presenter) + throw new Exception("Failed to get OverlappedPresenter for window"); + presenter.IsMaximizable = false; + presenter.IsMinimizable = false; + presenter.IsResizable = false; + presenter.IsAlwaysOnTop = true; + presenter.SetBorderAndTitleBar(true, false); + AppWindow.IsShownInSwitchers = false; + + // Ensure the corner is rounded. + var windowHandle = Win32Interop.GetWindowFromWindowId(AppWindow.Id); + var value = 2; + var result = NativeApi.DwmSetWindowAttribute(windowHandle, 33, ref value, Marshal.SizeOf()); + if (result != 0) throw new Exception("Failed to set window corner preference"); + } + + private void Content_SizeChanged(object sender, SizeChangedEventArgs e) + { + ResizeWindow(); + MoveWindow(); + } + + private void ResizeWindow() + { + if (Content is not FrameworkElement content) + throw new Exception("Failed to get Content as FrameworkElement for window"); + + // Measure the desired size of the content + content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + var desiredSize = content.DesiredSize; + + // Adjust the AppWindow size + var scale = GetDisplayScale(); + var height = (int)(desiredSize.Height * scale); + AppWindow.Resize(new SizeInt32(WIDTH, height)); + } + + private double GetDisplayScale() + { + var hwnd = WindowNative.GetWindowHandle(this); + var dpi = NativeApi.GetDpiForWindow(hwnd); + if (dpi == 0) return 1; // assume scale of 1 + return dpi / 96.0; // 96 DPI == 1 + } + + public void MoveResizeAndActivate() + { + SaveCursorPos(); + ResizeWindow(); + MoveWindow(); + AppWindow.Show(); + NativeApi.SetForegroundWindow(WindowNative.GetWindowHandle(this)); + } + + private void SaveCursorPos() + { + var res = NativeApi.GetCursorPos(out var cursorPosition); + if (res) + _lastActivatePosition = cursorPosition; + else + // When the cursor position is null, we will spawn the window in + // the bottom right corner of the primary display. + // TODO: log(?) an error when this happens + _lastActivatePosition = null; + } + + private void MoveWindow() + { + AppWindow.Move(GetWindowPosition()); + } + + private PointInt32 GetWindowPosition() + { + var height = AppWindow.Size.Height; + var cursorPosition = _lastActivatePosition; + if (cursorPosition is null) + { + var primaryWorkArea = DisplayArea.Primary.WorkArea; + return new PointInt32( + primaryWorkArea.Width - WIDTH, + primaryWorkArea.Height - height + ); + } + + // Spawn the window to the top right of the cursor. + var x = cursorPosition.Value.X + 10; + var y = cursorPosition.Value.Y - 10 - height; + + var workArea = DisplayArea.GetFromPoint( + new PointInt32(cursorPosition.Value.X, cursorPosition.Value.Y), + DisplayAreaFallback.Primary + ).WorkArea; + + // Adjust if the window goes off the right edge of the display. + if (x + WIDTH > workArea.X + workArea.Width) x = workArea.X + workArea.Width - WIDTH; + + // Adjust if the window goes off the bottom edge of the display. + if (y + height > workArea.Y + workArea.Height) y = workArea.Y + workArea.Height - height; + + // Adjust if the window goes off the left edge of the display (somehow). + if (x < workArea.X) x = workArea.X; + + // Adjust if the window goes off the top edge of the display (somehow). + if (y < workArea.Y) y = workArea.Y; + + return new PointInt32(x, y); + } + + private void Window_Activated(object sender, WindowActivatedEventArgs e) + { + // Close the window as soon as it loses focus. + if (e.WindowActivationState == WindowActivationState.Deactivated +#if DEBUG + // In DEBUG, holding SHIFT is required to have the window close when it loses focus. + && InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down) +#endif + ) + AppWindow.Hide(); + } + + private void ButtonBase_OnClick(object sender, RoutedEventArgs e) + { + Agents.Add(new Agent + { + Hostname = "cool", + Suffix = ".coder", + Status = AgentStatus.Gray, + }); + } + + [RelayCommand] + private void Tray_Open() + { + MoveResizeAndActivate(); + } + + [RelayCommand] + private void Tray_Exit() + { + // TODO: implement exit + } + + public class NativeApi + { + [DllImport("dwmapi.dll")] + public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attribute, ref int value, int size); + + [DllImport("user32.dll")] + public static extern bool GetCursorPos(out POINT lpPoint); + + [DllImport("user32.dll")] + public static extern bool SetForegroundWindow(IntPtr hwnd); + + [DllImport("user32.dll")] + public static extern int GetDpiForWindow(IntPtr hwnd); + + public struct POINT + { + public int X; + public int Y; + } + } +} diff --git a/App/app.manifest b/App/app.manifest new file mode 100644 index 0000000..28bdcff --- /dev/null +++ b/App/app.manifest @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + PerMonitorV2 + + + diff --git a/Coder.Desktop.sln b/Coder.Desktop.sln index c5fc598..e25c8fa 100644 --- a/Coder.Desktop.sln +++ b/Coder.Desktop.sln @@ -1,53 +1,192 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.Vpn", "Vpn\Vpn.csproj", "{B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}" +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35707.178 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn", "Vpn\Vpn.csproj", "{B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.Vpn.Proto", "Vpn.Proto\Vpn.Proto.csproj", "{318E78BB-E6AD-410F-8F3F-B680F6880293}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn.Proto", "Vpn.Proto\Vpn.Proto.csproj", "{318E78BB-E6AD-410F-8F3F-B680F6880293}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.Vpn.Service", "Vpn.Service\Vpn.Service.csproj", "{51B91794-0A2A-4F84-9935-8E17DD2AB260}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn.Service", "Vpn.Service\Vpn.Service.csproj", "{51B91794-0A2A-4F84-9935-8E17DD2AB260}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.Tests.Vpn", "Tests.Vpn\Tests.Vpn.csproj", "{D247B2E7-38A0-4A69-A710-7E8FAA7B807E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Vpn", "Tests.Vpn\Tests.Vpn.csproj", "{D247B2E7-38A0-4A69-A710-7E8FAA7B807E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.Tests.Vpn.Proto", "Tests.Vpn.Proto\Tests.Vpn.Proto.csproj", "{AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Vpn.Proto", "Tests.Vpn.Proto\Tests.Vpn.Proto.csproj", "{AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.Tests.Vpn.Service", "Tests.Vpn.Service\Tests.Vpn.Service.csproj", "{D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.Vpn.Service", "Tests.Vpn.Service\Tests.Vpn.Service.csproj", "{D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Coder.Desktop.CoderSdk", "CoderSdk\CoderSdk.csproj", "{A3D2B2B3-A051-46BD-A190-5487A9F24C28}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoderSdk", "CoderSdk\CoderSdk.csproj", "{A3D2B2B3-A051-46BD-A190-5487A9F24C28}" +EndProject +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "Package\Package.wapproj", "{C184988D-56E0-451F-B6A1-E5FE0405C80B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{800C7E2D-0D86-4554-9903-B879DA6FA2CE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|ARM64.Build.0 = Debug|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|x64.ActiveCfg = Debug|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|x64.Build.0 = Debug|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|x86.ActiveCfg = Debug|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Debug|x86.Build.0 = Debug|Any CPU {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|Any CPU.ActiveCfg = Release|Any CPU {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|Any CPU.Build.0 = Release|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|ARM64.ActiveCfg = Release|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|ARM64.Build.0 = Release|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|x64.ActiveCfg = Release|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|x64.Build.0 = Release|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|x86.ActiveCfg = Release|Any CPU + {B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}.Release|x86.Build.0 = Release|Any CPU {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|Any CPU.Build.0 = Debug|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|ARM64.Build.0 = Debug|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|x64.ActiveCfg = Debug|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|x64.Build.0 = Debug|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|x86.ActiveCfg = Debug|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Debug|x86.Build.0 = Debug|Any CPU {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|Any CPU.ActiveCfg = Release|Any CPU {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|Any CPU.Build.0 = Release|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|ARM64.ActiveCfg = Release|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|ARM64.Build.0 = Release|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|x64.ActiveCfg = Release|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|x64.Build.0 = Release|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|x86.ActiveCfg = Release|Any CPU + {318E78BB-E6AD-410F-8F3F-B680F6880293}.Release|x86.Build.0 = Release|Any CPU {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|ARM64.Build.0 = Debug|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|x64.ActiveCfg = Debug|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|x64.Build.0 = Debug|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|x86.ActiveCfg = Debug|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Debug|x86.Build.0 = Debug|Any CPU {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|Any CPU.ActiveCfg = Release|Any CPU {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|Any CPU.Build.0 = Release|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|ARM64.ActiveCfg = Release|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|ARM64.Build.0 = Release|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|x64.ActiveCfg = Release|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|x64.Build.0 = Release|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|x86.ActiveCfg = Release|Any CPU + {51B91794-0A2A-4F84-9935-8E17DD2AB260}.Release|x86.Build.0 = Release|Any CPU {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|ARM64.Build.0 = Debug|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|x64.ActiveCfg = Debug|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|x64.Build.0 = Debug|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|x86.ActiveCfg = Debug|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Debug|x86.Build.0 = Debug|Any CPU {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|Any CPU.ActiveCfg = Release|Any CPU {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|Any CPU.Build.0 = Release|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|ARM64.ActiveCfg = Release|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|ARM64.Build.0 = Release|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|x64.ActiveCfg = Release|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|x64.Build.0 = Release|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|x86.ActiveCfg = Release|Any CPU + {D247B2E7-38A0-4A69-A710-7E8FAA7B807E}.Release|x86.Build.0 = Release|Any CPU {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|ARM64.Build.0 = Debug|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|x64.ActiveCfg = Debug|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|x64.Build.0 = Debug|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|x86.ActiveCfg = Debug|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Debug|x86.Build.0 = Debug|Any CPU {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|Any CPU.Build.0 = Release|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|ARM64.ActiveCfg = Release|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|ARM64.Build.0 = Release|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|x64.ActiveCfg = Release|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|x64.Build.0 = Release|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|x86.ActiveCfg = Release|Any CPU + {AA3EEFF4-414B-4A83-8ACF-188C3C61CCE1}.Release|x86.Build.0 = Release|Any CPU {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|ARM64.Build.0 = Debug|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|x64.ActiveCfg = Debug|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|x64.Build.0 = Debug|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|x86.ActiveCfg = Debug|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Debug|x86.Build.0 = Debug|Any CPU {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|Any CPU.ActiveCfg = Release|Any CPU {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|Any CPU.Build.0 = Release|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|ARM64.ActiveCfg = Release|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|ARM64.Build.0 = Release|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|x64.ActiveCfg = Release|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|x64.Build.0 = Release|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|x86.ActiveCfg = Release|Any CPU + {D32E5FE1-C251-4A08-8EBE-B8D4F18A36F1}.Release|x86.Build.0 = Release|Any CPU {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|ARM64.Build.0 = Debug|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|x64.ActiveCfg = Debug|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|x64.Build.0 = Debug|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|x86.ActiveCfg = Debug|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Debug|x86.Build.0 = Debug|Any CPU {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|Any CPU.ActiveCfg = Release|Any CPU {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|Any CPU.Build.0 = Release|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|ARM64.ActiveCfg = Release|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|ARM64.Build.0 = Release|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|x64.ActiveCfg = Release|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|x64.Build.0 = Release|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|x86.ActiveCfg = Release|Any CPU + {A3D2B2B3-A051-46BD-A190-5487A9F24C28}.Release|x86.Build.0 = Release|Any CPU + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|Any CPU.ActiveCfg = Debug|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|Any CPU.Build.0 = Debug|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|Any CPU.Deploy.0 = Debug|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|ARM64.Build.0 = Debug|ARM64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|x64.ActiveCfg = Debug|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|x64.Build.0 = Debug|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|x64.Deploy.0 = Debug|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|x86.ActiveCfg = Debug|x86 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|x86.Build.0 = Debug|x86 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Debug|x86.Deploy.0 = Debug|x86 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|Any CPU.ActiveCfg = Release|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|Any CPU.Build.0 = Release|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|Any CPU.Deploy.0 = Release|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|ARM64.ActiveCfg = Release|ARM64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|ARM64.Build.0 = Release|ARM64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|ARM64.Deploy.0 = Release|ARM64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|x64.ActiveCfg = Release|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|x64.Build.0 = Release|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|x64.Deploy.0 = Release|x64 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|x86.ActiveCfg = Release|x86 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|x86.Build.0 = Release|x86 + {C184988D-56E0-451F-B6A1-E5FE0405C80B}.Release|x86.Deploy.0 = Release|x86 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|Any CPU.ActiveCfg = Debug|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|Any CPU.Build.0 = Debug|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|ARM64.Build.0 = Debug|ARM64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|x64.ActiveCfg = Debug|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|x64.Build.0 = Debug|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|x86.ActiveCfg = Debug|x86 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Debug|x86.Build.0 = Debug|x86 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|Any CPU.ActiveCfg = Release|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|Any CPU.Build.0 = Release|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|ARM64.ActiveCfg = Release|ARM64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|ARM64.Build.0 = Release|ARM64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x64.ActiveCfg = Release|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x64.Build.0 = Release|x64 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.ActiveCfg = Release|x86 + {800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/CoderSdk/CoderSdk.csproj b/CoderSdk/CoderSdk.csproj index 3a63532..1ca7d3c 100644 --- a/CoderSdk/CoderSdk.csproj +++ b/CoderSdk/CoderSdk.csproj @@ -1,6 +1,7 @@ - + + Coder.Desktop.CoderSdk net8.0 enable enable diff --git a/Package/Images/SplashScreen.scale-200.png b/Package/Images/SplashScreen.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..32f486a86792a5e34cd9a8261b394c49b48f86be GIT binary patch literal 5372 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 literal 0 HcmV?d00001 diff --git a/Package/Images/Square44x44Logo.scale-200.png b/Package/Images/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000000000000000000000000000000000..f713bba67f551ef91020b75716a4dc8ebd744b1c GIT binary patch literal 637 zcmeAS@N?(olHy`uVBq!ia0vp^5g^RL1|$oo8kjIJFu8cTIEGZ*dUI*J;2{SImxtDO zm%3!R$UazoY}x{$j0P5ABYXWr(l=jxJ6ps1W{tV=^>{Dl><3nv3A}sm=EZ)#l3`NR zpZda3^rNox*D1%NC98Z~L*6zipLw~Gxn&(Y-;KmJ+aR6eLabU-L#y8HW%7P-E_-VlLqIabbHPHKT*)fT@9iWJ7iWgOT9%0}Lrj>lztPxWq6sPw3pi z#-<=#$jjrP_DD*i!RLsn0mIA=>4~N)IMYWIf=j%-zuKCdMG%tHYot70D1| zvWa0wMhauW#S>1CnI_;>!1Q3zMA17@DOVq{MQ+{U7^a&yA+%dMCG;WNPV0i;w$tu; zX^b}UKziPM)(<;)ruW;-`)bBN+rQNM*Zs_>?n$|FVFo-e*PZb*@U7VAd+tHb4e + + + + + + + + + App (Package) + dean + Images\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package/Package.wapproj b/Package/Package.wapproj new file mode 100644 index 0000000..10fb751 --- /dev/null +++ b/Package/Package.wapproj @@ -0,0 +1,67 @@ + + + + 15.0 + + + + Debug + x86 + + + Release + x86 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ + App\ + + + + c184988d-56e0-451f-b6a1-e5fe0405c80b + 10.0.22621.0 + 10.0.17763.0 + net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) + en-US + false + ..\App\App.csproj + + + + Designer + + + + + + + + + + True + Properties\PublishProfiles\win-$(Platform).pubxml + + + + + + + + \ No newline at end of file diff --git a/Tests.Vpn.Service/TestHttpServer.cs b/Tests.Vpn.Service/TestHttpServer.cs index d33697f..4129b0d 100644 --- a/Tests.Vpn.Service/TestHttpServer.cs +++ b/Tests.Vpn.Service/TestHttpServer.cs @@ -15,8 +15,6 @@ public class TestHttpServer : IDisposable private readonly HttpListener _listener; private readonly Thread _listenerThread; - public string BaseUrl { get; private set; } - public TestHttpServer(Action handler) : this(ctx => { handler(ctx); @@ -77,6 +75,8 @@ public TestHttpServer(Func handler) _listenerThread.Start(); } + public string BaseUrl { get; private set; } + public void Dispose() { _cts.Cancel(); diff --git a/Tests.Vpn/SpeakerTest.cs b/Tests.Vpn/SpeakerTest.cs index 51950f7..0b1552b 100644 --- a/Tests.Vpn/SpeakerTest.cs +++ b/Tests.Vpn/SpeakerTest.cs @@ -16,6 +16,13 @@ internal class FailableStream : Stream private readonly TaskCompletionSource _writeTcs = new(); + public FailableStream(Stream inner, Exception? writeException, Exception? readException) + { + _inner = inner; + if (writeException != null) _writeTcs.SetException(writeException); + if (readException != null) _readTcs.SetException(readException); + } + public override bool CanRead => _inner.CanRead; public override bool CanSeek => _inner.CanSeek; public override bool CanWrite => _inner.CanWrite; @@ -27,13 +34,6 @@ public override long Position set => _inner.Position = value; } - public FailableStream(Stream inner, Exception? writeException, Exception? readException) - { - _inner = inner; - if (writeException != null) _writeTcs.SetException(writeException); - if (readException != null) _readTcs.SetException(readException); - } - public void SetWriteException(Exception ex) { _writeTcs.SetException(ex); diff --git a/Vpn.Proto/RpcHeader.cs b/Vpn.Proto/RpcHeader.cs index cf7ffcc..c81eb1d 100644 --- a/Vpn.Proto/RpcHeader.cs +++ b/Vpn.Proto/RpcHeader.cs @@ -9,9 +9,6 @@ public class RpcHeader { private const string Preamble = "codervpn"; - public string Role { get; } - public RpcVersionList VersionList { get; } - /// Role of the peer /// Version of the peer public RpcHeader(string role, RpcVersionList versionList) @@ -20,6 +17,9 @@ public RpcHeader(string role, RpcVersionList versionList) VersionList = versionList; } + public string Role { get; } + public RpcVersionList VersionList { get; } + /// /// Parse a header string into a SpeakerHeader. /// diff --git a/Vpn.Proto/RpcMessage.cs b/Vpn.Proto/RpcMessage.cs index bfe4d82..fc1af11 100644 --- a/Vpn.Proto/RpcMessage.cs +++ b/Vpn.Proto/RpcMessage.cs @@ -6,12 +6,12 @@ namespace Coder.Desktop.Vpn.Proto; [AttributeUsage(AttributeTargets.Class, Inherited = false)] public class RpcRoleAttribute : Attribute { - public string Role { get; } - public RpcRoleAttribute(string role) { Role = role; } + + public string Role { get; } } /// diff --git a/Vpn.Proto/RpcVersion.cs b/Vpn.Proto/RpcVersion.cs index 574768d..8eb0de0 100644 --- a/Vpn.Proto/RpcVersion.cs +++ b/Vpn.Proto/RpcVersion.cs @@ -7,9 +7,6 @@ public class RpcVersion { public static readonly RpcVersion Current = new(1, 0); - public ulong Major { get; } - public ulong Minor { get; } - /// The major version of the peer /// The minor version of the peer public RpcVersion(ulong major, ulong minor) @@ -18,6 +15,9 @@ public RpcVersion(ulong major, ulong minor) Minor = minor; } + public ulong Major { get; } + public ulong Minor { get; } + /// /// Parse a string in the format "major.minor" into an ApiVersion. /// diff --git a/Vpn.Service/Downloader.cs b/Vpn.Service/Downloader.cs index 83eda24..ea4c587 100644 --- a/Vpn.Service/Downloader.cs +++ b/Vpn.Service/Downloader.cs @@ -42,13 +42,13 @@ public class AuthenticodeDownloadValidator : IDownloadValidator { private readonly string _expectedName; - public static AuthenticodeDownloadValidator Coder => new("Coder Technologies Inc."); - public AuthenticodeDownloadValidator(string expectedName) { _expectedName = expectedName; } + public static AuthenticodeDownloadValidator Coder => new("Coder Technologies Inc."); + public async Task ValidateAsync(string path, CancellationToken ct = default) { FileSignatureInfo fileSigInfo; @@ -187,13 +187,6 @@ public class DownloadTask public readonly HttpRequestMessage Request; public readonly string TempDestinationPath; - public ulong? TotalBytes { get; private set; } - public ulong BytesRead { get; private set; } - public Task Task { get; private set; } = null!; // Set in EnsureStartedAsync - - public double? Progress => TotalBytes == null ? null : (double)BytesRead / TotalBytes.Value; - public bool IsCompleted => Task.IsCompleted; - internal DownloadTask(ILogger logger, HttpRequestMessage req, string destinationPath, IDownloadValidator validator) { _logger = logger; @@ -216,6 +209,13 @@ internal DownloadTask(ILogger logger, HttpRequestMessage req, string destination ".download-" + Path.GetRandomFileName()); } + public ulong? TotalBytes { get; private set; } + public ulong BytesRead { get; private set; } + public Task Task { get; private set; } = null!; // Set in EnsureStartedAsync + + public double? Progress => TotalBytes == null ? null : (double)BytesRead / TotalBytes.Value; + public bool IsCompleted => Task.IsCompleted; + internal async Task EnsureStartedAsync(CancellationToken ct = default) { using var _ = await _semaphore.LockAsync(ct); diff --git a/Vpn/Speaker.cs b/Vpn/Speaker.cs index 4c6ef3c..899c346 100644 --- a/Vpn/Speaker.cs +++ b/Vpn/Speaker.cs @@ -27,14 +27,6 @@ public class ReplyableRpcMessage : RpcMessage private readonly TR _message; private readonly Speaker _speaker; - public override RPC? RpcField - { - get => _message.RpcField; - set => _message.RpcField = value; - } - - public override TR Message => _message; - /// Speaker to use for sending reply /// Original received message public ReplyableRpcMessage(Speaker speaker, TR message) @@ -43,6 +35,14 @@ public ReplyableRpcMessage(Speaker speaker, TR message) _message = message; } + public override RPC? RpcField + { + get => _message.RpcField; + set => _message.RpcField = value; + } + + public override TR Message => _message; + public override void Validate() { _message.Validate(); diff --git a/Vpn/Utilities/BidirectionalPipe.cs b/Vpn/Utilities/BidirectionalPipe.cs index 72e633b..0792ce8 100644 --- a/Vpn/Utilities/BidirectionalPipe.cs +++ b/Vpn/Utilities/BidirectionalPipe.cs @@ -10,6 +10,14 @@ public class BidirectionalPipe : Stream private readonly Stream _reader; private readonly Stream _writer; + /// The stream to perform reads from + /// The stream to write data to + public BidirectionalPipe(Stream reader, Stream writer) + { + _reader = reader; + _writer = writer; + } + public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => true; @@ -21,14 +29,6 @@ public override long Position set => throw new NotImplementedException("BidirectionalPipe does not support setting position"); } - /// The stream to perform reads from - /// The stream to write data to - public BidirectionalPipe(Stream reader, Stream writer) - { - _reader = reader; - _writer = writer; - } - /// /// Creates a new pair of BidirectionalPipes that are connected to each other using buffered in-memory pipes. ///