Skip to content
This repository has been archived by the owner on Mar 22, 2023. It is now read-only.

Commit

Permalink
todo: fix async code, and get GitHub API key or figure out this shit …
Browse files Browse the repository at this point in the history
…faster than the API rate limits block debugging.
  • Loading branch information
retailcoder committed May 20, 2019
1 parent 9d9c8a7 commit fb1620a
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 35 deletions.
51 changes: 51 additions & 0 deletions RubberduckWeb/RubberduckWeb/Content/Site.css
Expand Up @@ -2,6 +2,52 @@
padding-bottom: 20px;
}

.tooltip {
position: relative;
display: inline-block;
border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}

/* Tooltip text */
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
padding: 5px 0;
border-radius: 6px;

/* Position the tooltip text */
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;

/* Fade in tooltip */
opacity: 0;
transition: opacity 0.3s;
}

/* Tooltip arrow */
.tooltip .tooltiptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}

/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}

/* Set padding to keep content from hitting the edges */
.body-content {
padding-left: 15px;
Expand Down Expand Up @@ -131,6 +177,11 @@ section {
margin-top: 0px;
}

.pre-release {
color: maroon;

}

#code {
width: 100%;
}
Expand Down
17 changes: 14 additions & 3 deletions RubberduckWeb/RubberduckWeb/Controllers/BuildController.cs
Expand Up @@ -2,8 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using RubberduckWeb.Models;

namespace RubberduckWeb.Controllers
{
Expand All @@ -15,13 +17,22 @@ public ActionResult Index()
return View("Version");
}

public ActionResult Version(string id)
public ActionResult Version(string id = null)
{
var version = string.Empty;
if (RubberduckReleaseBuilds.ShouldInvalidate)
{
var task = Task.Run(async () => await RubberduckReleaseBuilds.InvalidateAsync());
task.Wait();
}

if (string.Equals(id, "stable", StringComparison.OrdinalIgnoreCase))
if (string.IsNullOrWhiteSpace(id))
{
version = RubberduckReleaseBuilds.LatestPreReleaseVersion.ToString();
}
else if (string.Equals(id, "stable", StringComparison.OrdinalIgnoreCase))
{
version = Assembly.GetAssembly(typeof(Rubberduck._Extension)).GetName().Version.ToString();
version = RubberduckReleaseBuilds.LatestStableVersion.ToString();
}

// If we leave `version` without casting to an `object`, it'll try to find a view with that name.
Expand Down
33 changes: 31 additions & 2 deletions RubberduckWeb/RubberduckWeb/Controllers/InspectionsController.cs
@@ -1,4 +1,6 @@
using System.Web.Mvc;
using System;
using System.Threading.Tasks;
using System.Web.Mvc;
using RubberduckWeb.Models;

namespace RubberduckWeb.Controllers
Expand All @@ -8,7 +10,34 @@ public class InspectionsController : Controller
{
public ActionResult Index() => RedirectToAction("List");

public ActionResult List() => View(RubberduckInspections.Inspections.Values);
public ActionResult List()
{
if (RubberduckInspections.ShouldInvalidate)
{
// todo async controller method to await the invalidate task?
try
{
Task.Delay(0).ContinueWith(t => ValidateInspectionsCache()).Wait();
}
catch (Exception e)
{
throw;
}
}
return View(RubberduckInspections.Inspections.Values);
}

private async Task ValidateInspectionsCache()
{
try
{
await RubberduckInspections.InvalidateAsync();
}
catch (Exception e)
{
throw;
}
}

public ActionResult Details(string id)
{
Expand Down
135 changes: 107 additions & 28 deletions RubberduckWeb/RubberduckWeb/Models/RubberduckInspections.cs
Expand Up @@ -2,59 +2,138 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using Octokit;

namespace RubberduckWeb.Models
{
public static class RubberduckInspections
public static class RubberduckReleaseBuilds
{
private static readonly string XmlDocumentationUrl =
"https://raw.githubusercontent.com/rubberduck-vba/Rubberduck/next/docs/Rubberduck.CodeAnalysis.xml";
private const string GitHubOrg = "rubberduck-vba";
private const string RepositoryName = "Rubberduck";

private static readonly string VersionPattern = @"v(?<major>\d+)\.(?<minor>\d+)\.(?<revision>\d+)\.(?<build>\d+)";

private static DateTime _lastInvalalidated;

static RubberduckInspections()
public static async Task InvalidateAsync()
{
Invalidate();
var client = new GitHubClient(new ProductHeaderValue("rubberduck-vba_RubberduckWEB"));
var releases = await client.Repository.Release.GetAll(GitHubOrg, RepositoryName);
var stable = releases.FirstOrDefault(e => !e.Prerelease);
var pre = releases.FirstOrDefault(e => e.Prerelease);

var stableVersion = Regex.Match(stable.Name, VersionPattern);
LatestStableVersion = new Version(
int.Parse(stableVersion.Groups["major"].Value),
int.Parse(stableVersion.Groups["minor"].Value),
int.Parse(stableVersion.Groups["revision"].Value),
int.Parse(stableVersion.Groups["build"].Value));

var preVersion = Regex.Match(pre.Name, VersionPattern);
LatestPreReleaseVersion = new Version(
int.Parse(preVersion.Groups["major"].Value),
int.Parse(preVersion.Groups["minor"].Value),
int.Parse(preVersion.Groups["revision"].Value),
int.Parse(preVersion.Groups["build"].Value));

_lastInvalalidated = DateTime.UtcNow;
}

public static void Invalidate()

public static Version LatestStableVersion { get; private set; }
public static Version LatestPreReleaseVersion { get; private set; }

public static bool ShouldInvalidate => _lastInvalalidated == default(DateTime) || DateTime.UtcNow > _lastInvalalidated.AddDays(1);
}

public static class RubberduckInspections
{
private const string GitHubOrg = "rubberduck-vba";
private const string RepositoryName = "Rubberduck";
private const string AssetName = "Rubberduck.CodeAnalysis.xml";

public static async Task InvalidateAsync()
{
_inspectionsCache
= new Lazy<IDictionary<string, InspectionInfo>>(CacheValueFactory,
LazyThreadSafetyMode.ExecutionAndPublication);
Inspections = /*await*/ RequestInspectionsAsync();
if (Inspections != null)
{
_lastInvalalidated = DateTime.UtcNow;
}
}

public static IDictionary<string, InspectionInfo> Inspections =>
_inspectionsCache.Value;
public static bool ShouldInvalidate => Inspections == null || DateTime.UtcNow > _lastInvalalidated.AddDays(1);

private static Lazy<IDictionary<string, InspectionInfo>> _inspectionsCache;
private static DateTime _lastInvalalidated;
public static IDictionary<string, InspectionInfo> Inspections { get; private set; }

private static IDictionary<string, InspectionInfo> CacheValueFactory() =>
RequestInspections();
private static /*async Task<*/IDictionary<string, InspectionInfo>/*>*/ RequestInspectionsAsync()
{
var client = new GitHubClient(new ProductHeaderValue("rubberduck-vba_RubberduckWEB"));
var masterTask = /*await*/ Task.Run(async () => await client.Repository.Release.GetLatest(GitHubOrg, RepositoryName));
masterTask.Wait();
if (masterTask.IsFaulted)
{
var e = masterTask.Exception;
}
var master = masterTask.Result;
var masterUrl = master.Assets.SingleOrDefault(a => a.Name == AssetName)?.BrowserDownloadUrl;

var nextTask = /*await*/ Task.Run(async () => await client.Repository.Release.GetAll(GitHubOrg, RepositoryName));
nextTask.Wait();
if (nextTask.IsFaulted)
{
var e = nextTask.Exception;
}
var next = nextTask.Result.FirstOrDefault(tag => tag.Prerelease);
var nextUrl = next?.Assets.SingleOrDefault(a => a.Name == AssetName)?.BrowserDownloadUrl;

var masterDocsTask = /*await*/ Task.Run(async () => await DownloadXmlDocAssetAsync(masterUrl, isPreRelease: false));
var nextDocsTask = /*await*/ Task.Run(async () => await DownloadXmlDocAssetAsync(nextUrl, isPreRelease: true));

masterDocsTask.Wait();
if (masterDocsTask.IsFaulted)
{
var e = masterDocsTask.Exception;
}
var masterDocs = masterDocsTask.Result;

private static IDictionary<string, InspectionInfo> RequestInspections()
nextDocsTask.Wait();
var nextDocs = nextDocsTask.Result;
if (nextDocsTask.IsFaulted)
{
var e = nextDocsTask.Exception;
}

return masterDocs.AsEnumerable()
.Concat(nextDocs.AsEnumerable().Where(kvp => !masterDocs.ContainsKey(kvp.Key)))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}

private static async Task<IDictionary<string, InspectionInfo>> DownloadXmlDocAssetAsync(string assetUrl, bool isPreRelease)
{
if (string.IsNullOrEmpty(assetUrl))
{
return new Dictionary<string, InspectionInfo>();
}

using (var client = new HttpClient())
{
var uri = new Uri(XmlDocumentationUrl);
var task = client.GetAsync(uri);
task.Wait();
var response = task.Result;
var readTask = response.Content.ReadAsStreamAsync();
readTask.Wait();
var document = XDocument.Load(readTask.Result);
var result = GetInspectionDocs(document)
.ToDictionary(info => info.InspectionName, info => info);
var uri = new Uri(assetUrl);
var response = await client.GetAsync(uri);
var xml = await response.Content.ReadAsStreamAsync();
var document = XDocument.Load(xml);
var result = GetInspectionDocs(document, isPreRelease).ToDictionary(info => info.InspectionName, info => info);
return result;
}
}

private static IEnumerable<InspectionInfo> GetInspectionDocs(XDocument doc) =>
private static IEnumerable<InspectionInfo> GetInspectionDocs(XDocument doc, bool isPreRelease) =>
from node in doc.Descendants("member")
let name = GetInspectionNameOrDefault(node)
where !string.IsNullOrEmpty(name)
select new InspectionInfo(name, node);
select new InspectionInfo(name, node, isPreRelease);

private static string GetInspectionNameOrDefault(XElement memberNode)
{
Expand Down
3 changes: 3 additions & 0 deletions RubberduckWeb/RubberduckWeb/RubberduckWeb.csproj
Expand Up @@ -95,6 +95,9 @@
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.6.3\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="Octokit, Version=0.32.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Octokit.0.32.0\lib\net45\Octokit.dll</HintPath>
</Reference>
<Reference Include="Rubberduck, Version=2.0.6.26123, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>libs\Rubberduck.dll</HintPath>
Expand Down
4 changes: 2 additions & 2 deletions RubberduckWeb/RubberduckWeb/Views/Inspections/List.cshtml
Expand Up @@ -34,10 +34,10 @@
@foreach (var info in item)
{
<td id=@info.InspectionName>
<a href="Details/@info.InspectionName"><strong>@info.InspectionName</strong></a>
<span><a href="Details/@info.InspectionName"><strong>@info.InspectionName</strong></a></span>
@if (info.IsPreRelease)
{
<p><strong><em>Pre-Release</em></strong></p>
<span>Pre-Release</span>
}
<p>@info.Summary</p>
</td>
Expand Down
1 change: 1 addition & 0 deletions RubberduckWeb/RubberduckWeb/packages.config
Expand Up @@ -21,6 +21,7 @@
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net46" />
<package id="NLog" version="4.6.3" targetFramework="net46" />
<package id="NLog.Schema" version="4.6.3" targetFramework="net46" />
<package id="Octokit" version="0.32.0" targetFramework="net46" />
<package id="popper.js" version="1.14.3" targetFramework="net46" />
<package id="Respond" version="1.4.2" targetFramework="net46" />
<package id="System.Runtime" version="4.0.20" targetFramework="net46" />
Expand Down

0 comments on commit fb1620a

Please sign in to comment.