From e04967a34e0d2efd3081b0f19fc22c0c19945953 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 3 Nov 2022 22:54:54 +0000 Subject: [PATCH] Cache API results --- code/AddToolDialog.cs | 2 - code/GithubApi.cs | 14 ++++- code/Header.cs | 8 +-- code/Page.cs | 78 +++++++++++++++++++--------- code/ToolsManager.cs | 45 ++++++++++++++-- code/Types/Manifest.cs | 6 +++ code/Utils/LocalProjectExtensions.cs | 15 ++++++ 7 files changed, 132 insertions(+), 36 deletions(-) diff --git a/code/AddToolDialog.cs b/code/AddToolDialog.cs index c930f6f..96caf30 100644 --- a/code/AddToolDialog.cs +++ b/code/AddToolDialog.cs @@ -119,8 +119,6 @@ private async Task DownloadTool() info.CreateNoWindow = false; info.WorkingDirectory = folder; - Log.Trace( info.FileName + " " + info.Arguments ); - var process = new Process(); process.StartInfo = info; process.Start(); diff --git a/code/GithubApi.cs b/code/GithubApi.cs index fec823e..3b27610 100644 --- a/code/GithubApi.cs +++ b/code/GithubApi.cs @@ -1,5 +1,6 @@ using Sandbox; using System; +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; @@ -11,6 +12,8 @@ public static class GithubApi private static HttpClient httpClient; private static RealTimeUntil TimeUntilRatelimitReset; + private static Dictionary Cache = new(); + private static HttpClient HttpClient { get @@ -44,6 +47,11 @@ private static async Task FetchText( string url ) return "{}"; } + if ( Cache.TryGetValue( url, out var cachedResponse ) ) + { + return cachedResponse; + } + var content = await HttpClient.GetAsync( url ); var result = await content.Content.ReadAsStringAsync(); @@ -59,8 +67,10 @@ private static async Task FetchText( string url ) var timestamp = DateTime.UnixEpoch.AddSeconds( resetTime ); TimeUntilRatelimitReset = (float)(timestamp - DateTime.Now).TotalSeconds; } - - Log.Trace( $"{url} query: {result}" ); + else + { + Cache[url] = result; + } return result; } diff --git a/code/Header.cs b/code/Header.cs index c41f9b0..9e6044b 100644 --- a/code/Header.cs +++ b/code/Header.cs @@ -35,9 +35,9 @@ protected override void OnPaint() var r = Paint.DrawText( pos, Title ); pos.y = r.Bottom; - r.Left = r.Right; - r.Width = 32; - r.Top -= 4; - Paint.DrawIcon( r, "update", 16 ); + //r.Left = r.Right; + //r.Width = 32; + //r.Top -= 4; + //Paint.DrawIcon( r, "update", 16 ); } } diff --git a/code/Page.cs b/code/Page.cs index d904211..983d30d 100644 --- a/code/Page.cs +++ b/code/Page.cs @@ -1,6 +1,6 @@ using Sandbox; +using System.Diagnostics; using System.IO; -using System.Text.Json; namespace Tools; @@ -13,6 +13,7 @@ internal class Page : Widget private Label LatestReleaseBody; private Manifest Manifest; + private LocalProject Project; private bool HasFetched = false; @@ -20,42 +21,42 @@ public Page( LocalProject project, Widget parent = null, bool isDarkWindow = fal { SetLayout( LayoutMode.TopToBottom ); + this.Project = project; + Layout.Spacing = 8; Layout.Margin = 24; // // Check if we have a tools manager manifest // - var manifestPath = project.GetManifestPath(); + Manifest = project.GetManifest(); - if ( File.Exists( manifestPath ) ) + if ( Manifest != null ) { - // Load manifest - Manifest = JsonSerializer.Deserialize( File.ReadAllText( manifestPath ) ); - - AddManifestWidgets( project ); + AddManifestWidgets(); } else { // Display sad face - AddNoManifestWidgets( project ); + AddNoManifestWidgets(); } } - private void AddManifestWidgets( LocalProject project ) + private void AddManifestWidgets() { - var config = project.Config; + var config = Project.Config; Header = Layout.Add( new Header( config.Title ) ); Layout.AddSpacingCell( 8 ); { ToolBar = new ToolBar( this ); ToolBar.SetIconSize( 16 ); - var autoUpdateOption = new Option( "Toggle Auto-Updates", "file_download_off" ); - autoUpdateOption.Triggered = () => ToggleAutoUpdates( autoUpdateOption ); - var option = ToolBar.AddOption( autoUpdateOption ); - ToolBar.AddOption( "Open in Explorer", "folder", () => Utility.OpenFolder( Path.GetDirectoryName( project.GetRootPath() ) ) ); + // var autoUpdateOption = new Option( "Toggle Auto-Updates", Manifest.AutoUpdate ? "file_download" : "file_download_off" ); + // autoUpdateOption.Triggered = () => ToggleAutoUpdates( autoUpdateOption ); + // var option = ToolBar.AddOption( autoUpdateOption ); + + ToolBar.AddOption( "Open in Explorer", "folder", () => Utility.OpenFolder( Path.GetDirectoryName( Project.GetRootPath() ) ) ); ToolBar.AddOption( "Open on GitHub", "open_in_new", () => Utility.OpenFolder( $"https://github.com/{Manifest.Repo}" ) ); Layout.Add( ToolBar ); } @@ -67,18 +68,42 @@ private void AddManifestWidgets( LocalProject project ) Layout.AddStretchCell(); - var group = new Container( this ); - group.SetLayout( LayoutMode.TopToBottom ); - group.Layout.Margin = 10; - Layout.Add( group ); + if ( Manifest.CheckUpdateAvailable() ) + { + var group = new Container( this ); + group.SetLayout( LayoutMode.TopToBottom ); + group.Layout.Margin = 10; + Layout.Add( group ); + + group.Layout.Add( new Heading( "Update Available" ) ); + LatestReleaseName = group.Layout.Add( new Subheading( $"Loading..." ) ); + LatestReleaseBody = group.Layout.Add( new Label( $"Loading..." ) ); + + group.Layout.AddSpacingCell( 8f ); + + group.Layout.Add( new Button( "Download Update", "download" ) { Clicked = Update } ); + } + } + + private void Update() + { + GithubApi.FetchLatestRelease( $"{Manifest.Repo}" ).ContinueWith( t => + { + var release = t.Result ?? default; + + var folder = Project.GetRootPath(); - group.Layout.Add( new Heading( "Update Available" ) ); - LatestReleaseName = group.Layout.Add( new Subheading( $"Loading..." ) ); - LatestReleaseBody = group.Layout.Add( new Label( $"Loading..." ) ); + Log.Trace( folder ); - group.Layout.AddSpacingCell( 8f ); + ProcessStartInfo info = new( "git", $"checkout -B \"{release.TagName}\" --force" ); + info.UseShellExecute = false; + info.CreateNoWindow = false; + info.WorkingDirectory = folder; - group.Layout.Add( new Button( "Download Update", "download" ) ); + var process = new Process(); + process.StartInfo = info; + process.Start(); + } ); } private void ToggleAutoUpdates( Option option ) @@ -87,10 +112,10 @@ private void ToggleAutoUpdates( Option option ) option.Icon = Manifest.AutoUpdate ? "file_download" : "file_download_off"; } - private void AddNoManifestWidgets( LocalProject project ) + private void AddNoManifestWidgets() { Layout.Add( new Label.Title( "😔" ) ).SetStyles( "font-size: 64px;" ); - Layout.Add( new Label.Body( $"'{project.Config.Title}' does not have a manifest file, because you didn't import " + + Layout.Add( new Label.Body( $"'{Project.Config.Title}' does not have a manifest file, because you didn't import " + "it through Tools Manager. Remove the tool and re-add it from GitHub by clicking \"Add Tool...\" " + "in the bottom left." ) ); @@ -110,6 +135,9 @@ protected override void OnPaint() { var latestRelease = t.Result ?? default; + if ( LatestReleaseName == null || LatestReleaseBody == null ) + return; + LatestReleaseName.Text = latestRelease.Name; LatestReleaseBody.Text = latestRelease.Body; } ); diff --git a/code/ToolsManager.cs b/code/ToolsManager.cs index 7f8833f..3b44375 100644 --- a/code/ToolsManager.cs +++ b/code/ToolsManager.cs @@ -1,5 +1,6 @@ using System.IO; using System.Linq; +using System.Threading.Tasks; using Tools; [Tool( "Tools Manager", "hardware", "Manages your tools." )] @@ -59,7 +60,9 @@ public void CreateUI() if ( config.PackageType == Sandbox.Package.Type.Tool ) { var option = toolsList.AddPage( config.Title, "hardware", new Page( project ) ); - option.OnPaintOverride = () => PaintPageOption( option ); + var manifest = project.GetManifest(); + + option.OnPaintOverride = () => PaintPageOption( option, manifest ); } } @@ -73,7 +76,7 @@ public void CreateUI() update.Clicked = () => ToolUpdateNotice.Open( 4 ); } - private bool PaintPageOption( NavigationView.Option option ) + private bool PaintPageOption( NavigationView.Option option, Manifest manifest ) { var fg = Theme.White.WithAlpha( 0.5f ); @@ -106,7 +109,7 @@ private bool PaintPageOption( NavigationView.Option option ) iconRect.Left = inner.Right - 32; iconRect.Top -= 2; - if ( option.IsSelected ) + if ( manifest.CheckUpdateAvailable() ) { Paint.SetPen( fg ); Paint.DrawIcon( iconRect, "update", 14, TextFlag.Center ); @@ -116,4 +119,40 @@ private bool PaintPageOption( NavigationView.Option option ) return true; } + + // + // I'm going to use this event because it's a decent one + // that runs when the editor starts plus infrequently + // while developing, making it quite useful + // + [Sandbox.Event( "tools.compilemgr.start" )] + public static void OnCompileMgrStart() + { + var count = CheckForUpdates().Result; + + if ( count > 0 ) + ToolUpdateNotice.Open( count ); + } + + private static async Task CheckForUpdates() + { + int count = 0; + + foreach ( var project in Utility.Projects.GetAll() ) + { + var manifest = project.GetManifest(); + + if ( manifest == null ) + continue; + + Log.Trace( manifest ); + + var latest = await GithubApi.FetchLatestRelease( manifest.Repo ); + + if ( manifest.CheckUpdateAvailable( latest ) ) + count++; + } + + return count; + } } diff --git a/code/Types/Manifest.cs b/code/Types/Manifest.cs index b4c2161..e57de9d 100644 --- a/code/Types/Manifest.cs +++ b/code/Types/Manifest.cs @@ -32,4 +32,10 @@ public bool CheckUpdateAvailable( Release latestRelease ) { return latestRelease.TagName != ReleaseVersion; } + + public bool CheckUpdateAvailable() + { + var latestRelease = GithubApi.FetchLatestRelease( Repo ).Result; + return CheckUpdateAvailable( latestRelease ); + } } diff --git a/code/Utils/LocalProjectExtensions.cs b/code/Utils/LocalProjectExtensions.cs index 0ba54c6..7808522 100644 --- a/code/Utils/LocalProjectExtensions.cs +++ b/code/Utils/LocalProjectExtensions.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Text.Json; namespace Tools; @@ -8,4 +9,18 @@ public static string GetManifestPath( this Sandbox.LocalProject localProject ) { return Path.Combine( localProject.GetRootPath(), "tm-manifest.json" ); } + + public static Manifest GetManifest( this Sandbox.LocalProject localProject ) + { + if ( localProject.Config.PackageType != Sandbox.Package.Type.Tool ) + return null; + + if ( !File.Exists( localProject.GetManifestPath() ) ) + return null; + + var manifestStr = File.ReadAllText( localProject.GetManifestPath() ); + var manifest = JsonSerializer.Deserialize( manifestStr ); + + return manifest; + } }