diff --git a/Divvun.Installer.sln b/Divvun.Installer.sln index bb14e38..0754e36 100644 --- a/Divvun.Installer.sln +++ b/Divvun.Installer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29025.244 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33530.505 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Divvun.Installer", "Divvun.Installer\Divvun.Installer.csproj", "{B876899E-C40F-4D5A-84DE-8BF1B0064A28}" EndProject @@ -34,7 +34,7 @@ Global {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Debug|x86.ActiveCfg = Debug|Any CPU {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Debug|x86.Build.0 = Debug|Any CPU - {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Release|Any CPU.ActiveCfg = Release|x86 + {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Release|Any CPU.ActiveCfg = Release|Any CPU {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Release|x86.ActiveCfg = Release|x86 {20F56DAF-5D1D-421D-8BB0-203F2F591074}.Release|x86.Build.0 = Release|x86 {5C78E2EC-FF0C-4AEA-B146-DDCA6291C025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/Divvun.Installer/App.xaml.cs b/Divvun.Installer/App.xaml.cs index 676c0c3..95c278d 100644 --- a/Divvun.Installer/App.xaml.cs +++ b/Divvun.Installer/App.xaml.cs @@ -12,7 +12,6 @@ using System.Windows.Controls; using System.Windows.Media.Imaging; using Divvun.Installer.Models; -using Divvun.Installer.Properties; using Divvun.Installer.Service; using Divvun.Installer.UI.About; using Divvun.Installer.UI.Main; @@ -30,11 +29,13 @@ namespace Divvun.Installer { public partial class PahkatApp : Application, ISingleInstance { - // public static DispatcherScheduler Scheduler; + //public static DispatcherScheduler Scheduler; + public bool IsShutdown = false; public const string ArgsSilent = "-s"; - private const int AttachParentProcess = -1; + private const int AttachParentProcess = -1; + private CompositeDisposable _bag = new CompositeDisposable(); private TaskbarIcon _icon; diff --git a/Divvun.Installer/Strings.Designer.cs b/Divvun.Installer/Strings.Designer.cs index f14eff7..52d95d7 100644 --- a/Divvun.Installer/Strings.Designer.cs +++ b/Divvun.Installer/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace Divvun.Installer { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Strings { @@ -672,6 +672,15 @@ public static string OpenPackageManager { } } + /// + /// Looks up a localized string similar to Failed to connect to the Pahkat Windows Service. Please verify that it is running and restart Divvun Manager.. + /// + public static string PahkatServiceConnectionException { + get { + return ResourceManager.GetString("PahkatServiceConnectionException", resourceCulture); + } + } + /// /// Looks up a localized string similar to Paste. /// diff --git a/Divvun.Installer/Strings.resx b/Divvun.Installer/Strings.resx index e2167b5..41c43db 100644 --- a/Divvun.Installer/Strings.resx +++ b/Divvun.Installer/Strings.resx @@ -1,490 +1,488 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, - PublicKeyToken=b77a5c561934e089 - - - + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + About Divvun Manager - + Alpha - + Help - + Divvun Manager - + Divvun Manager v{0} is now available. It is highly recommended that you update as soon as possible. Update now? - + Divvun Manager is updating... - + Divvun Manager Update Available - + Beta - + Bring All to Front - + Cancel - + Are you sure you want to cancel all downloads? - + Cancel Downloads - + Canceling... - + Category - + Channel - + Check for Updates... - + Completed - + Copy - + Do you wish to send a crash report to the developers? No personal or private information is sent. (Recommended) - + Cut - + Daily - + Delete - + Error 😞 - + Downloaded - + Downloading... - + Edit - + Error - + An error occurring during installation. - + Error: Invalid Version - + Error: No Installer - + Error: Unknown Item - + Every 4 Weeks - + Every 2 Weeks - + Exit - + Finish - + Help - + Hide Divvun Manager - + Hide Others - + Install - + Install {0} Items - + Install (System) - + Install/Uninstall {0} Items - + Install (User) - + Installed - + Installing {0} {1}... - + Installing/Uninstalling - + Interface Language - + Please ensure that the URL begins with \"https\" and try again. - + The provided URL is invalid. - + Language - + Loading... - + Minimize - + {0} items remaining. - + {0} Updates Available - + Never - + Next update check at: {0} - + Nightly - + No Items Selected - + No new updates were found. - + No Updates - - - - + + + + Not Installed - + OK - + Open Divvun Manager - + Paste - + Paste and Match Style - + Preferences… - + You may now close this window, or return to the main screen. - + Done! - + Queued - + Quit Divvun Manager - + Redo - + Remind Me Later - + Are you sure you wish to remove this repository? - + This will remove the selected repository. - + Repositories - + Repository - + Repository Error - + There was an error while opening the repository: {0} - + Restart Later - + Restart Now - + It is highly recommended that you restart your computer in order for some changes to take effect. - + Time to reboot! - + Restart the app for language changes to take effect. - + Save - + Select All - + Services - + Settings - + Show All - + Skip These Updates - - Sort by - - + + Sort by + + Stable - + Starting... - + Default Language - + There are {0} updates available! - + Undo - + Uninstall - + Uninstall {0} Items - + Uninstalling {0} {1}... - + Update - + Update Available - + Update Channel - + Update Frequency - + Update (System) - + Update (User) - + URL - + {0} (User) - + Version Skipped - + Waiting for process to finish... - + Weekly - + Window - + Would you like to download them now? - + Zoom - + Refresh - + Search - + Beta Update Available - + You are using a developer mode channel override. Would you like to update to the latest beta? - + You need administrator rights to complete this action. - + Authentication Failed - - All Repositories - - - Generate debugging zip file... - + + All Repositories + + + Generate debugging zip file... + + + Failed to connect to the Pahkat Windows Service. Please verify that it is running and restart Divvun Manager. + \ No newline at end of file diff --git a/Divvun.Installer/UI/Main/LandingPage.xaml.cs b/Divvun.Installer/UI/Main/LandingPage.xaml.cs index 0eca81b..bc413df 100644 --- a/Divvun.Installer/UI/Main/LandingPage.xaml.cs +++ b/Divvun.Installer/UI/Main/LandingPage.xaml.cs @@ -132,64 +132,95 @@ private async void SetRepository(Uri? url) { var app = (PahkatApp)Application.Current; var pahkat = app.PackageStore; - var repos = await pahkat.RepoIndexes(); - var records = await pahkat.GetRepoRecords(); - TitleBarHandler.RefreshFlyoutItems(TitleBarReposButton, TitleBarReposFlyout, - repos.Values.ToArray(), records); - - await app.Dispatcher.InvokeAsync(() => { - ILoadedRepository? repo = null; - if (url == null) { - if (records.IsNullOrEmpty()) { - ShowNoLandingPage(); - return; + try + { + var repos = await pahkat.RepoIndexes(); + var records = await pahkat.GetRepoRecords(); + + TitleBarHandler.RefreshFlyoutItems(TitleBarReposButton, TitleBarReposFlyout, + repos.Values.ToArray(), records); + + await app.Dispatcher.InvokeAsync(() => + { + ILoadedRepository? repo = null; + if (url == null) + { + if (records.IsNullOrEmpty()) + { + ShowNoLandingPage(); + return; + } + + if (!repos.Values.IsNullOrEmpty()) + { + repo = repos.Values.First(r => records.ContainsKey(r.Index.Url)); + } + + if (repo == null) + { + ShowNoLandingPage(); + return; + } } - - if (!repos.Values.IsNullOrEmpty()) { - repo = repos.Values.First(r => records.ContainsKey(r.Index.Url)); + else if (url.Scheme == "divvun-installer") + { + if (url.AbsolutePath == "detailed") + { + ShowNoLandingPage(); + return; + } } - - if (repo == null) { - ShowNoLandingPage(); - return; + else + { + if (!repos.Values.IsNullOrEmpty()) + { + repo = repos.Values.First(r => r.Index.Url == url); + repo ??= repos.Values.First(r => records.ContainsKey(r.Index.Url)); + } + + if (repo == null) + { + ShowNoLandingPage(); + return; + } } - } - else if (url.Scheme == "divvun-installer") { - if (url.AbsolutePath == "detailed") { - ShowNoLandingPage(); + + if (repo == null) + { + app.Settings.Mutate(file => + { + Log.Warning("No repository found, setting selected repo to null"); + file.SelectedRepository = null; + }); return; } - } - else { - if (!repos.Values.IsNullOrEmpty()) { - repo = repos.Values.First(r => r.Index.Url == url); - repo ??= repos.Values.First(r => records.ContainsKey(r.Index.Url)); - } - if (repo == null) { + if (repo.Index.LandingUrl == null) + { ShowNoLandingPage(); return; } - } - - if (repo == null) { - app.Settings.Mutate(file => { - Log.Warning("No repository found, setting selected repo to null"); - file.SelectedRepository = null; - }); - return; - } - if (repo.Index.LandingUrl == null) { - ShowNoLandingPage(); - return; + TitleBarReposButton.Content = repo.Index.NativeName(); + _webBridge.SetRepository(repo); + _webView.Load(repo.Index.LandingUrl.SetQueryParam("ts", DateTimeOffset.UtcNow)); + }); + } + catch (PahkatServiceConnectionException) + { + var current = (PahkatApp)Application.Current; + + if (!current.IsShutdown) { + current.IsShutdown = true; + MessageBox.Show(Strings.PahkatServiceConnectionException); + Application.Current.Dispatcher.Invoke(() => + { + Application.Current.Shutdown(1); + } + ); } - - TitleBarReposButton.Content = repo.Index.NativeName(); - _webBridge.SetRepository(repo); - _webView.Load(repo.Index.LandingUrl.SetQueryParam("ts", DateTimeOffset.UtcNow)); - }); + } } private async Task ProcessRequest(string rawRequest) { diff --git a/Divvun.Installer/UI/Main/MainPage.xaml.cs b/Divvun.Installer/UI/Main/MainPage.xaml.cs index c887b68..4af3e10 100644 --- a/Divvun.Installer/UI/Main/MainPage.xaml.cs +++ b/Divvun.Installer/UI/Main/MainPage.xaml.cs @@ -15,6 +15,7 @@ using System.Windows.Threading; using Divvun.Installer.Extensions; using Divvun.Installer.UI.Shared; +using Pahkat.Sdk.Rpc; namespace Divvun.Installer.UI.Main { @@ -158,12 +159,28 @@ private async void Page_Loaded(object sender, RoutedEventArgs e) { _presenter.Start().DisposedBy(_bag); TitleBarHandler.BindRepoDropdown(_bag, async x => { - var app = (PahkatApp)Application.Current; - var repos = (await app.PackageStore.RepoIndexes()).Values.ToArray(); - var records = await app.PackageStore.GetRepoRecords(); + try { + var app = (PahkatApp)Application.Current; + var repos = (await app.PackageStore.RepoIndexes()).Values.ToArray(); + var records = await app.PackageStore.GetRepoRecords(); - TitleBarHandler.RefreshFlyoutItems(TitleBarReposButton, TitleBarReposFlyout, repos, records); - // _presenter.BindNewRepositories(_sortedBy.Value); + TitleBarHandler.RefreshFlyoutItems(TitleBarReposButton, TitleBarReposFlyout, repos, records); + // _presenter.BindNewRepositories(_sortedBy.Value); + } + catch (PahkatServiceConnectionException) + { + var current = (PahkatApp)Application.Current; + + if (!current.IsShutdown) { + current.IsShutdown = true; + MessageBox.Show(Strings.PahkatServiceConnectionException); + Application.Current.Dispatcher.Invoke(() => + { + Application.Current.Shutdown(1); + } + ); + } + } }); ConfigureSortBy(); diff --git a/Divvun.Installer/UI/Main/MainPagePresenter.cs b/Divvun.Installer/UI/Main/MainPagePresenter.cs index a25fadb..0914612 100644 --- a/Divvun.Installer/UI/Main/MainPagePresenter.cs +++ b/Divvun.Installer/UI/Main/MainPagePresenter.cs @@ -155,40 +155,55 @@ private async Task FilterByCategory(ILoadedRepository repo) { internal async Task BindNewRepositories(SortBy sortBy) { var app = PahkatApp.Current; - var repos = (await app.PackageStore.RepoIndexes()).Values; - var records = await app.PackageStore.GetRepoRecords(); - _tree.Clear(); + try { + var repos = (await app.PackageStore.RepoIndexes()).Values; + var records = await app.PackageStore.GetRepoRecords(); - var sorted = new SortedSet(); + _tree.Clear(); - if (repos.IsNullOrEmpty()) { - Log.Debug("Repository empty."); - _view.UpdateTitle(Strings.AppName); - return; - } + var sorted = new SortedSet(); - foreach (var repo in repos) { - if (!records.ContainsKey(repo.Index.Url)) { - continue; + if (repos.IsNullOrEmpty()) { + Log.Debug("Repository empty."); + _view.UpdateTitle(Strings.AppName); + return; } - switch (sortBy) { - case SortBy.Category: - sorted.Add(await FilterByCategory(repo)); - break; - case SortBy.Language: - sorted.Add(FilterByLanguage(repo)); - break; + foreach (var repo in repos) { + if (!records.ContainsKey(repo.Index.Url)) { + continue; + } + + switch (sortBy) { + case SortBy.Category: + sorted.Add(await FilterByCategory(repo)); + break; + case SortBy.Language: + sorted.Add(FilterByLanguage(repo)); + break; + } } - } - foreach (var repoTreeItem in sorted) { - _tree.Add(repoTreeItem); - } + foreach (var repoTreeItem in sorted) { + _tree.Add(repoTreeItem); + } - _view.UpdateTitle(Strings.AppName); - Log.Debug("Added packages."); + _view.UpdateTitle(Strings.AppName); + Log.Debug("Added packages."); + } + catch (PahkatServiceConnectionException) + { + MessageBox.Show( + Strings.PahkatServiceConnectionException + ); + Application.Current.Dispatcher.Invoke( + () => + { + Application.Current.Shutdown(1); + } + ); + } } private void GeneratePrimaryButtonLabel(Dictionary packages) { diff --git a/Divvun.Installer/UI/Settings/SettingsWindow.xaml.cs b/Divvun.Installer/UI/Settings/SettingsWindow.xaml.cs index 6a36d53..4e005b0 100644 --- a/Divvun.Installer/UI/Settings/SettingsWindow.xaml.cs +++ b/Divvun.Installer/UI/Settings/SettingsWindow.xaml.cs @@ -12,6 +12,7 @@ using ModernWpf.Controls; using Pahkat.Sdk; using Pahkat.Sdk.Rpc; +using Serilog; namespace Divvun.Installer.UI.Settings { @@ -147,50 +148,64 @@ private void OnLoaded(object sender, RoutedEventArgs e) { private async Task RefreshRepoTable() { var app = (PahkatApp)Application.Current; - var repos = await app.PackageStore.RepoIndexes(); - var repoRecords = await app.PackageStore.GetRepoRecords(); - var repoStrings = await app.PackageStore.Strings(app.Settings.GetLanguage() ?? "en"); - - RepoList.Clear(); - - foreach (var keyValuePair in repoRecords) { - var name = keyValuePair.Key.AbsoluteUri; - if (repos.TryGetValue(keyValuePair.Key, out var repo)) { - name = repo.Index.NativeName(); - } - else { - name += " ⚠️"; - } + try { + var repos = await app.PackageStore.RepoIndexes(); + var repoRecords = await app.PackageStore.GetRepoRecords(); + var repoStrings = await app.PackageStore.Strings(app.Settings.GetLanguage() ?? "en"); - var strings = repoStrings.Get(keyValuePair.Key); - - var channels = new List(); - if (strings != null) { - var defaultString = strings.Channels.Get("default"); + RepoList.Clear(); - if (defaultString == null) { - channels.Add(ChannelMenuItem.Create(Strings.Stable, "")); + foreach (var keyValuePair in repoRecords) { + var name = keyValuePair.Key.AbsoluteUri; + if (repos.TryGetValue(keyValuePair.Key, out var repo)) { + name = repo.Index.NativeName(); } else { - channels.Add(ChannelMenuItem.Create(defaultString, "")); + name += " ⚠️"; } + + var strings = repoStrings.Get(keyValuePair.Key); + + var channels = new List(); + if (strings != null) { + var defaultString = strings.Channels.Get("default"); + + if (defaultString == null) { + channels.Add(ChannelMenuItem.Create(Strings.Stable, "")); + } + else { + channels.Add(ChannelMenuItem.Create(defaultString, "")); + } - foreach (var channelPair in strings.Channels) { - if (channelPair.Key == "default") { - continue; - } + foreach (var channelPair in strings.Channels) { + if (channelPair.Key == "default") { + continue; + } - channels.Add(ChannelMenuItem.Create(channelPair.Value, channelPair.Key)); + channels.Add(ChannelMenuItem.Create(channelPair.Value, channelPair.Key)); + } + } + else { + channels.Add(ChannelMenuItem.Create(Strings.Stable, "")); } - } - else { - channels.Add(ChannelMenuItem.Create(Strings.Stable, "")); - } - var selectedChannel = keyValuePair.Value.Channel ?? ""; + var selectedChannel = keyValuePair.Value.Channel ?? ""; - RepoList.Add(new RepositoryListItem(keyValuePair.Key, name, channels, selectedChannel)); + RepoList.Add(new RepositoryListItem(keyValuePair.Key, name, channels, selectedChannel)); + } + } + catch (PahkatServiceConnectionException) + { + MessageBox.Show( + Strings.PahkatServiceConnectionException + ); + Application.Current.Dispatcher.Invoke( + () => + { + Application.Current.Shutdown(1); + } + ); } } diff --git a/Pahkat.Sdk.Rpc/pahkat_rpc.cs b/Pahkat.Sdk.Rpc/pahkat_rpc.cs index 183638e..081de61 100644 --- a/Pahkat.Sdk.Rpc/pahkat_rpc.cs +++ b/Pahkat.Sdk.Rpc/pahkat_rpc.cs @@ -15,6 +15,7 @@ using Newtonsoft.Json; using Pahkat.Sdk.Grpc; using Pahkat.Sdk.Rpc.Models; +using Serilog; namespace Pahkat.Sdk.Rpc { @@ -77,6 +78,7 @@ public PahkatClient() { HttpHandler = CreateHttpHandler(), MaxReceiveMessageSize = null, MaxSendMessageSize = null, + ThrowOperationCanceledOnCancellation = true, }); innerClient = new Grpc.Pahkat.PahkatClient(channel); @@ -200,12 +202,24 @@ public async Task> RemoveRepo(Uri url) { } public async Task> RepoIndexes() { - var response = await innerClient.RepositoryIndexesAsync(new RepositoryIndexesRequest()); - return response.Repositories.Map(repo => { - var ser = JsonConvert.SerializeObject(repo); - var de = JsonConvert.DeserializeObject(ser); - return (de.Index.Url, (ILoadedRepository)de); - }).ToDict(); + try + { + var response = await innerClient.RepositoryIndexesAsync(new RepositoryIndexesRequest()); + return response.Repositories.Map(repo => + { + var ser = JsonConvert.SerializeObject(repo); + var de = JsonConvert.DeserializeObject(ser); + return (de.Index.Url, (ILoadedRepository)de); + }).ToDict(); + } + catch (RpcException ex) when (ex.Status.Detail.Contains("TimeoutException: The operation has timed out.")) + { + throw new PahkatServiceConnectionException("Failed to connect to the Pahkat Service", ex); + } + catch + { + throw; + } } public async Task ResolvePackageQuery(PackageQuery query) { @@ -275,14 +289,24 @@ public async ValueTask ConnectAsync(SocketsHttpConnectionContext _, TokenImpersonationLevel.Identification); try { - await namedPipe.ConnectAsync(cancellationToken).ConfigureAwait(false); + Log.Debug("Connecting to Pahkat Service Named Pipe."); + await namedPipe.ConnectAsync(2000, cancellationToken).ConfigureAwait(false); return namedPipe; } catch { + Log.Debug("Failed to connect to Pahkat Service Named Pipe."); namedPipe.Dispose(); throw; } } } -} \ No newline at end of file +public class PahkatServiceConnectionException : Exception +{ public PahkatServiceConnectionException() { } + + public PahkatServiceConnectionException(string message) : base(message) { } + + public PahkatServiceConnectionException(string message, Exception inner) : base(message, inner) { } +} + +}