From 611938eb9f761f5462badc6491ed1c0ba30880e5 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 22 Jan 2025 15:06:58 +1100 Subject: [PATCH 1/2] feat: add mocked tray app --- 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 | 178 +++++++++++ App/TrayWindow.xaml.cs | 302 ++++++++++++++++++ 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, 1044 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..66906cc --- /dev/null +++ b/App/TrayWindow.xaml @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/App/TrayWindow.xaml.cs b/App/TrayWindow.xaml.cs new file mode 100644 index 0000000..e83a107 --- /dev/null +++ b/App/TrayWindow.xaml.cs @@ -0,0 +1,302 @@ +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.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 string Hostname { get; set; } // without suffix + public 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 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. /// From 553a19a88cce546ce765141ab16f9a4369dbf7bc Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 22 Jan 2025 16:08:02 +1100 Subject: [PATCH 2/2] Populate hostname text from code --- App/TrayWindow.xaml | 14 +++----------- App/TrayWindow.xaml.cs | 25 +++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/App/TrayWindow.xaml b/App/TrayWindow.xaml index 66906cc..a779bb5 100644 --- a/App/TrayWindow.xaml +++ b/App/TrayWindow.xaml @@ -104,24 +104,16 @@ Canvas.Top="3" /> - + + Width="180" /> diff --git a/App/TrayWindow.xaml.cs b/App/TrayWindow.xaml.cs index e83a107..9e172b4 100644 --- a/App/TrayWindow.xaml.cs +++ b/App/TrayWindow.xaml.cs @@ -15,6 +15,7 @@ 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; @@ -30,8 +31,8 @@ public enum AgentStatus public partial class Agent { - public string Hostname { get; set; } // without suffix - public string Suffix { get; set; } + public required string Hostname { get; set; } // without suffix + public required string Suffix { get; set; } public AgentStatus Status { get; set; } public Brush StatusColor => Status switch @@ -82,6 +83,26 @@ private void AgentHostnameCopyButton_Click(object parameter) 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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy