caching github folder content (fast loading)

This commit is contained in:
LarsBrubaker 2020-08-07 07:47:10 -07:00
parent 7ac7a295f2
commit 5d033bbdb4
2 changed files with 94 additions and 61 deletions

View file

@ -64,6 +64,8 @@ namespace MatterHackers.MatterControl.Library
public string RepoDirectory { get; }
private object locker = new object();
public GitHubContainer(string containerName, string account, string repositor, string repoDirectory)
{
this.ChildContainers = new List<ILibraryContainerLink>();
@ -74,40 +76,25 @@ namespace MatterHackers.MatterControl.Library
this.RepoDirectory = repoDirectory;
}
public override async void Load()
{
try
{
await GetRepo();
}
catch
{
// show an error
}
OnContentChanged();
}
// Get all files from a repo
public async Task GetRepo()
{
var client = new HttpClient();
await ReadDirectory("root",
client,
$"https://api.github.com/repos/{Account}/{Repository}/contents/{RepoDirectory}");
client.Dispose();
}
private async Task ReadDirectory(string name, HttpClient client, string uri)
public override void Load()
{
var uri = $"https://api.github.com/repos/{Account}/{Repository}/contents/{RepoDirectory}";
// get the directory contents
var request = new HttpRequestMessage(HttpMethod.Get, uri);
AddCromeHeaders(request);
WebCache.RetrieveText(uri,
(content) =>
{
lock (locker)
{
ParseJson(content);
}
},
false,
AddCromeHeaders);
}
private void ParseJson(string jsonStr)
{
// parse result
HttpResponseMessage response = client.SendAsync(request).Result;
string jsonStr = response.Content.ReadAsStringAsync().Result;
response.Dispose();
FileInfo[] dirContents = JsonConvert.DeserializeObject<FileInfo[]>(jsonStr);
// read in data
@ -136,7 +123,7 @@ namespace MatterHackers.MatterControl.Library
}
}
this.ChildContainers.Sort((a, b) => a.Name.CompareTo(b.Name));
OnContentChanged();
}
public static void AddCromeHeaders(HttpRequestMessage request)
@ -246,27 +233,8 @@ namespace MatterHackers.MatterControl.Library
public override async Task<ILibraryContainer> GetContainer(Action<double, string> reportProgress)
{
try
{
// download the .library file
var downLoadUrl = new HttpRequestMessage(HttpMethod.Get, path);
GitHubContainer.AddCromeHeaders(downLoadUrl);
using (var client = new HttpClient())
{
using (HttpResponseMessage contentResponse = await client.SendAsync(downLoadUrl))
{
var content = await contentResponse.Content.ReadAsStringAsync();
// parse it
return await LibraryJsonFile.ContainerFromJson(Name, content).GetContainer(null);
}
}
}
catch
{
}
return null;
var content = WebCache.GetCachedText(path, false, AddCromeHeaders);
return await LibraryJsonFile.ContainerFromJson(Name, content).GetContainer(null);
}
}
}

View file

@ -32,6 +32,7 @@ using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
@ -216,11 +217,68 @@ namespace MatterHackers.MatterControl
}
}
public static void RetrieveText(string uriToLoad, Action<string> updateResult)
/// <summary>
/// Return the first result that can be found (usually the cache). Wait up to 5 seconds to populate the cache
/// if it does not exist.
/// </summary>
/// <param name="uriToLoad"></param>
/// <param name="addToAppCache"></param>
/// <param name="addHeaders"></param>
/// <returns></returns>
public static string GetCachedText(string uriToLoad,
bool addToAppCache = true,
Action<HttpRequestMessage> addHeaders = null)
{
string results = null;
WebCache.RetrieveText(uriToLoad,
(content) =>
{
results = content;
},
false,
addHeaders);
var startTime = UiThread.CurrentTimerMs;
// wait up to 5 seconds for a response
while (results == null
&& UiThread.CurrentTimerMs < startTime + 5000)
{
Thread.Sleep(10);
}
return results;
}
/// <summary>
/// Retrieve text from a url async, but first return any existing cache of the text synchronously
/// </summary>
/// <param name="uriToLoad">The web path to find the text, will also be used as the cache key</param>
/// <param name="updateResult">A function to call when the text is received if it is different than the cache.</param>
/// <param name="addToAppCache">Add the results to a directory that can be copied into the main distribution,
/// or add them to a directory that is only for the local machine.</param>
public static void RetrieveText(string uriToLoad,
Action<string> updateResult,
bool addToAppCache = true,
Action<HttpRequestMessage> addHeaders = null)
{
if (addToAppCache)
{
RetrieveText(uriToLoad, "TextWebCache", updateResult, addHeaders);
}
else
{
RetrieveText(uriToLoad, "Text", updateResult, addHeaders);
}
}
private static void RetrieveText(string uriToLoad,
string cacheFolder,
Action<string> updateResult,
Action<HttpRequestMessage> addHeaders = null)
{
var longHash = uriToLoad.GetLongHashCode();
var appDataFileName = ApplicationController.CacheablePath("TextWebCache", longHash.ToString() + ".txt");
var appDataFileName = ApplicationController.CacheablePath(cacheFolder, longHash.ToString() + ".txt");
string fileText = null;
// first try the cache in the users applications folder
@ -237,7 +295,7 @@ namespace MatterHackers.MatterControl
}
else // We could not find it in the application cache. Check if it is in static data.
{
var staticDataPath = Path.Combine("TextWebCache", longHash.ToString() + ".txt");
var staticDataPath = Path.Combine(cacheFolder, longHash.ToString() + ".txt");
if (AggContext.StaticData.FileExists(staticDataPath))
{
@ -255,13 +313,20 @@ namespace MatterHackers.MatterControl
// whether we find it or not check the web for the latest version
Task.Run(async () =>
{
var client = new HttpClient();
var text = await client.GetStringAsync(uriToLoad);
if (!string.IsNullOrEmpty(text)
&& text != fileText)
var requestMessage = new HttpRequestMessage(HttpMethod.Get, uriToLoad);
addHeaders?.Invoke(requestMessage);
using (var client = new HttpClient())
{
File.WriteAllText(appDataFileName, text);
updateResult?.Invoke(text);
using (HttpResponseMessage response = await client.SendAsync(requestMessage))
{
var text = await response.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(text)
&& text != fileText)
{
File.WriteAllText(appDataFileName, text);
updateResult?.Invoke(text);
}
}
}
});
}